diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..07dedbc4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,63 @@ +language: c + +matrix: + include: + - os: osx + compiler: clang + env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release + - os: linux + compiler: gcc + env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release + - os: linux + compiler: gcc + env: OPJ_CI_ARCH=i386 OPJ_CI_BUILD_CONFIGURATION=Release + addons: + apt: + packages: + - gcc-multilib + - os: linux + compiler: gcc + env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Debug + - os: linux + compiler: clang + env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Debug OPJ_CI_ASAN=1 + - os: linux + compiler: x86_64-w64-mingw32-gcc + env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release + addons: + apt: + packages: + - gcc-mingw-w64-base + - binutils-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - gcc-mingw-w64 + - os: linux + compiler: x86_64-w64-mingw32-gcc + env: OPJ_CI_ARCH=i386 OPJ_CI_BUILD_CONFIGURATION=Release + addons: + apt: + packages: + - gcc-mingw-w64-base + - binutils-mingw-w64-i686 + - gcc-mingw-w64-i686 + - gcc-mingw-w64 + - os: linux + compiler: gcc-4.8 + env: OPJ_CI_ABI_CHECK=1 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - libelf-dev + - elfutils + - texinfo + - exuberant-ctags + +install: + - ./tools/travis-ci/install.sh + +script: + - ./tools/travis-ci/run.sh + - ./tools/travis-ci/abi-check.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 229da1e1..3326b54e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,9 @@ cmake_minimum_required(VERSION 2.8.2) if(COMMAND CMAKE_POLICY) cmake_policy(SET CMP0003 NEW) + if (NOT (${CMAKE_VERSION} VERSION_LESS 3.0)) + cmake_policy(SET CMP0042 NEW) + endif() endif() if(NOT OPENJPEG_NAMESPACE) @@ -146,6 +149,11 @@ if(NOT OPENJPEG_INSTALL_PACKAGE_DIR) set(OPENJPEG_INSTALL_PACKAGE_DIR "${OPENJPEG_INSTALL_LIB_DIR}/${OPENJPEG_INSTALL_SUBDIR}") endif() +if (APPLE) + list(APPEND OPENJPEG_LIBRARY_PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${OPENJPEG_INSTALL_LIB_DIR}") + option(OPJ_USE_DSYMUTIL "Call dsymutil on binaries after build." OFF) +endif() + #----------------------------------------------------------------------------- # Big endian test: include (${CMAKE_ROOT}/Modules/TestBigEndian.cmake) @@ -182,7 +190,7 @@ if(CMAKE_COMPILER_IS_GNUCC) # For all builds, make sure openjpeg is std99 compliant: # set(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build. # Do not use ffast-math for all build, it would produce incorrect results, only set for release: - set(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}") + SET(OPENJPEG_LIBRARY_COMPILE_OPTIONS ${OPENJPEG_LIBRARY_COMPILE_OPTIONS} "$<$:-ffast-math>") endif() #----------------------------------------------------------------------------- @@ -217,6 +225,18 @@ CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H) include(TestLargeFiles) OPJ_TEST_LARGE_FILES(OPJ_HAVE_LARGEFILES) +# Allocating Aligned Memory Blocks +include(CheckIncludeFiles) +check_include_files(malloc.h OPJ_HAVE_MALLOC_H) +include(CheckSymbolExists) +# _aligned_alloc https://msdn.microsoft.com/en-us/library/8z34s9c6.aspx +check_symbol_exists(_aligned_malloc malloc.h OPJ_HAVE__ALIGNED_MALLOC) +# posix_memalign (needs _POSIX_C_SOURCE >= 200112L on Linux) +set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200112L) +check_symbol_exists(posix_memalign stdlib.h OPJ_HAVE_POSIX_MEMALIGN) +unset(CMAKE_REQUIRED_DEFINITIONS) +# memalign (obsolete) +check_symbol_exists(memalign malloc.h OPJ_HAVE_MEMALIGN) #----------------------------------------------------------------------------- # Build Library if(BUILD_JPIP_SERVER) @@ -283,8 +303,8 @@ if(BUILD_TESTING) include(CTest) # Search openjpeg data needed for the tests - # They could be found via svn on the OpenJPEG google code project - # svn checkout http://openjpeg.googlecode.com/svn/data (about 70 Mo) + # They could be found via git on the OpenJPEG GitHub code project + # git clone https://github.com/uclouvain/openjpeg-data.git find_path(OPJ_DATA_ROOT README-OPJ-Data PATHS $ENV{OPJ_DATA_ROOT} ${CMAKE_SOURCE_DIR}/../data NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH diff --git a/INSTALL b/INSTALL index 109ec4b1..16549f58 100644 --- a/INSTALL +++ b/INSTALL @@ -44,7 +44,7 @@ Main available cmake flags: cmake . -DBUILD_TESTING:BOOL=ON -DOPJ_DATA_ROOT:PATH='path/to/the/data/directory' make make Experimental - Note : JPEG2000 test files are available with 'svn checkout http://openjpeg.googlecode.com/svn/data' (about 70 Mo). + Note : JPEG2000 test files are available with 'git clone https://github.com/uclouvain/openjpeg-data.git'. If '-DOPJ_DATA_ROOT:PATH' option is omitted, test files will be automatically searched in '${CMAKE_SOURCE_DIR}/../data', corresponding to the location of the data directory when compiling from the trunk (and assuming the data directory has been checked out of course). diff --git a/NEWS b/NEWS index 2fecd4ac..1a6aaa07 100644 --- a/NEWS +++ b/NEWS @@ -36,7 +36,7 @@ API/ABI modifications: (see abi_compat_report in dev-utils/scripts) Misc: - * OpenJPEG is now officialy conformant with JPEG 2000 Part-1 + * OpenJPEG is now officially conformant with JPEG 2000 Part-1 and will soon become official reference software at the JPEG committee. * Huge amount of bug fixes. See CHANGES for details. diff --git a/README b/README deleted file mode 100644 index 0a891782..00000000 --- a/README +++ /dev/null @@ -1,47 +0,0 @@ - -OPENJPEG LIBRARY and APPLICATIONS ----------------------------------- - -Details on folders hierarchy: - -* src - * lib - * openjp2: contains the sources of the openjp2 library (Part 1 & 2) - * openjpwl: contains the additional sources if you want to build a JPWL-flavoured library. - * openjpip: complete client-server architecture for remote browsing of jpeg 2000 images. - * openjp3d: JP3D implementation - * openmj2: MJ2 implementation - * bin: contains all applications that use the openjpeg library - * common: common files to all applications - * jp2: a basic codec - * mj2: motion jpeg 2000 executables - * jpip: OpenJPIP applications (server and dec server) - * java: a Java client viewer for JPIP - * jp3d: JP3D applications - * tcltk: a test tool for JP3D - * wx - * OPJViewer: gui for displaying j2k files (based on wxWidget) -* wrapping - * java: java jni to use openjpeg in a java program -* thirdparty: thirdparty libraries used by some applications. These libraries will be built only if there are not found on the system. Note that libopenjpeg itself does not have any dependency. -* doc: doxygen documentation setup file and man pages -* tests: configuration files and utilities for the openjpeg test suite. All test images are located in 'http://openjpeg.googlecode.com/svn/data' folder. -* cmake: cmake related files - -see LICENSE for license and copyright information. -see INSTALL for installation procedures. -see NEWS for user visible changes in successive releases. -see CHANGES for per-revision changes. - ----------------- -API/ABI - -OpenJPEG strives to provide a stable API/ABI for your applications. As such it -only exposes a limited subset of its functions. It uses a mecanism of -exporting/hiding functions. If you are unsure which functions you can use in -your applications, you should compile OpenJPEG using something similar to gcc: --fvisibility=hidden compilation flag. -See also: http://gcc.gnu.org/wiki/Visibility - -On windows, MSVC directly supports export/hidding function and as such the only -API available is the one supported by OpenJPEG. diff --git a/README.md b/README.md new file mode 100644 index 00000000..c40f19e5 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ + +# OPENJPEG Library and Applications + +## What is OpenJPEG ? + +OpenJPEG is an open-source JPEG 2000 codec written in C language. It has been developed in order to promote the use of [JPEG 2000](http://www.jpeg.org/jpeg2000), a still-image compression standard from the Joint Photographic Experts Group ([JPEG](http://www.jpeg.org)). Since April 2015, it is officially recognized by ISO/IEC and ITU-T as a [JPEG 2000 Reference Software](http://www.itu.int/rec/T-REC-T.804-201504-I!Amd2). + +## Who can use the code ? +[![badge-license]][link-license] + +Anyone. As the OpenJPEG code is released under the [BSD 2-clause "Simplified" License][link-license], anyone can use or modify the code, even for commercial applications. The only restriction is to retain the copyright in the sources or in the binaries documentation. Of course, if you modified the code in a way that might be of interest for other users, you are encouraged to share it (through a [github pull request](https://github.com/uclouvain/openjpeg/pulls) or by filling an [issue](https://github.com/uclouvain/openjpeg/issues)) but this is not a requirement. + +## How to install and use OpenJPEG ? +API Documentation needs a major refactoring. Meanwhile, you can check [installation](https://github.com/uclouvain/openjpeg/wiki/Installation) instructions and [codec documentation](https://github.com/uclouvain/openjpeg/wiki/DocJ2KCodec). + +## Current Status +[![badge-build]][link-build] + +[![badge-msvc-build]][link-msvc-build] + +[![badge-coverity]][link-coverity] + +## Who are the developers ? + +The library is developed and maintained by the Image and Signal Processing Group ([ISPGroup](http://sites.uclouvain.be/ispgroup/)), in the Université catholique de Louvain ([UCL](http://www.uclouvain.be/en-index.html), with the support of the [CNES](https://cnes.fr/), the [CS](http://www.c-s.fr/) company and the [intoPIX](http://www.intopix.com) company. The JPWL module has been developed by the Digital Signal Processing Lab ([DSPLab](http://dsplab.diei.unipg.it/)) of the University of Perugia, Italy ([UNIPG](http://www.unipg.it/)). + +## Details on folders hierarchy + +* src + * lib + * openjp2: contains the sources of the openjp2 library (Part 1 & 2) + * openjpwl: contains the additional sources if you want to build a JPWL-flavoured library. + * openjpip: complete client-server architecture for remote browsing of jpeg 2000 images. + * openjp3d: JP3D implementation + * openmj2: MJ2 implementation + * bin: contains all applications that use the openjpeg library + * common: common files to all applications + * jp2: a basic codec + * mj2: motion jpeg 2000 executables + * jpip: OpenJPIP applications (server and dec server) + * java: a Java client viewer for JPIP + * jp3d: JP3D applications + * tcltk: a test tool for JP3D + * wx + * OPJViewer: gui for displaying j2k files (based on wxWidget) +* wrapping + * java: java jni to use openjpeg in a java program +* thirdparty: thirdparty libraries used by some applications. These libraries will be built only if there are not found on the system. Note that libopenjpeg itself does not have any dependency. +* doc: doxygen documentation setup file and man pages +* tests: configuration files and utilities for the openjpeg test suite. All test images are located in [openjpeg-data](https://github.com/uclouvain/openjpeg-data) repository. +* cmake: cmake related files + +See [LICENSE][link-license] for license and copyright information. + +See [INSTALL](https://github.com/uclouvain/openjpeg/blob/master/INSTALL) for installation procedures. + +See [NEWS](https://github.com/uclouvain/openjpeg/blob/master/NEWS) for user visible changes in successive releases. + +## API/ABI + +OpenJPEG strives to provide a stable API/ABI for your applications. As such it +only exposes a limited subset of its functions. It uses a mechanism of +exporting/hiding functions. If you are unsure which functions you can use in +your applications, you should compile OpenJPEG using something similar to gcc: +`-fvisibility=hidden` compilation flag. +See also: http://gcc.gnu.org/wiki/Visibility + +On windows, MSVC directly supports export/hiding function and as such the only +API available is the one supported by OpenJPEG. + +[comment-license]: https://img.shields.io/github/license/uclouvain/openjpeg.svg "https://img.shields.io/badge/license-BSD--2--Clause-blue.svg" +[badge-license]: https://img.shields.io/badge/license-BSD--2--Clause-blue.svg "BSD 2-clause "Simplified" License" +[link-license]: https://github.com/uclouvain/openjpeg/blob/master/LICENSE "BSD 2-clause "Simplified" License" +[badge-build]: https://travis-ci.org/uclouvain/openjpeg.svg?branch=master "Build Status" +[link-build]: https://travis-ci.org/uclouvain/openjpeg "Build Status" +[badge-msvc-build]: https://ci.appveyor.com/api/projects/status/github/uclouvain/openjpeg?branch=master&svg=true "Windows Build Status" +[link-msvc-build]: https://ci.appveyor.com/project/detonin/openjpeg/branch/master "Windows Build Status" +[badge-coverity]: https://scan.coverity.com/projects/6383/badge.svg "Coverity Scan Build Status" +[link-coverity]: https://scan.coverity.com/projects/uclouvain-openjpeg "Coverity Scan Build Status" diff --git a/THANKS b/THANKS index 27a35aa4..f1547961 100644 --- a/THANKS +++ b/THANKS @@ -4,30 +4,32 @@ Many people have contributed to OpenJPEG by reporting problems, suggesting vario or submitting actual code. Here is a list of these people. Help me keep it complete and exempt of errors. -Winfried Szukalski -Vincent Torri -Bob Friesenhahn -Callum Lerwick -Dzonatas Sol -Julien Malik -Jerôme Fimes -Herve Drolon -Yannick Verschueren -Sebastien Lugan -Kaori Hagihara -Peter Wimmer -Francois-Olivier Devaux -Antonin Descampe -David Janssens -Pr. Benoit Macq -Luis Ibanez +Giuseppe Baruffa Ben Boeckel +Aaron Boxer +David Burken +Matthieu Darbois +Rex Dieter +Herve Drolon +Antonin Descampe +Francois-Olivier Devaux +Parvatha Elangovan +Jerôme Fimes +Bob Friesenhahn +Kaori Hagihara +Luc Hermitte +Luis Ibanez +David Janssens +Hans Johnson +Callum Lerwick +Sebastien Lugan +Benoit Macq +Arnaud Maye +Julien Malik Vincent Nicolas Glenn Pearson -Giuseppe Baruffa -Arnaud Maye -Rex Dieter -David Burken -Parvatha Elangovan -Hans Johnson -Luc Hermitte \ No newline at end of file +Dzonatas Sol +Winfried Szukalski +Vincent Torri +Yannick Verschueren +Peter Wimmer diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..d5cc1620 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +version: 2.1.1.{build} +branches: + except: + - coverity_scan +skip_tags: true +clone_depth: 50 +environment: + matrix: + - OPJ_CI_ARCH: x86 + OPJ_CI_VSCOMNTOOLS: $(VS140COMNTOOLS) + - OPJ_CI_ARCH: x64 + OPJ_CI_VSCOMNTOOLS: $(VS140COMNTOOLS) + - OPJ_CI_ARCH: x86 + OPJ_CI_VSCOMNTOOLS: $(VS100COMNTOOLS) +install: +- cmd: c:\cygwin\bin\bash ./tools/travis-ci/install.sh +build_script: +- cmd: >- + "%OPJ_CI_VSCOMNTOOLS%..\..\VC\vcvarsall.bat" %OPJ_CI_ARCH% + + bash ./tools/travis-ci/run.sh +test: off +deploy: off diff --git a/cmake/CTestCustom.cmake.in b/cmake/CTestCustom.cmake.in index a8cb57ae..70e045da 100644 --- a/cmake/CTestCustom.cmake.in +++ b/cmake/CTestCustom.cmake.in @@ -30,7 +30,7 @@ set(CTEST_CUSTOM_WARNING_EXCEPTION # java also warns about deprecated API ".*java.*deprecation" ".*deprecation.*" - # supress warnings caused by 3rd party libs: + # suppress warnings caused by 3rd party libs: ".*thirdparty.*" "libtiff.*has no symbols" "libpng.*has no symbols" diff --git a/cmake/FindJPYLYZER.cmake b/cmake/FindJPYLYZER.cmake new file mode 100644 index 00000000..4fbbaa85 --- /dev/null +++ b/cmake/FindJPYLYZER.cmake @@ -0,0 +1,12 @@ +# +# this module looks for JPYLYZER +# http://jpylyzer.openpreservation.org +# + +find_program(JPYLYZER_EXECUTABLE + jpylyzer + ) + +mark_as_advanced( + JPYLYZER_EXECUTABLE + ) diff --git a/cmake/TestLargeFiles.cmake b/cmake/TestLargeFiles.cmake index 7960e52c..01e4ea70 100644 --- a/cmake/TestLargeFiles.cmake +++ b/cmake/TestLargeFiles.cmake @@ -17,7 +17,7 @@ # macro(OPJ_TEST_LARGE_FILES VARIABLE) - if("${VARIABLE}" MATCHES "^${VARIABLE}$") + if(NOT DEFINED ${VARIABLE}) # On most platforms it is probably overkill to first test the flags for 64-bit off_t, # and then separately fseeko. However, in the future we might have 128-bit filesystems diff --git a/doc/mainpage.dox.in b/doc/mainpage.dox.in index 72084d9b..6c105998 100644 --- a/doc/mainpage.dox.in +++ b/doc/mainpage.dox.in @@ -36,21 +36,21 @@ * * \section home Home page * -* The Home Page of the OpenJPEG library can be found at: -* -* http://code.google.com/p/openjpeg/ -* -* More information about the OpenJPEG library is available here: +* The Home Page of the OpenJPEG project can be found at: * * http://www.openjpeg.org/ * +* The source code repository is available here: +* +* http://github.com/uclouvain/openjpeg +* * The OpenJPEG mailing list is located here: * * http://groups.google.com/group/openjpeg * -* All the source code is online and can be retrieved using svn from here: +* The test files repository is available here: * -* http://openjpeg.googlecode.com/svn/ +* http://github.com/uclouvain/openjpeg-data * * \section license License * This software is released under the BSD license, anybody can use or modify the library, even for commercial applications.\n diff --git a/doc/man/man1/opj_compress.1 b/doc/man/man1/opj_compress.1 index 51e5b1a5..cb37a427 100644 --- a/doc/man/man1/opj_compress.1 +++ b/doc/man/man1/opj_compress.1 @@ -29,7 +29,7 @@ .SP .fi .. -.TH opj_compress 1 "Version 1.4.0" "opj_compress" "converts to jpeg2000 files" +.TH opj_compress 1 "Version 2.1.1" "opj_compress" "converts to jpeg2000 files" .P .SH NAME opj_compress - diff --git a/doc/man/man1/opj_decompress.1 b/doc/man/man1/opj_decompress.1 index 470fd3c1..1e7b6c54 100644 --- a/doc/man/man1/opj_decompress.1 +++ b/doc/man/man1/opj_decompress.1 @@ -29,7 +29,7 @@ .SP .fi .. -.TH opj_decompress 1 "Version 1.4.0" "opj_decompress" "converts jpeg2000 files" +.TH opj_decompress 1 "Version 2.1.1" "opj_decompress" "converts jpeg2000 files" .P .SH NAME opj_decompress - @@ -73,9 +73,19 @@ n is the maximum number of quality layers to decode. See LAYERS below) .B \-\^OutFor "ext" (extension for output files) .P +.SH JPIP OPTIONS +Options usable only if the library has been compiled with +.B BUILD_JPIP +.TP +.B -jpip +Embed index table box into the output JP2 file (compulsory for JPIP) +.TP +.B -TP R +Partition a tile into tile parts of different resolution levels (compulsory for JPT-stream) +.P .SH JPWL OPTIONS Options usable only if the library has been compiled with -.B -DUSE_JPWL +.B BUILD_JPWL .TP .B -W c\fR[=Nc] (Nc is the number of expected components in the codestream; default:3) .TP diff --git a/doc/man/man1/opj_dump.1 b/doc/man/man1/opj_dump.1 index a6033c61..160af63a 100644 --- a/doc/man/man1/opj_dump.1 +++ b/doc/man/man1/opj_dump.1 @@ -29,7 +29,7 @@ .SP .fi .. -.TH opj_dump 1 "Version 1.4.0" "opj_dump" "dumps jpeg2000 files" +.TH opj_dump 1 "Version 2.1.1" "opj_dump" "dumps jpeg2000 files" .P .SH NAME opj_dump - diff --git a/doc/openjpip.dox.in b/doc/openjpip.dox.in index e54ca75d..09ed9073 100644 --- a/doc/openjpip.dox.in +++ b/doc/openjpip.dox.in @@ -64,7 +64,7 @@ * * * \section sysarchtect System Architecture - * JPIP protocol is implimented between the JPIP server program (opj_server) and the JPIP client java program (opj_viewer).\n + * JPIP protocol is implemented between the JPIP server program (opj_server) and the JPIP client java program (opj_viewer).\n * Figure below represents the overview of our system architecture.\n * The JPIP server parses JPIP query and sends corresponding JPT/JPP-stream. * The JPIP client viewer is an image viewer with GUI to publish JPIP requests and receive JPT/JPP-stream.\n diff --git a/src/bin/common/color.c b/src/bin/common/color.c index cea35041..0f2b8dac 100644 --- a/src/bin/common/color.c +++ b/src/bin/common/color.c @@ -91,12 +91,13 @@ static void sycc444_to_rgb(opj_image_t *img) { int *d0, *d1, *d2, *r, *g, *b; const int *y, *cb, *cr; - int maxw, maxh, max, i, offset, upb; + unsigned int maxw, maxh, max, i; + int offset, upb; - i = (int)img->comps[0].prec; - offset = 1<<(i - 1); upb = (1<comps[0].prec; + offset = 1<<(upb - 1); upb = (1<comps[0].w; maxh = (int)img->comps[0].h; + maxw = (unsigned int)img->comps[0].w; maxh = (unsigned int)img->comps[0].h; max = maxw * maxh; y = img->comps[0].data; @@ -107,12 +108,11 @@ static void sycc444_to_rgb(opj_image_t *img) d1 = g = (int*)malloc(sizeof(int) * (size_t)max); d2 = b = (int*)malloc(sizeof(int) * (size_t)max); - for(i = 0; i < max; ++i) - { - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - - ++y; ++cb; ++cr; ++r; ++g; ++b; - } + for(i = 0U; i < max; ++i) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++cb; ++cr; ++r; ++g; ++b; + } free(img->comps[0].data); img->comps[0].data = d0; free(img->comps[1].data); img->comps[1].data = d1; free(img->comps[2].data); img->comps[2].data = d2; @@ -123,13 +123,14 @@ static void sycc422_to_rgb(opj_image_t *img) { int *d0, *d1, *d2, *r, *g, *b; const int *y, *cb, *cr; - int maxw, maxh, max, offset, upb; - int i, j; + unsigned int maxw, maxh, max; + int offset, upb; + unsigned int i, j; - i = (int)img->comps[0].prec; - offset = 1<<(i - 1); upb = (1<comps[0].prec; + offset = 1<<(upb - 1); upb = (1<comps[0].w; maxh = (int)img->comps[0].h; + maxw = (unsigned int)img->comps[0].w; maxh = (unsigned int)img->comps[0].h; max = maxw * maxh; y = img->comps[0].data; @@ -140,19 +141,20 @@ static void sycc422_to_rgb(opj_image_t *img) d1 = g = (int*)malloc(sizeof(int) * (size_t)max); d2 = b = (int*)malloc(sizeof(int) * (size_t)max); - for(i=0; i < maxh; ++i) - { - for(j=0; j < maxw; j += 2) - { - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - - ++y; ++r; ++g; ++b; - - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - - ++y; ++r; ++g; ++b; ++cb; ++cr; - } - } + for(i=0U; i < maxh; ++i) + { + for(j=0U; j < (maxw & ~(unsigned int)1U); j += 2U) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; ++cb; ++cr; + } + if (j < maxw) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; ++cb; ++cr; + } + } free(img->comps[0].data); img->comps[0].data = d0; free(img->comps[1].data); img->comps[1].data = d1; free(img->comps[2].data); img->comps[2].data = d2; @@ -175,13 +177,14 @@ static void sycc420_to_rgb(opj_image_t *img) { int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb; const int *y, *cb, *cr, *ny; - int maxw, maxh, max, offset, upb; - int i, j; + unsigned int maxw, maxh, max; + int offset, upb; + unsigned int i, j; - i = (int)img->comps[0].prec; - offset = 1<<(i - 1); upb = (1<comps[0].prec; + offset = 1<<(upb - 1); upb = (1<comps[0].w; maxh = (int)img->comps[0].h; + maxw = (unsigned int)img->comps[0].w; maxh = (unsigned int)img->comps[0].h; max = maxw * maxh; y = img->comps[0].data; @@ -192,31 +195,51 @@ static void sycc420_to_rgb(opj_image_t *img) d1 = g = (int*)malloc(sizeof(int) * (size_t)max); d2 = b = (int*)malloc(sizeof(int) * (size_t)max); - for(i=0; i < maxh; i += 2) - { - ny = y + maxw; - nr = r + maxw; ng = g + maxw; nb = b + maxw; + for(i=0U; i < (maxh & ~(unsigned int)1U); i += 2U) + { + ny = y + maxw; + nr = r + maxw; ng = g + maxw; nb = b + maxw; - for(j=0; j < maxw; j += 2) - { - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + for(j=0; j < (maxw & ~(unsigned int)1U); j += 2U) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; - ++y; ++r; ++g; ++b; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; ++nr; ++ng; ++nb; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; ++nr; ++ng; ++nb; ++cb; ++cr; + } + if(j < maxw) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; ++r; ++g; ++b; - sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; ++nr; ++ng; ++nb; ++cb; ++cr; + } + y += maxw; r += maxw; g += maxw; b += maxw; + } + if(i < maxh) + { + for(j=0U; j < (maxw & ~(unsigned int)1U); j += 2U) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++y; ++r; ++g; ++b; + ++y; ++r; ++g; ++b; - sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); - ++ny; ++nr; ++ng; ++nb; + ++y; ++r; ++g; ++b; ++cb; ++cr; + } + if(j < maxw) + { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + } + } - sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); - - ++ny; ++nr; ++ng; ++nb; ++cb; ++cr; - } - y += maxw; r += maxw; g += maxw; b += maxw; - } free(img->comps[0].data); img->comps[0].data = d0; free(img->comps[1].data); img->comps[1].data = d1; free(img->comps[2].data); img->comps[2].data = d2; @@ -237,11 +260,11 @@ static void sycc420_to_rgb(opj_image_t *img) void color_sycc_to_rgb(opj_image_t *img) { - if(img->numcomps < 3) - { - img->color_space = OPJ_CLRSPC_GRAY; - return; - } + if(img->numcomps < 3) + { + img->color_space = OPJ_CLRSPC_GRAY; + return; + } if((img->comps[0].dx == 1) && (img->comps[1].dx == 2) @@ -250,7 +273,7 @@ void color_sycc_to_rgb(opj_image_t *img) && (img->comps[1].dy == 2) && (img->comps[2].dy == 2))/* horizontal and vertical sub-sample */ { - sycc420_to_rgb(img); + sycc420_to_rgb(img); } else if((img->comps[0].dx == 1) @@ -260,7 +283,7 @@ void color_sycc_to_rgb(opj_image_t *img) && (img->comps[1].dy == 1) && (img->comps[2].dy == 1))/* horizontal sub-sample only */ { - sycc422_to_rgb(img); + sycc422_to_rgb(img); } else if((img->comps[0].dx == 1) @@ -270,19 +293,19 @@ void color_sycc_to_rgb(opj_image_t *img) && (img->comps[1].dy == 1) && (img->comps[2].dy == 1))/* no sub-sample */ { - sycc444_to_rgb(img); + sycc444_to_rgb(img); } else { - fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n", - __FILE__,__LINE__); - return; + fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n", __FILE__,__LINE__); + return; } img->color_space = OPJ_CLRSPC_SRGB; }/* color_sycc_to_rgb() */ #if defined(OPJ_HAVE_LIBLCMS2) || defined(OPJ_HAVE_LIBLCMS1) + #ifdef OPJ_HAVE_LIBLCMS1 /* Bob Friesenhahn proposed:*/ #define cmsSigXYZData icSigXYZData @@ -332,16 +355,16 @@ void color_apply_icc_profile(opj_image_t *image) if(out_space == cmsSigRgbData) /* enumCS 16 */ { - if( prec <= 8 ) -{ + if( prec <= 8 ) + { in_type = TYPE_RGB_8; out_type = TYPE_RGB_8; -} -else -{ + } + else + { in_type = TYPE_RGB_16; out_type = TYPE_RGB_16; -} + } out_prof = cmsCreate_sRGBProfile(); image->color_space = OPJ_CLRSPC_SRGB; } @@ -367,8 +390,8 @@ else fprintf(stderr,"%s:%d: color_apply_icc_profile\n\tICC Profile has unknown " "output colorspace(%#x)(%c%c%c%c)\n\tICC Profile ignored.\n", __FILE__,__LINE__,out_space, -(out_space>>24) & 0xff,(out_space>>16) & 0xff, -(out_space>>8) & 0xff, out_space & 0xff); + (out_space>>24) & 0xff,(out_space>>16) & 0xff, + (out_space>>8) & 0xff, out_space & 0xff); #endif return; } @@ -376,21 +399,21 @@ __FILE__,__LINE__,out_space, #ifdef DEBUG_PROFILE fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tchannels(%d) prec(%d) w(%d) h(%d)" "\n\tprofile: in(%p) out(%p)\n",__FILE__,__LINE__,image->numcomps,prec, -max_w,max_h, (void*)in_prof,(void*)out_prof); + max_w,max_h, (void*)in_prof,(void*)out_prof); fprintf(stderr,"\trender_intent (%u)\n\t" "color_space: in(%#x)(%c%c%c%c) out:(%#x)(%c%c%c%c)\n\t" " type: in(%u) out:(%u)\n", -intent, -in_space, -(in_space>>24) & 0xff,(in_space>>16) & 0xff, -(in_space>>8) & 0xff, in_space & 0xff, + intent, + in_space, + (in_space>>24) & 0xff,(in_space>>16) & 0xff, + (in_space>>8) & 0xff, in_space & 0xff, -out_space, -(out_space>>24) & 0xff,(out_space>>16) & 0xff, -(out_space>>8) & 0xff, out_space & 0xff, + out_space, + (out_space>>24) & 0xff,(out_space>>16) & 0xff, + (out_space>>8) & 0xff, out_space & 0xff, -in_type,out_type + in_type,out_type ); #else (void)prec; @@ -422,11 +445,11 @@ fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " if(image->numcomps > 2)/* RGB, RGBA */ { - if( prec <= 8 ) -{ + if( prec <= 8 ) + { unsigned char *inbuf, *outbuf, *in, *out; max = max_w * max_h; - nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char); + nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char); in = inbuf = (unsigned char*)malloc(nr_samples); out = outbuf = (unsigned char*)malloc(nr_samples); @@ -435,11 +458,11 @@ fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " b = image->comps[2].data; for(i = 0; i < max; ++i) - { + { *in++ = (unsigned char)*r++; *in++ = (unsigned char)*g++; *in++ = (unsigned char)*b++; - } + } cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); @@ -448,18 +471,18 @@ fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " b = image->comps[2].data; for(i = 0; i < max; ++i) - { + { *r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++; - } + } free(inbuf); free(outbuf); -} -else -{ + } + else + { unsigned short *inbuf, *outbuf, *in, *out; max = max_w * max_h; - nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short); + nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short); in = inbuf = (unsigned short*)malloc(nr_samples); out = outbuf = (unsigned short*)malloc(nr_samples); @@ -468,11 +491,11 @@ else b = image->comps[2].data; for(i = 0; i < max; ++i) - { + { *in++ = (unsigned short)*r++; *in++ = (unsigned short)*g++; *in++ = (unsigned short)*b++; - } + } cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); @@ -481,19 +504,19 @@ else b = image->comps[2].data; for(i = 0; i < max; ++i) - { + { *r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++; - } + } free(inbuf); free(outbuf); -} + } } else /* GRAY, GRAYA */ { unsigned char *in, *inbuf, *out, *outbuf; - max = max_w * max_h; - nr_samples = (cmsUInt32Number)max * 3 * sizeof(unsigned char); + max = max_w * max_h; + nr_samples = (cmsUInt32Number)max * 3 * sizeof(unsigned char); in = inbuf = (unsigned char*)malloc(nr_samples); out = outbuf = (unsigned char*)malloc(nr_samples); @@ -539,5 +562,227 @@ else #endif }/* color_apply_icc_profile() */ +void color_cielab_to_rgb(opj_image_t *image) +{ + int *row; + int enumcs, numcomps; + + image->color_space = OPJ_CLRSPC_SRGB; + + numcomps = (int)image->numcomps; + + if(numcomps != 3) + { + fprintf(stderr,"%s:%d:\n\tnumcomps %d not handled. Quitting.\n", + __FILE__,__LINE__,numcomps); + return; + } + + row = (int*)image->icc_profile_buf; + enumcs = row[0]; + + if(enumcs == 14) /* CIELab */ + { + int *L, *a, *b, *red, *green, *blue; + int *src0, *src1, *src2, *dst0, *dst1, *dst2; + double rl, ol, ra, oa, rb, ob, prec0, prec1, prec2; + double minL, maxL, mina, maxa, minb, maxb; + unsigned int default_type; + unsigned int i, max; + cmsHPROFILE in, out; + cmsHTRANSFORM transform; + cmsUInt16Number RGB[3]; + cmsCIELab Lab; + + in = cmsCreateLab4Profile(NULL); + out = cmsCreate_sRGBProfile(); + + transform = cmsCreateTransform(in, TYPE_Lab_DBL, out, TYPE_RGB_16, INTENT_PERCEPTUAL, 0); + +#ifdef OPJ_HAVE_LIBLCMS2 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + if(transform == NULL) + { +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + return; + } + prec0 = (double)image->comps[0].prec; + prec1 = (double)image->comps[1].prec; + prec2 = (double)image->comps[2].prec; + + default_type = (unsigned int)row[1]; + + if(default_type == 0x44454600)/* DEF : default */ + { + rl = 100; ra = 170; rb = 200; + ol = 0; + oa = pow(2, prec1 - 1); + ob = pow(2, prec2 - 2) + pow(2, prec2 - 3); + } + else + { + rl = row[2]; ra = row[4]; rb = row[6]; + ol = row[3]; oa = row[5]; ob = row[7]; + } + + L = src0 = image->comps[0].data; + a = src1 = image->comps[1].data; + b = src2 = image->comps[2].data; + + max = image->comps[0].w * image->comps[0].h; + + red = dst0 = (int*)malloc(max * sizeof(int)); + green = dst1 = (int*)malloc(max * sizeof(int)); + blue = dst2 = (int*)malloc(max * sizeof(int)); + + minL = -(rl * ol)/(pow(2, prec0)-1); + maxL = minL + rl; + + mina = -(ra * oa)/(pow(2, prec1)-1); + maxa = mina + ra; + + minb = -(rb * ob)/(pow(2, prec2)-1); + maxb = minb + rb; + + for(i = 0; i < max; ++i) + { + Lab.L = minL + (double)(*L) * (maxL - minL)/(pow(2, prec0)-1); ++L; + Lab.a = mina + (double)(*a) * (maxa - mina)/(pow(2, prec1)-1); ++a; + Lab.b = minb + (double)(*b) * (maxb - minb)/(pow(2, prec2)-1); ++b; + + cmsDoTransform(transform, &Lab, RGB, 1); + + *red++ = RGB[0]; + *green++ = RGB[1]; + *blue++ = RGB[2]; + } + cmsDeleteTransform(transform); +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + free(src0); image->comps[0].data = dst0; + free(src1); image->comps[1].data = dst1; + free(src2); image->comps[2].data = dst2; + + image->color_space = OPJ_CLRSPC_SRGB; + image->comps[0].prec = 16; + image->comps[1].prec = 16; + image->comps[2].prec = 16; + + return; + } + + fprintf(stderr,"%s:%d:\n\tenumCS %d not handled. Ignoring.\n", __FILE__,__LINE__, enumcs); +}/* color_apply_conversion() */ + #endif /* OPJ_HAVE_LIBLCMS2 || OPJ_HAVE_LIBLCMS1 */ +void color_cmyk_to_rgb(opj_image_t *image) +{ + float C, M, Y, K; + float sC, sM, sY, sK; + unsigned int w, h, max, i; + + w = image->comps[0].w; + h = image->comps[0].h; + + if(image->numcomps < 4) return; + + max = w * h; + + sC = 1.0F / (float)((1 << image->comps[0].prec) - 1); + sM = 1.0F / (float)((1 << image->comps[1].prec) - 1); + sY = 1.0F / (float)((1 << image->comps[2].prec) - 1); + sK = 1.0F / (float)((1 << image->comps[3].prec) - 1); + + for(i = 0; i < max; ++i) + { + /* CMYK values from 0 to 1 */ + C = (float)(image->comps[0].data[i]) * sC; + M = (float)(image->comps[1].data[i]) * sM; + Y = (float)(image->comps[2].data[i]) * sY; + K = (float)(image->comps[3].data[i]) * sK; + + /* Invert all CMYK values */ + C = 1.0F - C; + M = 1.0F - M; + Y = 1.0F - Y; + K = 1.0F - K; + + /* CMYK -> RGB : RGB results from 0 to 255 */ + image->comps[0].data[i] = (int)(255.0F * C * K); /* R */ + image->comps[1].data[i] = (int)(255.0F * M * K); /* G */ + image->comps[2].data[i] = (int)(255.0F * Y * K); /* B */ + } + + free(image->comps[3].data); image->comps[3].data = NULL; + image->comps[0].prec = 8; + image->comps[1].prec = 8; + image->comps[2].prec = 8; + image->numcomps -= 1; + image->color_space = OPJ_CLRSPC_SRGB; + + for (i = 3; i < image->numcomps; ++i) { + memcpy(&(image->comps[i]), &(image->comps[i+1]), sizeof(image->comps[i])); + } + +}/* color_cmyk_to_rgb() */ + +/* + * This code has been adopted from sjpx_openjpeg.c of ghostscript + */ +void color_esycc_to_rgb(opj_image_t *image) +{ + int y, cb, cr, sign1, sign2, val; + unsigned int w, h, max, i; + int flip_value = (1 << (image->comps[0].prec-1)); + int max_value = (1 << image->comps[0].prec) - 1; + + if(image->numcomps < 3) return; + + w = image->comps[0].w; + h = image->comps[0].h; + + sign1 = (int)image->comps[1].sgnd; + sign2 = (int)image->comps[2].sgnd; + + max = w * h; + + for(i = 0; i < max; ++i) + { + + y = image->comps[0].data[i]; cb = image->comps[1].data[i]; cr = image->comps[2].data[i]; + + if( !sign1) cb -= flip_value; + if( !sign2) cr -= flip_value; + + val = (int) + ((float)y - (float)0.0000368 * (float)cb + + (float)1.40199 * (float)cr + (float)0.5); + + if(val > max_value) val = max_value; else if(val < 0) val = 0; + image->comps[0].data[i] = val; + + val = (int) + ((float)1.0003 * (float)y - (float)0.344125 * (float)cb + - (float)0.7141128 * (float)cr + (float)0.5); + + if(val > max_value) val = max_value; else if(val < 0) val = 0; + image->comps[1].data[i] = val; + + val = (int) + ((float)0.999823 * (float)y + (float)1.77204 * (float)cb + - (float)0.000008 *(float)cr + (float)0.5); + + if(val > max_value) val = max_value; else if(val < 0) val = 0; + image->comps[2].data[i] = val; + } + image->color_space = OPJ_CLRSPC_SRGB; + +}/* color_esycc_to_rgb() */ diff --git a/src/bin/common/color.h b/src/bin/common/color.h index da8c6e7b..0cd78e89 100644 --- a/src/bin/common/color.h +++ b/src/bin/common/color.h @@ -40,5 +40,8 @@ extern void color_sycc_to_rgb(opj_image_t *img); extern void color_apply_icc_profile(opj_image_t *image); +extern void color_cielab_to_rgb(opj_image_t *image); +extern void color_cmyk_to_rgb(opj_image_t *image); +extern void color_esycc_to_rgb(opj_image_t *image); #endif /* _OPJ_COLOR_H_ */ diff --git a/src/bin/common/opj_getopt.c b/src/bin/common/opj_getopt.c index 100cded7..65f271f8 100644 --- a/src/bin/common/opj_getopt.c +++ b/src/bin/common/opj_getopt.c @@ -54,7 +54,7 @@ int opj_opterr = 1, /* if error message should be printed */ static char EMSG[]={""}; /* As this class remembers its values from one Java call to the other, reset the values before each use */ -void reset_options_reading(void) { +void opj_reset_options_reading(void) { opj_opterr = 1; opj_optind = 1; } @@ -66,7 +66,7 @@ void reset_options_reading(void) { int opj_getopt(int nargc, char *const *nargv, const char *ostr) { # define __progname nargv[0] static char *place = EMSG; /* option letter processing */ - char *oli = NULL; /* option letter list index */ + const char *oli = NULL; /* option letter list index */ if (opj_optreset || !*place) { /* update scanning pointer */ opj_optreset = 0; @@ -125,7 +125,7 @@ int opj_getopt(int nargc, char *const *nargv, const char *ostr) { int opj_getopt_long(int argc, char * const argv[], const char *optstring, const opj_option_t *longopts, int totlen) { static int lastidx,lastofs; - char *tmp; + const char *tmp; int i,len; char param = 1; diff --git a/src/bin/common/opj_getopt.h b/src/bin/common/opj_getopt.h index e1f41a56..f97e8b35 100644 --- a/src/bin/common/opj_getopt.h +++ b/src/bin/common/opj_getopt.h @@ -24,6 +24,6 @@ extern char *opj_optarg; extern int opj_getopt(int nargc, char *const *nargv, const char *ostr); extern int opj_getopt_long(int argc, char * const argv[], const char *optstring, const opj_option_t *longopts, int totlen); -extern void reset_options_reading(void); +extern void opj_reset_options_reading(void); #endif /* _GETOPT_H_ */ diff --git a/src/bin/common/opj_string.h b/src/bin/common/opj_string.h new file mode 100644 index 00000000..8829926a --- /dev/null +++ b/src/bin/common/opj_string.h @@ -0,0 +1,72 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 COPYRIGHT OWNER 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. + */ + +#ifndef OPJ_STRING_H +#define OPJ_STRING_H + +#include +#include + +/* strnlen is not standard, strlen_s is C11... */ +/* keep in mind there still is a buffer read overflow possible */ +static size_t opj_strnlen_s(const char *src, size_t max_len) +{ + size_t len; + + if (src == NULL) { + return 0U; + } + for (len = 0U; (*src != '\0') && (len < max_len); src++, len++); + return len; +} + +/* should be equivalent to C11 function except for the handler */ +/* keep in mind there still is a buffer read overflow possible */ +static int opj_strcpy_s(char* dst, size_t dst_size, const char* src) +{ + size_t src_len = 0U; + if ((dst == NULL) || (dst_size == 0U)) { + return EINVAL; + } + if (src == NULL) { + dst[0] = '\0'; + return EINVAL; + } + src_len = opj_strnlen_s(src, dst_size); + if (src_len >= dst_size) { + return ERANGE; + } + memcpy(dst, src, src_len); + dst[src_len] = '\0'; + return 0; +} + +#endif /* OPJ_STRING_H */ diff --git a/src/bin/jp2/CMakeLists.txt b/src/bin/jp2/CMakeLists.txt index 1c2ef39c..d583c2e6 100644 --- a/src/bin/jp2/CMakeLists.txt +++ b/src/bin/jp2/CMakeLists.txt @@ -3,10 +3,23 @@ # First thing define the common source: set(common_SRCS convert.c + convert.h + convertbmp.c index.c + index.h ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.h ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.h + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_string.h ) + +if(OPJ_HAVE_LIBTIFF) + list(APPEND common_SRCS converttif.c) +endif() +if(OPJ_HAVE_LIBPNG) + list(APPEND common_SRCS convertpng.c) +endif() # Headers file are located here: include_directories( @@ -50,6 +63,12 @@ foreach(exe opj_decompress opj_compress opj_dump) EXPORT OpenJPEGTargets DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications ) + if(OPJ_USE_DSYMUTIL) + add_custom_command(TARGET ${exe} POST_BUILD + COMMAND "dsymutil" "$" + COMMENT "dsymutil $" + DEPENDS ${exe}) + endif() endforeach() if(BUILD_DOC) diff --git a/src/bin/jp2/convert.c b/src/bin/jp2/convert.c index 1b2d3618..13713204 100644 --- a/src/bin/jp2/convert.c +++ b/src/bin/jp2/convert.c @@ -42,15 +42,6 @@ #include #include -#ifdef OPJ_HAVE_LIBTIFF -#include -#endif /* OPJ_HAVE_LIBTIFF */ - -#ifdef OPJ_HAVE_LIBPNG -#include -#include -#endif /* OPJ_HAVE_LIBPNG */ - #include "openjpeg.h" #include "convert.h" @@ -67,6 +58,475 @@ static int int_floorlog2(int a) { return l; } +/* Component precision scaling */ +void clip_component(opj_image_comp_t* component, OPJ_UINT32 precision) +{ + OPJ_SIZE_T i; + OPJ_SIZE_T len; + OPJ_UINT32 umax = (OPJ_UINT32)((OPJ_INT32)-1); + + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (precision < 32) { + umax = (1U << precision) - 1U; + } + + if (component->sgnd) { + OPJ_INT32* l_data = component->data; + OPJ_INT32 max = (OPJ_INT32)(umax / 2U); + OPJ_INT32 min = -max - 1; + for (i = 0; i < len; ++i) { + if (l_data[i] > max) { + l_data[i] = max; + } else if (l_data[i] < min) { + l_data[i] = min; + } + } + } else { + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + if (l_data[i] > umax) { + l_data[i] = umax; + } + } + } + component->prec = precision; +} + +/* Component precision scaling */ +static void scale_component_up(opj_image_comp_t* component, OPJ_UINT32 precision) +{ + OPJ_SIZE_T i, len; + + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (component->sgnd) { + OPJ_INT64 newMax = (OPJ_INT64)(1U << (precision - 1)); + OPJ_INT64 oldMax = (OPJ_INT64)(1U << (component->prec - 1)); + OPJ_INT32* l_data = component->data; + for (i = 0; i < len; ++i) { + l_data[i] = (OPJ_INT32)(((OPJ_INT64)l_data[i] * newMax) / oldMax); + } + } else { + OPJ_UINT64 newMax = (OPJ_UINT64)((1U << precision) - 1U); + OPJ_UINT64 oldMax = (OPJ_UINT64)((1U << component->prec) - 1U); + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + l_data[i] = (OPJ_UINT32)(((OPJ_UINT64)l_data[i] * newMax) / oldMax); + } + } + component->prec = precision; + component->bpp = precision; +} +void scale_component(opj_image_comp_t* component, OPJ_UINT32 precision) +{ + int shift; + OPJ_SIZE_T i, len; + + if (component->prec == precision) { + return; + } + if (component->prec < precision) { + scale_component_up(component, precision); + return; + } + shift = (int)(component->prec - precision); + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (component->sgnd) { + OPJ_INT32* l_data = component->data; + for (i = 0; i < len; ++i) { + l_data[i] >>= shift; + } + } else { + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + l_data[i] >>= shift; + } + } + component->bpp = precision; + component->prec = precision; +} + + +/* planar / interleaved conversions */ +/* used by PNG/TIFF */ +static void convert_32s_C1P1(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length) +{ + memcpy(pDst[0], pSrc, length * sizeof(OPJ_INT32)); +} +static void convert_32s_C2P2(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[2*i+0]; + pDst1[i] = pSrc[2*i+1]; + } +} +static void convert_32s_C3P3(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + OPJ_INT32* pDst2 = pDst[2]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[3*i+0]; + pDst1[i] = pSrc[3*i+1]; + pDst2[i] = pSrc[3*i+2]; + } +} +static void convert_32s_C4P4(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + OPJ_INT32* pDst2 = pDst[2]; + OPJ_INT32* pDst3 = pDst[3]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[4*i+0]; + pDst1[i] = pSrc[4*i+1]; + pDst2[i] = pSrc[4*i+2]; + pDst3[i] = pSrc[4*i+3]; + } +} +const convert_32s_CXPX convert_32s_CXPX_LUT[5] = { + NULL, + convert_32s_C1P1, + convert_32s_C2P2, + convert_32s_C3P3, + convert_32s_C4P4 +}; + +static void convert_32s_P1C1(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + + for (i = 0; i < length; i++) { + pDst[i] = pSrc0[i] + adjust; + } +} +static void convert_32s_P2C2(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + + for (i = 0; i < length; i++) { + pDst[2*i+0] = pSrc0[i] + adjust; + pDst[2*i+1] = pSrc1[i] + adjust; + } +} +static void convert_32s_P3C3(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + const OPJ_INT32* pSrc2 = pSrc[2]; + + for (i = 0; i < length; i++) { + pDst[3*i+0] = pSrc0[i] + adjust; + pDst[3*i+1] = pSrc1[i] + adjust; + pDst[3*i+2] = pSrc2[i] + adjust; + } +} +static void convert_32s_P4C4(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + const OPJ_INT32* pSrc2 = pSrc[2]; + const OPJ_INT32* pSrc3 = pSrc[3]; + + for (i = 0; i < length; i++) { + pDst[4*i+0] = pSrc0[i] + adjust; + pDst[4*i+1] = pSrc1[i] + adjust; + pDst[4*i+2] = pSrc2[i] + adjust; + pDst[4*i+3] = pSrc3[i] + adjust; + } +} +const convert_32s_PXCX convert_32s_PXCX_LUT[5] = { + NULL, + convert_32s_P1C1, + convert_32s_P2C2, + convert_32s_P3C3, + convert_32s_P4C4 +}; + +/* bit depth conversions */ +/* used by PNG/TIFF up to 8bpp */ +static void convert_1u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i+=8U) { + OPJ_UINT32 val = *pSrc++; + pDst[i+0] = (OPJ_INT32)( val >> 7); + pDst[i+1] = (OPJ_INT32)((val >> 6) & 0x1U); + pDst[i+2] = (OPJ_INT32)((val >> 5) & 0x1U); + pDst[i+3] = (OPJ_INT32)((val >> 4) & 0x1U); + pDst[i+4] = (OPJ_INT32)((val >> 3) & 0x1U); + pDst[i+5] = (OPJ_INT32)((val >> 2) & 0x1U); + pDst[i+6] = (OPJ_INT32)((val >> 1) & 0x1U); + pDst[i+7] = (OPJ_INT32)(val & 0x1U); + } + if (length & 7U) { + OPJ_UINT32 val = *pSrc++; + length = length & 7U; + pDst[i+0] = (OPJ_INT32)(val >> 7); + + if (length > 1U) { + pDst[i+1] = (OPJ_INT32)((val >> 6) & 0x1U); + if (length > 2U) { + pDst[i+2] = (OPJ_INT32)((val >> 5) & 0x1U); + if (length > 3U) { + pDst[i+3] = (OPJ_INT32)((val >> 4) & 0x1U); + if (length > 4U) { + pDst[i+4] = (OPJ_INT32)((val >> 3) & 0x1U); + if (length > 5U) { + pDst[i+5] = (OPJ_INT32)((val >> 2) & 0x1U); + if (length > 6U) { + pDst[i+6] = (OPJ_INT32)((val >> 1) & 0x1U); + } + } + } + } + } + } + } +} +static void convert_2u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 val = *pSrc++; + pDst[i+0] = (OPJ_INT32)( val >> 6); + pDst[i+1] = (OPJ_INT32)((val >> 4) & 0x3U); + pDst[i+2] = (OPJ_INT32)((val >> 2) & 0x3U); + pDst[i+3] = (OPJ_INT32)(val & 0x3U); + } + if (length & 3U) { + OPJ_UINT32 val = *pSrc++; + length = length & 3U; + pDst[i+0] = (OPJ_INT32)(val >> 6); + + if (length > 1U) { + pDst[i+1] = (OPJ_INT32)((val >> 4) & 0x3U); + if (length > 2U) { + pDst[i+2] = (OPJ_INT32)((val >> 2) & 0x3U); + + } + } + } +} +static void convert_4u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i+=2U) { + OPJ_UINT32 val = *pSrc++; + pDst[i+0] = (OPJ_INT32)(val >> 4); + pDst[i+1] = (OPJ_INT32)(val & 0xFU); + } + if (length & 1U) { + OPJ_UINT8 val = *pSrc++; + pDst[i+0] = (OPJ_INT32)(val >> 4); + } +} +static void convert_6u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + pDst[i+0] = (OPJ_INT32)(val0 >> 2); + pDst[i+1] = (OPJ_INT32)(((val0 & 0x3U) << 4) | (val1 >> 4)); + pDst[i+2] = (OPJ_INT32)(((val1 & 0xFU) << 2) | (val2 >> 6)); + pDst[i+3] = (OPJ_INT32)(val2 & 0x3FU); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + length = length & 3U; + pDst[i+0] = (OPJ_INT32)(val0 >> 2); + + if (length > 1U) { + OPJ_UINT32 val1 = *pSrc++; + pDst[i+1] = (OPJ_INT32)(((val0 & 0x3U) << 4) | (val1 >> 4)); + if (length > 2U) { + OPJ_UINT32 val2 = *pSrc++; + pDst[i+2] = (OPJ_INT32)(((val1 & 0xFU) << 2) | (val2 >> 6)); + } + } + } +} +static void convert_8u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + pDst[i] = pSrc[i]; + } +} +const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9] = { + NULL, + convert_1u32s_C1R, + convert_2u32s_C1R, + NULL, + convert_4u32s_C1R, + NULL, + convert_6u32s_C1R, + NULL, + convert_8u32s_C1R +}; + + +static void convert_32s1u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i+=8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i+2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i+3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i+4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i+5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i+6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i+7]; + + *pDst++ = (OPJ_BYTE)((src0 << 7) | (src1 << 6) | (src2 << 5) | (src3 << 4) | (src4 << 3) | (src5 << 2) | (src6 << 1) | src7); + } + + if (length & 7U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + OPJ_UINT32 src3 = 0U; + OPJ_UINT32 src4 = 0U; + OPJ_UINT32 src5 = 0U; + OPJ_UINT32 src6 = 0U; + length = length & 7U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i+1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i+2]; + if (length > 3U) { + src3 = (OPJ_UINT32)pSrc[i+3]; + if (length > 4U) { + src4 = (OPJ_UINT32)pSrc[i+4]; + if (length > 5U) { + src5 = (OPJ_UINT32)pSrc[i+5]; + if (length > 6U) { + src6 = (OPJ_UINT32)pSrc[i+6]; + } + } + } + } + } + } + *pDst++ = (OPJ_BYTE)((src0 << 7) | (src1 << 6) | (src2 << 5) | (src3 << 4) | (src4 << 3) | (src5 << 2) | (src6 << 1)); + } +} + +static void convert_32s2u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i+2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i+3]; + + *pDst++ = (OPJ_BYTE)((src0 << 6) | (src1 << 4) | (src2 << 2) | src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i+1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i+2]; + } + } + *pDst++ = (OPJ_BYTE)((src0 << 6) | (src1 << 4) | (src2 << 2)); + } +} + +static void convert_32s4u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i+=2U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + + *pDst++ = (OPJ_BYTE)((src0 << 4) | src1); + } + + if (length & 1U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + *pDst++ = (OPJ_BYTE)((src0 << 4)); + } +} + +static void convert_32s6u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i+2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i+3]; + + *pDst++ = (OPJ_BYTE)((src0 << 2) | (src1 >> 4)); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 2)); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6) | src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i+1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i+2]; + } + } + *pDst++ = (OPJ_BYTE)((src0 << 2) | (src1 >> 4)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 2)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6)); + } + } + } +} +static void convert_32s8u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; ++i) { + pDst[i] = (OPJ_BYTE)pSrc[i]; + } +} +const convert_32sXXx_C1R convert_32sXXu_C1R_LUT[9] = { + NULL, + convert_32s1u_C1R, + convert_32s2u_C1R, + NULL, + convert_32s4u_C1R, + NULL, + convert_32s6u_C1R, + NULL, + convert_32s8u_C1R +}; + /* -->> -->> -->> -->> TGA IMAGE FORMAT @@ -98,14 +558,12 @@ struct tga_header }; #endif /* INFORMATION_ONLY */ -static unsigned short get_ushort(unsigned short val) { - +static unsigned short get_ushort(const unsigned char *data) { + unsigned short val = *(const unsigned short *)data; #ifdef OPJ_BIG_ENDIAN - return( ((val & 0xff) << 8) + (val >> 8) ); -#else - return( val ); + val = ((val & 0xffU) << 8) | (val >> 8); #endif - + return val; } #define TGA_HEADER_SIZE 18 @@ -114,7 +572,7 @@ static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, unsigned int *width, unsigned int *height, int *flip_image) { int palette_size; - unsigned char *tga ; + unsigned char tga[TGA_HEADER_SIZE]; unsigned char id_len, /*cmap_type,*/ image_type; unsigned char pixel_depth, image_desc; unsigned short /*cmap_index,*/ cmap_len, cmap_entry_size; @@ -122,31 +580,28 @@ static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, if (!bits_per_pixel || !width || !height || !flip_image) return 0; - tga = (unsigned char*)malloc(18); if ( fread(tga, TGA_HEADER_SIZE, 1, fp) != 1 ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); return 0 ; } - id_len = (unsigned char)tga[0]; - /*cmap_type = (unsigned char)tga[1];*/ - image_type = (unsigned char)tga[2]; - /*cmap_index = get_ushort(*(unsigned short*)(&tga[3]));*/ - cmap_len = get_ushort(*(unsigned short*)(&tga[5])); - cmap_entry_size = (unsigned char)tga[7]; + id_len = tga[0]; + /*cmap_type = tga[1];*/ + image_type = tga[2]; + /*cmap_index = get_ushort(&tga[3]);*/ + cmap_len = get_ushort(&tga[5]); + cmap_entry_size = tga[7]; #if 0 - x_origin = get_ushort(*(unsigned short*)(&tga[8])); - y_origin = get_ushort(*(unsigned short*)(&tga[10])); + x_origin = get_ushort(&tga[8]); + y_origin = get_ushort(&tga[10]); #endif - image_w = get_ushort(*(unsigned short*)(&tga[12])); - image_h = get_ushort(*(unsigned short*)(&tga[14])); - pixel_depth = (unsigned char)tga[16]; - image_desc = (unsigned char)tga[17]; - - free(tga); + image_w = get_ushort(&tga[12]); + image_h = get_ushort(&tga[14]); + pixel_depth = tga[16]; + image_desc = tga[17]; *bits_per_pixel = (unsigned int)pixel_depth; *width = (unsigned int)image_w; @@ -189,10 +644,9 @@ static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, #ifdef OPJ_BIG_ENDIAN -static INLINE int16_t swap16(int16_t x) +static INLINE OPJ_UINT16 swap16(OPJ_UINT16 x) { - return((((u_int16_t)x & 0x00ffU) << 8) | - (((u_int16_t)x & 0xff00U) >> 8)); + return (OPJ_UINT16)(((x & 0x00ffU) << 8) | ((x & 0xff00U) >> 8)); } #endif @@ -200,7 +654,7 @@ static INLINE int16_t swap16(int16_t x) static int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, OPJ_BOOL flip_image) { - unsigned short image_w, image_h, us0; + OPJ_UINT16 image_w, image_h, us0; unsigned char uc0, image_type; unsigned char pixel_depth, image_desc; @@ -279,12 +733,16 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { return 0; } - if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, &flip_image)) + if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, &flip_image)) { + fclose(f); return NULL; + } /* We currently only support 24 & 32 bit tga's ... */ - if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) + if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) { + fclose(f); return NULL; + } /* initialize image components */ memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); @@ -317,8 +775,11 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { /* create the image */ image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); - if (!image) + if (!image) { + fclose(f); return NULL; + } + /* set image offset and reference grid */ image->x0 = (OPJ_UINT32)parameters->image_offset_x0; @@ -346,18 +807,21 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } if ( !fread(&g, 1, 1, f) ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } if ( !fread(&r, 1, 1, f) ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } @@ -376,24 +840,28 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } if ( !fread(&g, 1, 1, f) ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } if ( !fread(&r, 1, 1, f) ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } if ( !fread(&a, 1, 1, f) ) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(f); return NULL; } @@ -408,6 +876,7 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) { fprintf(stderr, "Currently unsupported bit depth : %s\n", filename); } } + fclose(f); return image; } @@ -434,6 +903,7 @@ int imagetotga(opj_image_t * image, const char *outfile) { if ((image->comps[0].dx != image->comps[i+1].dx) ||(image->comps[0].dy != image->comps[i+1].dy) ||(image->comps[0].prec != image->comps[i+1].prec)) { + fclose(fdest); fprintf(stderr, "Unable to create a tga file with such J2K image charateristics."); return 1; } @@ -529,700 +999,6 @@ fin: return fails; } -/* -->> -->> -->> -->> - - BMP IMAGE FORMAT - - <<-- <<-- <<-- <<-- */ - -/* WORD defines a two byte word */ -typedef unsigned short int WORD; - -/* DWORD defines a four byte word */ -typedef unsigned int DWORD; - -typedef struct { - WORD bfType; /* 'BM' for Bitmap (19776) */ - DWORD bfSize; /* Size of the file */ - WORD bfReserved1; /* Reserved : 0 */ - WORD bfReserved2; /* Reserved : 0 */ - DWORD bfOffBits; /* Offset */ -} BITMAPFILEHEADER_t; - -typedef struct { - DWORD biSize; /* Size of the structure in bytes */ - DWORD biWidth; /* Width of the image in pixels */ - DWORD biHeight; /* Heigth of the image in pixels */ - WORD biPlanes; /* 1 */ - WORD biBitCount; /* Number of color bits by pixels */ - DWORD biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ - DWORD biSizeImage; /* Size of the image in bytes */ - DWORD biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ - DWORD biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ - DWORD biClrUsed; /* Number of color used in the image (0: ALL) */ - DWORD biClrImportant; /* Number of important color (0: ALL) */ -} BITMAPINFOHEADER_t; - -opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) -{ - int subsampling_dx = parameters->subsampling_dx; - int subsampling_dy = parameters->subsampling_dy; - - int i, numcomps, w, h; - OPJ_COLOR_SPACE color_space; - opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ - opj_image_t * image = NULL; - - FILE *IN; - BITMAPFILEHEADER_t File_h; - BITMAPINFOHEADER_t Info_h; - unsigned char *RGB; - unsigned char *table_R, *table_G, *table_B; - unsigned int j, PAD = 0; - - unsigned int x, y; - int index; - int gray_scale = 1; - int has_color; - DWORD W, H; - - IN = fopen(filename, "rb"); - if (!IN) - { - fprintf(stderr, "Failed to open %s for reading !!\n", filename); - return NULL; - } - - File_h.bfType = (WORD)getc(IN); - File_h.bfType = (WORD)((getc(IN) << 8) + File_h.bfType); - - if (File_h.bfType != 19778) - { - fprintf(stderr,"Error, not a BMP file!\n"); - fclose(IN); - return NULL; - } - /* FILE HEADER */ - /* ------------- */ - File_h.bfSize = (DWORD)getc(IN); - File_h.bfSize = (DWORD)(getc(IN) << 8) + File_h.bfSize; - File_h.bfSize = (DWORD)(getc(IN) << 16) + File_h.bfSize; - File_h.bfSize = (DWORD)(getc(IN) << 24) + File_h.bfSize; - - File_h.bfReserved1 = (WORD)getc(IN); - File_h.bfReserved1 = (WORD)((getc(IN) << 8) + File_h.bfReserved1); - - File_h.bfReserved2 = (WORD)getc(IN); - File_h.bfReserved2 = (WORD)((getc(IN) << 8) + File_h.bfReserved2); - - File_h.bfOffBits = (DWORD)getc(IN); - File_h.bfOffBits = (DWORD)(getc(IN) << 8) + File_h.bfOffBits; - File_h.bfOffBits = (DWORD)(getc(IN) << 16) + File_h.bfOffBits; - File_h.bfOffBits = (DWORD)(getc(IN) << 24) + File_h.bfOffBits; - - /* INFO HEADER */ - /* ------------- */ - - Info_h.biSize = (DWORD)getc(IN); - Info_h.biSize = (DWORD)(getc(IN) << 8) + Info_h.biSize; - Info_h.biSize = (DWORD)(getc(IN) << 16) + Info_h.biSize; - Info_h.biSize = (DWORD)(getc(IN) << 24) + Info_h.biSize; - - if(Info_h.biSize != 40) - { - fprintf(stderr,"Error, unknown BMP header size %d\n", Info_h.biSize); - fclose(IN); - return NULL; - } - Info_h.biWidth = (DWORD)getc(IN); - Info_h.biWidth = (DWORD)(getc(IN) << 8) + Info_h.biWidth; - Info_h.biWidth = (DWORD)(getc(IN) << 16) + Info_h.biWidth; - Info_h.biWidth = (DWORD)(getc(IN) << 24) + Info_h.biWidth; - w = (int)Info_h.biWidth; - - Info_h.biHeight = (DWORD)getc(IN); - Info_h.biHeight = (DWORD)(getc(IN) << 8) + Info_h.biHeight; - Info_h.biHeight = (DWORD)(getc(IN) << 16) + Info_h.biHeight; - Info_h.biHeight = (DWORD)(getc(IN) << 24) + Info_h.biHeight; - h = (int)Info_h.biHeight; - - Info_h.biPlanes = (WORD)getc(IN); - Info_h.biPlanes = (WORD)((getc(IN) << 8) + Info_h.biPlanes); - - Info_h.biBitCount = (WORD)getc(IN); - Info_h.biBitCount = (WORD)((getc(IN) << 8) + Info_h.biBitCount); - - Info_h.biCompression = (DWORD)getc(IN); - Info_h.biCompression = (DWORD)(getc(IN) << 8) + Info_h.biCompression; - Info_h.biCompression = (DWORD)(getc(IN) << 16) + Info_h.biCompression; - Info_h.biCompression = (DWORD)(getc(IN) << 24) + Info_h.biCompression; - - Info_h.biSizeImage = (DWORD)getc(IN); - Info_h.biSizeImage = (DWORD)(getc(IN) << 8) + Info_h.biSizeImage; - Info_h.biSizeImage = (DWORD)(getc(IN) << 16) + Info_h.biSizeImage; - Info_h.biSizeImage = (DWORD)(getc(IN) << 24) + Info_h.biSizeImage; - - Info_h.biXpelsPerMeter = (DWORD)getc(IN); - Info_h.biXpelsPerMeter = (DWORD)(getc(IN) << 8) + Info_h.biXpelsPerMeter; - Info_h.biXpelsPerMeter = (DWORD)(getc(IN) << 16) + Info_h.biXpelsPerMeter; - Info_h.biXpelsPerMeter = (DWORD)(getc(IN) << 24) + Info_h.biXpelsPerMeter; - - Info_h.biYpelsPerMeter = (DWORD)getc(IN); - Info_h.biYpelsPerMeter = (DWORD)(getc(IN) << 8) + Info_h.biYpelsPerMeter; - Info_h.biYpelsPerMeter = (DWORD)(getc(IN) << 16) + Info_h.biYpelsPerMeter; - Info_h.biYpelsPerMeter = (DWORD)(getc(IN) << 24) + Info_h.biYpelsPerMeter; - - Info_h.biClrUsed = (DWORD)getc(IN); - Info_h.biClrUsed = (DWORD)(getc(IN) << 8) + Info_h.biClrUsed; - Info_h.biClrUsed = (DWORD)(getc(IN) << 16) + Info_h.biClrUsed; - Info_h.biClrUsed = (DWORD)(getc(IN) << 24) + Info_h.biClrUsed; - - Info_h.biClrImportant = (DWORD)getc(IN); - Info_h.biClrImportant = (DWORD)(getc(IN) << 8) + Info_h.biClrImportant; - Info_h.biClrImportant = (DWORD)(getc(IN) << 16) + Info_h.biClrImportant; - Info_h.biClrImportant = (DWORD)(getc(IN) << 24) + Info_h.biClrImportant; - - /* Read the data and store them in the OUT file */ - - if (Info_h.biBitCount == 24) - { - numcomps = 3; - color_space = OPJ_CLRSPC_SRGB; - /* initialize image components */ - memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); - for(i = 0; i < numcomps; i++) - { - cmptparm[i].prec = 8; - cmptparm[i].bpp = 8; - cmptparm[i].sgnd = 0; - cmptparm[i].dx = (OPJ_UINT32)subsampling_dx; - cmptparm[i].dy = (OPJ_UINT32)subsampling_dy; - cmptparm[i].w = (OPJ_UINT32)w; - cmptparm[i].h = (OPJ_UINT32)h; - } - /* create the image */ - image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); - if(!image) - { - fclose(IN); - return NULL; - } - - /* set image offset and reference grid */ - image->x0 = (OPJ_UINT32)parameters->image_offset_x0; - image->y0 = (OPJ_UINT32)parameters->image_offset_y0; - image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; - image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; - - /* set image data */ - - /* Place the cursor at the beginning of the image information */ - fseek(IN, 0, SEEK_SET); - fseek(IN, (long)File_h.bfOffBits, SEEK_SET); - - W = Info_h.biWidth; - H = Info_h.biHeight; - - /* PAD = 4 - (3 * W) % 4; */ - /* PAD = (PAD == 4) ? 0 : PAD; */ - PAD = (3 * W) % 4 ? 4 - (3 * W) % 4 : 0; - - RGB = (unsigned char *) - malloc((3 * W + PAD) * H * sizeof(unsigned char)); - - if ( fread(RGB, sizeof(unsigned char), (3 * W + PAD) * H, IN) != (3 * W + PAD) * H ) - { - free(RGB); - opj_image_destroy(image); - fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); - return NULL; - } - - index = 0; - - for(y = 0; y < H; y++) - { - unsigned char *scanline = RGB + (3 * (unsigned int)W + PAD) * ((unsigned int)H - 1 - (unsigned int)y); - for(x = 0; x < W; x++) - { - unsigned char *pixel = &scanline[3 * x]; - image->comps[0].data[index] = pixel[2]; /* R */ - image->comps[1].data[index] = pixel[1]; /* G */ - image->comps[2].data[index] = pixel[0]; /* B */ - index++; - } - } - free(RGB); - }/* if (Info_h.biBitCount == 24) */ - else - if (Info_h.biBitCount == 8 && Info_h.biCompression == 0)/*RGB */ - { - if(Info_h.biClrUsed == 0) Info_h.biClrUsed = 256; - else - if(Info_h.biClrUsed > 256) Info_h.biClrUsed = 256; - - table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); - table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); - table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); - - has_color = 0; - for (j = 0; j < Info_h.biClrUsed; j++) - { - table_B[j] = (unsigned char)getc(IN); - table_G[j] = (unsigned char)getc(IN); - table_R[j] = (unsigned char)getc(IN); - getc(IN); - has_color += - !(table_R[j] == table_G[j] && table_R[j] == table_B[j]); - } - if(has_color) gray_scale = 0; - - /* Place the cursor at the beginning of the image information */ - fseek(IN, 0, SEEK_SET); - fseek(IN, (long)File_h.bfOffBits, SEEK_SET); - - W = Info_h.biWidth; - H = Info_h.biHeight; - if (Info_h.biWidth % 2) - W++; - - numcomps = gray_scale ? 1 : 3; - color_space = gray_scale ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB; - /* initialize image components */ - memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); - for(i = 0; i < numcomps; i++) - { - cmptparm[i].prec = 8; - cmptparm[i].bpp = 8; - cmptparm[i].sgnd = 0; - cmptparm[i].dx = (OPJ_UINT32)subsampling_dx; - cmptparm[i].dy = (OPJ_UINT32)subsampling_dy; - cmptparm[i].w = (OPJ_UINT32)w; - cmptparm[i].h = (OPJ_UINT32)h; - } - /* create the image */ - image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); - if(!image) - { - fclose(IN); - free(table_R); free(table_G); free(table_B); - return NULL; - } - - /* set image offset and reference grid */ - image->x0 = (OPJ_UINT32)parameters->image_offset_x0; - image->y0 = (OPJ_UINT32)parameters->image_offset_y0; - image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; - image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; - - /* set image data */ - - RGB = (unsigned char *) malloc(W * H * sizeof(unsigned char)); - - if ( fread(RGB, sizeof(unsigned char), W * H, IN) != W * H ) - { - free(table_R); - free(table_G); - free(table_B); - free(RGB); - opj_image_destroy(image); - fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); - return NULL; - } - if (gray_scale) - { - index = 0; - for (j = 0; j < W * H; j++) - { - if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) - { - image->comps[0].data[index] = - table_R[RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]]; - index++; - } - } - - } - else - { - index = 0; - for (j = 0; j < W * H; j++) - { - if ((j % W < W - 1 && Info_h.biWidth % 2) - || !(Info_h.biWidth % 2)) - { - unsigned char pixel_index = - RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]; - image->comps[0].data[index] = table_R[pixel_index]; - image->comps[1].data[index] = table_G[pixel_index]; - image->comps[2].data[index] = table_B[pixel_index]; - index++; - } - } - } - free(RGB); - free(table_R); - free(table_G); - free(table_B); - }/* RGB8 */ - else - if (Info_h.biBitCount == 8 && Info_h.biCompression == 1)/*RLE8*/ - { - unsigned char *pix, *beyond; - int *gray, *red, *green, *blue; - unsigned int max; - int c, c1; - unsigned char uc; - - if (Info_h.biClrUsed == 0) - Info_h.biClrUsed = 256; - else if (Info_h.biClrUsed > 256) - Info_h.biClrUsed = 256; - - table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); - table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); - table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); - - has_color = 0; - for (j = 0; j < Info_h.biClrUsed; j++) - { - table_B[j] = (unsigned char)getc(IN); - table_G[j] = (unsigned char)getc(IN); - table_R[j] = (unsigned char)getc(IN); - getc(IN); - has_color += !(table_R[j] == table_G[j] && table_R[j] == table_B[j]); - } - - if (has_color) - gray_scale = 0; - - numcomps = gray_scale ? 1 : 3; - color_space = gray_scale ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB; - /* initialize image components */ - memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); - for (i = 0; i < numcomps; i++) - { - cmptparm[i].prec = 8; - cmptparm[i].bpp = 8; - cmptparm[i].sgnd = 0; - cmptparm[i].dx = (OPJ_UINT32)subsampling_dx; - cmptparm[i].dy = (OPJ_UINT32)subsampling_dy; - cmptparm[i].w = (OPJ_UINT32)w; - cmptparm[i].h = (OPJ_UINT32)h; - } - /* create the image */ - image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); - if (!image) - { - fclose(IN); - free(table_R); - free(table_G); - free(table_B); - return NULL; - } - - /* set image offset and reference grid */ - image->x0 = (OPJ_UINT32)parameters->image_offset_x0; - image->y0 = (OPJ_UINT32)parameters->image_offset_y0; - image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; - image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; - - /* set image data */ - - /* Place the cursor at the beginning of the image information */ - fseek(IN, 0, SEEK_SET); - fseek(IN, (long)File_h.bfOffBits, SEEK_SET); - - W = Info_h.biWidth; - H = Info_h.biHeight; - RGB = (unsigned char *) calloc(1, W * H * sizeof(unsigned char)); - beyond = RGB + W * H; - pix = beyond - W; - x = y = 0; - - while (y < H) - { - c = getc(IN); - - if (c) - { - c1 = getc(IN); - - for (i = 0; i < c && x < W && pix < beyond; i++, x++, pix++) - *pix = (unsigned char)c1; - } - else - { - c = getc(IN); - - if (c == 0x00) /* EOL */ - { - x = 0; - ++y; - pix = RGB + x + (H - y - 1) * W; - } - else if (c == 0x01) /* EOP */ - break; - else if (c == 0x02) /* MOVE by dxdy */ - { - c = getc(IN); - x += (unsigned int)c; - c = getc(IN); - y += (unsigned int)c; - pix = RGB + (H - y - 1) * W + x; - } - else /* 03 .. 255 */ - { - i = 0; - for (; i < c && x < W && pix < beyond; i++, x++, pix++) - { - c1 = getc(IN); - *pix = (unsigned char)c1; - } - if (c & 1) /* skip padding byte */ - getc(IN); - } - } - }/* while() */ - - if (gray_scale) - { - gray = image->comps[0].data; - pix = RGB; - max = W * H; - - while (max--) - { - uc = *pix++; - - *gray++ = table_R[uc]; - } - } - else - { - /*int *red, *green, *blue;*/ - - red = image->comps[0].data; - green = image->comps[1].data; - blue = image->comps[2].data; - pix = RGB; - max = W * H; - - while (max--) - { - uc = *pix++; - - *red++ = table_R[uc]; - *green++ = table_G[uc]; - *blue++ = table_B[uc]; - } - } - free(RGB); - free(table_R); - free(table_G); - free(table_B); - }/* RLE8 */ - else - { - fprintf(stderr, - "Other system than 24 bits/pixels or 8 bits (no RLE coding) " - "is not yet implemented [%d]\n", Info_h.biBitCount); - } - fclose(IN); - return image; -} - -int imagetobmp(opj_image_t * image, const char *outfile) { - int w, h; - int i, pad; - FILE *fdest = NULL; - int adjustR, adjustG, adjustB; - - if (image->comps[0].prec < 8) { - fprintf(stderr, "Unsupported number of components: %d\n", image->comps[0].prec); - return 1; - } - if (image->numcomps >= 3 && image->comps[0].dx == image->comps[1].dx - && image->comps[1].dx == image->comps[2].dx - && image->comps[0].dy == image->comps[1].dy - && image->comps[1].dy == image->comps[2].dy - && image->comps[0].prec == image->comps[1].prec - && image->comps[1].prec == image->comps[2].prec) { - - /* -->> -->> -->> -->> - 24 bits color - <<-- <<-- <<-- <<-- */ - - fdest = fopen(outfile, "wb"); - if (!fdest) { - fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); - return 1; - } - - w = (int)image->comps[0].w; - h = (int)image->comps[0].h; - - fprintf(fdest, "BM"); - - /* FILE HEADER */ - /* ------------- */ - fprintf(fdest, "%c%c%c%c", - (unsigned char) (h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff,((54) >> 16) & 0xff, ((54) >> 24) & 0xff); - - /* INFO HEADER */ - /* ------------- */ - fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), - (unsigned char) ((w) >> 8) & 0xff, - (unsigned char) ((w) >> 16) & 0xff, - (unsigned char) ((w) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), - (unsigned char) ((h) >> 8) & 0xff, - (unsigned char) ((h) >> 16) & 0xff, - (unsigned char) ((h) >> 24) & 0xff); - fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); - fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) (3 * h * w + 3 * h * (w % 2)) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, - (unsigned char) ((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - - if (image->comps[0].prec > 8) { - adjustR = (int)image->comps[0].prec - 8; - printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); - } - else - adjustR = 0; - if (image->comps[1].prec > 8) { - adjustG = (int)image->comps[1].prec - 8; - printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); - } - else - adjustG = 0; - if (image->comps[2].prec > 8) { - adjustB = (int)image->comps[2].prec - 8; - printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); - } - else - adjustB = 0; - - for (i = 0; i < w * h; i++) { - unsigned char rc, gc, bc; - int r, g, b; - - r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - r = ((r >> adjustR)+((r >> (adjustR-1))%2)); - if(r > 255) r = 255; else if(r < 0) r = 0; - rc = (unsigned char)r; - - g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; - g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - g = ((g >> adjustG)+((g >> (adjustG-1))%2)); - if(g > 255) g = 255; else if(g < 0) g = 0; - gc = (unsigned char)g; - - b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; - b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - b = ((b >> adjustB)+((b >> (adjustB-1))%2)); - if(b > 255) b = 255; else if(b < 0) b = 0; - bc = (unsigned char)b; - - fprintf(fdest, "%c%c%c", bc, gc, rc); - - if ((i + 1) % w == 0) { - for (pad = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; pad > 0; pad--) /* ADD */ - fprintf(fdest, "%c", 0); - } - } - fclose(fdest); - } else { /* Gray-scale */ - - /* -->> -->> -->> -->> - 8 bits non code (Gray scale) - <<-- <<-- <<-- <<-- */ - - fdest = fopen(outfile, "wb"); - w = (int)image->comps[0].w; - h = (int)image->comps[0].h; - - fprintf(fdest, "BM"); - - /* FILE HEADER */ - /* ------------- */ - fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + 54 + 1024 + h * (w % 2)) & 0xff, - (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, - (unsigned char) ((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, - (unsigned char) ((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, - ((54 + 1024) >> 16) & 0xff, - ((54 + 1024) >> 24) & 0xff); - - /* INFO HEADER */ - /* ------------- */ - fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) ((w) & 0xff), - (unsigned char) ((w) >> 8) & 0xff, - (unsigned char) ((w) >> 16) & 0xff, - (unsigned char) ((w) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) ((h) & 0xff), - (unsigned char) ((h) >> 8) & 0xff, - (unsigned char) ((h) >> 16) & 0xff, - (unsigned char) ((h) >> 24) & 0xff); - fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); - fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); - fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (unsigned char) (h * w + h * (w % 2)) & 0xff, - (unsigned char) ((h * w + h * (w % 2)) >> 8) & 0xff, - (unsigned char) ((h * w + h * (w % 2)) >> 16) & 0xff, - (unsigned char) ((h * w + h * (w % 2)) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); - fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); - - if (image->comps[0].prec > 8) { - adjustR = (int)image->comps[0].prec - 8; - printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); - }else - adjustR = 0; - - for (i = 0; i < 256; i++) { - fprintf(fdest, "%c%c%c%c", i, i, i, 0); - } - - for (i = 0; i < w * h; i++) { - int r; - - r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - r = ((r >> adjustR)+((r >> (adjustR-1))%2)); - if(r > 255) r = 255; else if(r < 0) r = 0; - - fprintf(fdest, "%c", (unsigned char)r); - - if ((i + 1) % w == 0) { - for (pad = w % 4 ? 4 - w % 4 : 0; pad > 0; pad--) /* ADD */ - fprintf(fdest, "%c", 0); - } - } - fclose(fdest); - } - - return 0; -} - /* -->> -->> -->> -->> PGX IMAGE FORMAT @@ -1320,6 +1096,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) { fseek(f, 0, SEEK_SET); if( fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d",temp,&endian1,&endian2,signtmp,&prec,temp,&w,temp,&h) != 9){ + fclose(f); fprintf(stderr, "ERROR: Failed to read the right number of element from the fscanf() function!\n"); return NULL; } @@ -1337,6 +1114,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) { } else if (endian2=='M' && endian1=='L') { bigendian = 0; } else { + fclose(f); fprintf(stderr, "Bad pgx header, please check input file\n"); return NULL; } @@ -1451,7 +1229,7 @@ int imagetopgx(opj_image_t * image, const char *outfile) FILE *fdest = NULL; for (compno = 0; compno < image->numcomps; compno++) - { + { opj_image_comp_t *comp = &image->comps[compno]; char bname[256]; /* buffer for name */ char *name = bname; /* pointer */ @@ -1462,25 +1240,30 @@ int imagetopgx(opj_image_t * image, const char *outfile) const size_t total = dotpos + 1 + 1 + 4; /* '-' + '[1-3]' + '.pgx' */ if( outfile[dotpos] != '.' ) - { + { /* `pgx` was recognized but there is no dot at expected position */ fprintf(stderr, "ERROR -> Impossible happen." ); goto fin; - } + } if( total > 256 ) - { + { name = (char*)malloc(total+1); - } + if (name == NULL) { + goto fin; + } + } strncpy(name, outfile, dotpos); - sprintf(name+dotpos, "_%d.pgx", compno); + sprintf(name+dotpos, "_%u.pgx", compno); fdest = fopen(name, "wb"); - /* dont need name anymore */ - if( total > 256 ) free(name); + /* don't need name anymore */ + if (!fdest) - { + { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + if( total > 256 ) free(name); goto fin; - } + } w = (int)image->comps[compno].w; h = (int)image->comps[compno].h; @@ -1496,26 +1279,28 @@ int imagetopgx(opj_image_t * image, const char *outfile) nbytes = 4; for (i = 0; i < w * h; i++) - { + { /* FIXME: clamp func is being called within a loop */ const int val = clamp(image->comps[compno].data[i], (int)comp->prec, (int)comp->sgnd); for (j = nbytes - 1; j >= 0; j--) - { + { int v = (int)(val >> (j * 8)); unsigned char byte = (unsigned char)v; res = fwrite(&byte, 1, 1, fdest); if( res < 1 ) - { + { fprintf(stderr, "failed to write 1 byte for %s\n", name); + if( total > 256 ) free(name); goto fin; - } - } - } + } + } + } + if( total > 256 ) free(name); fclose(fdest); fdest = NULL; - } + } fails = 0; fin: if(fdest) fclose(fdest); @@ -1552,7 +1337,7 @@ static char *skip_int(char *start, int *out_n) char *s; char c; - *out_n = 0; s = start; + *out_n = 0; s = skip_white(start); if(s == NULL) return NULL; @@ -1587,7 +1372,6 @@ static char *skip_idf(char *start, char out_idf[256]) static void read_pnm_header(FILE *reader, struct pnm_header *ph) { - char *s; int format, have_wh, end, ttype; char idf[256], type[256]; char line[256]; @@ -1613,6 +1397,8 @@ static void read_pnm_header(FILE *reader, struct pnm_header *ph) while(fgets(line, 250, reader)) { + char *s; + if(*line == '#') continue; s = line; @@ -1696,7 +1482,18 @@ static void read_pnm_header(FILE *reader, struct pnm_header *ph) have_wh = 1; if(format == 1 || format == 4) break; - + + if(format == 2 || format == 3 || format == 5 || format == 6) + { + if (skip_int(s, &ph->maxval) != NULL) { + if(ph->maxval > 65535) { + return; + } + else { + break; + } + } + } continue; } if(format == 2 || format == 3 || format == 5 || format == 6) @@ -1877,6 +1674,7 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) { { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); opj_image_destroy(image); + fclose(fp); return NULL; } if(one) @@ -1946,7 +1744,7 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) { return image; }/* pnmtoimage() */ -int imagetopnm(opj_image_t * image, const char *outfile) +int imagetopnm(opj_image_t * image, const char *outfile, int force_split) { int *red, *green, *blue, *alpha; int wr, hr, max; @@ -1976,7 +1774,8 @@ int imagetopnm(opj_image_t * image, const char *outfile) if(want_gray) ncomp = 1; - if (ncomp == 2 /* GRAYA */ + if ((force_split == 0) && + (ncomp == 2 /* GRAYA */ || (ncomp > 2 /* RGB, RGBA */ && image->comps[0].dx == image->comps[1].dx && image->comps[1].dx == image->comps[2].dx @@ -1984,8 +1783,8 @@ int imagetopnm(opj_image_t * image, const char *outfile) && image->comps[1].dy == image->comps[2].dy && image->comps[0].prec == image->comps[1].prec && image->comps[1].prec == image->comps[2].prec - )) - { + ))) + { fdest = fopen(outfile, "wb"); if (!fdest) @@ -2011,7 +1810,7 @@ int imagetopnm(opj_image_t * image, const char *outfile) { const char *tt = (triple?"RGB_ALPHA":"GRAYSCALE_ALPHA"); - fprintf(fdest, "P7\n# OpenJPEG-%s\nWIDTH %d\nHEIGHT %d\nDEPTH %d\n" + fprintf(fdest, "P7\n# OpenJPEG-%s\nWIDTH %d\nHEIGHT %d\nDEPTH %u\n" "MAXVAL %d\nTUPLTYPE %s\nENDHDR\n", opj_version(), wr, hr, ncomp, max, tt); alpha = image->comps[ncomp - 1].data; @@ -2117,7 +1916,7 @@ if(v > 65535) v = 65535; else if(v < 0) v = 0; const size_t dotpos = olen - 4; strncpy(destname, outfile, dotpos); - sprintf(destname+dotpos, "_%d.pgm", compno); + sprintf(destname+dotpos, "_%u.pgm", compno); } else sprintf(destname, "%s", outfile); @@ -2177,769 +1976,6 @@ if(v > 65535) v = 65535; else if(v < 0) v = 0; return 0; }/* imagetopnm() */ -#ifdef OPJ_HAVE_LIBTIFF -/* -->> -->> -->> -->> - - TIFF IMAGE FORMAT - - <<-- <<-- <<-- <<-- */ - -int imagetotif(opj_image_t * image, const char *outfile) -{ - int width, height, imgsize; - int bps,index,adjust, sgnd; - int ushift, dshift, has_alpha, force16; - TIFF *tif; - tdata_t buf; - tstrip_t strip; - tsize_t strip_size; - - ushift = dshift = force16 = has_alpha = 0; - bps = (int)image->comps[0].prec; - - if(bps > 8 && bps < 16) - { - ushift = 16 - bps; dshift = bps - ushift; - bps = 16; force16 = 1; - } - - if(bps != 8 && bps != 16) - { - fprintf(stderr,"imagetotif: Bits=%d, Only 8 and 16 bits implemented\n", - bps); - fprintf(stderr,"\tAborting\n"); - return 1; - } - tif = TIFFOpen(outfile, "wb"); - - if (!tif) - { - fprintf(stderr, "imagetotif:failed to open %s for writing\n", outfile); - return 1; - } - sgnd = (int)image->comps[0].sgnd; - adjust = sgnd ? 1 << (image->comps[0].prec - 1) : 0; - - if(image->numcomps >= 3 - && image->comps[0].dx == image->comps[1].dx - && image->comps[1].dx == image->comps[2].dx - && image->comps[0].dy == image->comps[1].dy - && image->comps[1].dy == image->comps[2].dy - && image->comps[0].prec == image->comps[1].prec - && image->comps[1].prec == image->comps[2].prec) - { - has_alpha = (image->numcomps == 4); - - width = (int)image->comps[0].w; - height = (int)image->comps[0].h; - imgsize = width * height ; - - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3 + has_alpha); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); - strip_size = TIFFStripSize(tif); - buf = _TIFFmalloc(strip_size); - index=0; - - for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++) - { - unsigned char *dat8; - tsize_t i, ssize, last_i = 0; - int step, restx; - ssize = TIFFStripSize(tif); - dat8 = (unsigned char*)buf; - - if(bps == 8) - { - step = 3 + has_alpha; - restx = step - 1; - - for(i=0; i < ssize - restx; i += step) - { - int r, g, b, a = 0; - - if(index < imgsize) - { - r = image->comps[0].data[index]; - g = image->comps[1].data[index]; - b = image->comps[2].data[index]; - if(has_alpha) a = image->comps[3].data[index]; - - if(sgnd) - { - r += adjust; - g += adjust; - b += adjust; - if(has_alpha) a += adjust; - } - if(r > 255) r = 255; else if(r < 0) r = 0; - dat8[i+0] = (unsigned char)r ; - if(g > 255) g = 255; else if(g < 0) g = 0; - dat8[i+1] = (unsigned char)g ; - if(b > 255) b = 255; else if(b < 0) b = 0; - dat8[i+2] = (unsigned char)b ; - if(has_alpha) - { - if(a > 255) a = 255; else if(a < 0) a = 0; - dat8[i+3] = (unsigned char)a; - } - - index++; - last_i = i + step; - } - else - break; - }/*for(i = 0;)*/ - - if(last_i < ssize) - { - for(i = last_i; i < ssize; i += step) - { - int r, g, b, a = 0; - - if(index < imgsize) - { - r = image->comps[0].data[index]; - g = image->comps[1].data[index]; - b = image->comps[2].data[index]; - if(has_alpha) a = image->comps[3].data[index]; - - if(sgnd) - { - r += adjust; - g += adjust; - b += adjust; - if(has_alpha) a += adjust; - } - if(r > 255) r = 255; else if(r < 0) r = 0; - if(g > 255) g = 255; else if(g < 0) g = 0; - if(b > 255) b = 255; else if(b < 0) b = 0; - - dat8[i+0] = (unsigned char)r ; - if(i+1 < ssize) dat8[i+1] = (unsigned char)g ; else break; - if(i+2 < ssize) dat8[i+2] = (unsigned char)b ; else break; - if(has_alpha) - { - if(a > 255) a = 255; else if(a < 0) a = 0; - - if(i+3 < ssize) dat8[i+3] = (unsigned char)a ; else break; - } - index++; - } - else - break; - }/*for(i)*/ - }/*if(last_i < ssize)*/ - - } /*if(bps == 8)*/ - else - if(bps == 16) - { - step = 6 + has_alpha + has_alpha; - restx = step - 1; - - for(i = 0; i < ssize - restx ; i += step) - { - int r, g, b, a = 0; - - if(index < imgsize) - { - r = image->comps[0].data[index]; - g = image->comps[1].data[index]; - b = image->comps[2].data[index]; - if(has_alpha) a = image->comps[3].data[index]; - - if(sgnd) - { - r += adjust; - g += adjust; - b += adjust; - if(has_alpha) a += adjust; - } - if(force16) - { - r = (r<>dshift); - g = (g<>dshift); - b = (b<>dshift); - if(has_alpha) a = (a<>dshift); - } - if(r > 65535) r = 65535; else if(r < 0) r = 0; - if(g > 65535) g = 65535; else if(g < 0) g = 0; - if(b > 65535) b = 65535; else if(b < 0) b = 0; - - dat8[i+0] = (unsigned char)r;/*LSB*/ - dat8[i+1] = (unsigned char)(r >> 8);/*MSB*/ - dat8[i+2] = (unsigned char)g; - dat8[i+3] = (unsigned char)(g >> 8); - dat8[i+4] = (unsigned char)b; - dat8[i+5] = (unsigned char)(b >> 8); - if(has_alpha) - { - if(a > 65535) a = 65535; else if(a < 0) a = 0; - dat8[i+6] = (unsigned char)a; - dat8[i+7] = (unsigned char)(a >> 8); - } - index++; - last_i = i + step; - } - else - break; - }/*for(i = 0;)*/ - - if(last_i < ssize) - { - for(i = last_i ; i < ssize ; i += step) - { - int r, g, b, a = 0; - - if(index < imgsize) - { - r = image->comps[0].data[index]; - g = image->comps[1].data[index]; - b = image->comps[2].data[index]; - if(has_alpha) a = image->comps[3].data[index]; - - if(sgnd) - { - r += adjust; - g += adjust; - b += adjust; - if(has_alpha) a += adjust; - } - if(force16) - { - r = (r<>dshift); - g = (g<>dshift); - b = (b<>dshift); - if(has_alpha) a = (a<>dshift); - } - if(r > 65535) r = 65535; else if(r < 0) r = 0; - if(g > 65535) g = 65535; else if(g < 0) g = 0; - if(b > 65535) b = 65535; else if(b < 0) b = 0; - - dat8[i+0] = (unsigned char) r;/*LSB*/ - if(i+1 < ssize) dat8[i+1] = (unsigned char)(r >> 8);else break;/*MSB*/ - if(i+2 < ssize) dat8[i+2] = (unsigned char) g; else break; - if(i+3 < ssize) dat8[i+3] = (unsigned char)(g >> 8);else break; - if(i+4 < ssize) dat8[i+4] = (unsigned char) b; else break; - if(i+5 < ssize) dat8[i+5] = (unsigned char)(b >> 8);else break; - - if(has_alpha) - { - if(a > 65535) a = 65535; else if(a < 0) a = 0; - if(i+6 < ssize) dat8[i+6] = (unsigned char)a; else break; - if(i+7 < ssize) dat8[i+7] = (unsigned char)(a >> 8); else break; - } - index++; - } - else - break; - }/*for(i)*/ - }/*if(last_i < ssize)*/ - - }/*if(bps == 16)*/ - (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); - }/*for(strip = 0; )*/ - - _TIFFfree((void*)buf); - TIFFClose(tif); - - return 0; - }/*RGB(A)*/ - - if(image->numcomps == 1 /* GRAY */ - || ( image->numcomps == 2 /* GRAY_ALPHA */ - && image->comps[0].dx == image->comps[1].dx - && image->comps[0].dy == image->comps[1].dy - && image->comps[0].prec == image->comps[1].prec)) - { - int step; - - has_alpha = (image->numcomps == 2); - - width = (int)image->comps[0].w; - height = (int)image->comps[0].h; - imgsize = width * height; - - /* Set tags */ - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1 + has_alpha); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); - - /* Get a buffer for the data */ - strip_size = TIFFStripSize(tif); - buf = _TIFFmalloc(strip_size); - index = 0; - - for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++) - { - unsigned char *dat8; - tsize_t i, ssize = TIFFStripSize(tif); - dat8 = (unsigned char*)buf; - - if(bps == 8) - { - step = 1 + has_alpha; - - for(i=0; i < ssize; i += step) - { - if(index < imgsize) - { - int r, a = 0; - - r = image->comps[0].data[index]; - if(has_alpha) a = image->comps[1].data[index]; - - if(sgnd) - { - r += adjust; - if(has_alpha) a += adjust; - } - if(r > 255) r = 255; else if(r < 0) r = 0; - dat8[i+0] = (unsigned char)r; - - if(has_alpha) - { - if(a > 255) a = 255; else if(a < 0) a = 0; - dat8[i+1] = (unsigned char)a; - } - index++; - } - else - break; - }/*for(i )*/ - }/*if(bps == 8*/ - else - if(bps == 16) - { - step = 2 + has_alpha + has_alpha; - - for(i=0; i < ssize; i += step) - { - if(index < imgsize) - { - int r, a = 0; - - r = image->comps[0].data[index]; - if(has_alpha) a = image->comps[1].data[index]; - - if(sgnd) - { - r += adjust; - if(has_alpha) a += adjust; - } - if(force16) - { - r = (r<>dshift); - if(has_alpha) a = (a<>dshift); - } - if(r > 65535) r = 65535; else if(r < 0) r = 0; - dat8[i+0] = (unsigned char)r;/*LSB*/ - dat8[i+1] = (unsigned char)(r >> 8);/*MSB*/ - if(has_alpha) - { - if(a > 65535) a = 65535; else if(a < 0) a = 0; - dat8[i+2] = (unsigned char)a; - dat8[i+3] = (unsigned char)(a >> 8); - } - index++; - }/*if(index < imgsize)*/ - else - break; - }/*for(i )*/ - } - (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); - }/*for(strip*/ - - _TIFFfree(buf); - TIFFClose(tif); - - return 0; - } - - TIFFClose(tif); - - fprintf(stderr,"imagetotif: Bad color format.\n" - "\tOnly RGB(A) and GRAY(A) has been implemented\n"); - fprintf(stderr,"\tFOUND: numcomps(%d)\n\tAborting\n", - image->numcomps); - - return 1; -}/* imagetotif() */ - -/* - * libtiff/tif_getimage.c : 1,2,4,8,16 bitspersample accepted - * CINEMA : 12 bit precision -*/ -opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) -{ - int subsampling_dx = parameters->subsampling_dx; - int subsampling_dy = parameters->subsampling_dy; - TIFF *tif; - tdata_t buf; - tstrip_t strip; - tsize_t strip_size; - int j, numcomps, w, h,index; - OPJ_COLOR_SPACE color_space; - opj_image_cmptparm_t cmptparm[4]; /* RGBA */ - opj_image_t *image = NULL; - int imgsize = 0; - int has_alpha = 0; - unsigned short tiBps, tiPhoto, tiSf, tiSpp, tiPC; - unsigned int tiWidth, tiHeight; - OPJ_BOOL is_cinema = OPJ_IS_CINEMA(parameters->rsiz); - - tif = TIFFOpen(filename, "r"); - - if(!tif) - { - fprintf(stderr, "tiftoimage:Failed to open %s for reading\n", filename); - return 0; - } - tiBps = tiPhoto = tiSf = tiSpp = tiPC = 0; - tiWidth = tiHeight = 0; - - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &tiWidth); - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &tiHeight); - TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiBps); - TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &tiSf); - TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiSpp); - TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &tiPhoto); - TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &tiPC); - w= (int)tiWidth; - h= (int)tiHeight; - - if(tiBps != 8 && tiBps != 16 && tiBps != 12) tiBps = 0; - if(tiPhoto != 1 && tiPhoto != 2) tiPhoto = 0; - - if( !tiBps || !tiPhoto) - { - if( !tiBps) - fprintf(stderr,"tiftoimage: Bits=%d, Only 8 and 16 bits" - " implemented\n",tiBps); - else - if( !tiPhoto) - fprintf(stderr,"tiftoimage: Bad color format %d.\n\tOnly RGB(A)" - " and GRAY(A) has been implemented\n",(int) tiPhoto); - - fprintf(stderr,"\tAborting\n"); - TIFFClose(tif); - - return NULL; - } - - {/* From: tiff-4.0.x/libtiff/tif_getimage.c : */ - uint16* sampleinfo; - uint16 extrasamples; - - TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, - &extrasamples, &sampleinfo); - - if(extrasamples >= 1) - { - switch(sampleinfo[0]) - { - case EXTRASAMPLE_UNSPECIFIED: - /* Workaround for some images without correct info about alpha channel -*/ - if(tiSpp > 3) - has_alpha = 1; - break; - - case EXTRASAMPLE_ASSOCALPHA: /* data pre-multiplied */ - case EXTRASAMPLE_UNASSALPHA: /* data not pre-multiplied */ - has_alpha = 1; - break; - } - } - else /* extrasamples == 0 */ - if(tiSpp == 4 || tiSpp == 2) has_alpha = 1; - } - - /* initialize image components -*/ - memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); - - if ((tiPhoto == PHOTOMETRIC_RGB) && (is_cinema)) { - fprintf(stdout,"WARNING:\n" - "Input image bitdepth is %d bits\n" - "TIF conversion has automatically rescaled to 12-bits\n" - "to comply with cinema profiles.\n", - tiBps); - } - - if(tiPhoto == PHOTOMETRIC_RGB) /* RGB(A) */ - { - numcomps = 3 + has_alpha; - color_space = OPJ_CLRSPC_SRGB; - - /*#define USETILEMODE*/ - for(j = 0; j < numcomps; j++) - { - if(is_cinema) - { - cmptparm[j].prec = 12; - cmptparm[j].bpp = 12; - } - else - { - cmptparm[j].prec = tiBps; - cmptparm[j].bpp = tiBps; - } - cmptparm[j].dx = (OPJ_UINT32)subsampling_dx; - cmptparm[j].dy = (OPJ_UINT32)subsampling_dy; - cmptparm[j].w = (OPJ_UINT32)w; - cmptparm[j].h = (OPJ_UINT32)h; -#ifdef USETILEMODE - cmptparm[j].x0 = 0; - cmptparm[j].y0 = 0; -#endif - } - -#ifdef USETILEMODE - image = opj_image_tile_create(numcomps,&cmptparm[0],color_space); -#else - image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); -#endif - - if(!image) - { - TIFFClose(tif); - return NULL; - } - /* set image offset and reference grid -*/ - image->x0 = (OPJ_UINT32)parameters->image_offset_x0; - image->y0 = (OPJ_UINT32)parameters->image_offset_y0; - image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : - image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; - image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : - image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; - - buf = _TIFFmalloc(TIFFStripSize(tif)); - - strip_size=TIFFStripSize(tif); - index = 0; - imgsize = (int)(image->comps[0].w * image->comps[0].h); - /* Read the Image components -*/ - for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++) - { - unsigned char *dat8; - int step; - tsize_t i, ssize; - ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); - dat8 = (unsigned char*)buf; - - if(tiBps == 16) - { - step = 6 + has_alpha + has_alpha; - - for(i = 0; i < ssize; i += step) - { - if(index < imgsize) - { - image->comps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; /* R */ - image->comps[1].data[index] = ( dat8[i+3] << 8 ) | dat8[i+2]; /* G */ - image->comps[2].data[index] = ( dat8[i+5] << 8 ) | dat8[i+4]; /* B */ - if(has_alpha) - image->comps[3].data[index] = ( dat8[i+7] << 8 ) | dat8[i+6]; - - if(is_cinema) - { - /* Rounding 16 to 12 bits -*/ - image->comps[0].data[index] = - (image->comps[0].data[index] + 0x08) >> 4 ; - image->comps[1].data[index] = - (image->comps[1].data[index] + 0x08) >> 4 ; - image->comps[2].data[index] = - (image->comps[2].data[index] + 0x08) >> 4 ; - if(has_alpha) - image->comps[3].data[index] = - (image->comps[3].data[index] + 0x08) >> 4 ; - } - index++; - } - else - break; - }/*for(i = 0)*/ - }/*if(tiBps == 16)*/ - else - if(tiBps == 8) - { - step = 3 + has_alpha; - - for(i = 0; i < ssize; i += step) - { - if(index < imgsize) - { -#ifndef USETILEMODE - image->comps[0].data[index] = dat8[i+0];/* R */ - image->comps[1].data[index] = dat8[i+1];/* G */ - image->comps[2].data[index] = dat8[i+2];/* B */ - if(has_alpha) - image->comps[3].data[index] = dat8[i+3]; -#endif - - if(is_cinema) - { - /* Rounding 8 to 12 bits -*/ -#ifndef USETILEMODE - image->comps[0].data[index] = image->comps[0].data[index] << 4 ; - image->comps[1].data[index] = image->comps[1].data[index] << 4 ; - image->comps[2].data[index] = image->comps[2].data[index] << 4 ; - if(has_alpha) - image->comps[3].data[index] = image->comps[3].data[index] << 4 ; -#endif - } - index++; - }/*if(index*/ - else - break; - }/*for(i )*/ - }/*if( tiBps == 8)*/ - else - if(tiBps == 12)/* CINEMA file */ - { - step = 9; - - for(i = 0; i < ssize; i += step) - { - if((index < imgsize)&(index+1 < imgsize)) - { - image->comps[0].data[index] = ( dat8[i+0]<<4 ) |(dat8[i+1]>>4); - image->comps[1].data[index] = ((dat8[i+1]& 0x0f)<< 8) | dat8[i+2]; - - image->comps[2].data[index] = ( dat8[i+3]<<4) |(dat8[i+4]>>4); - image->comps[0].data[index+1] = ((dat8[i+4]& 0x0f)<< 8) | dat8[i+5]; - - image->comps[1].data[index+1] = ( dat8[i+6] <<4) |(dat8[i+7]>>4); - image->comps[2].data[index+1] = ((dat8[i+7]& 0x0f)<< 8) | dat8[i+8]; - - index += 2; - } - else - break; - }/*for(i )*/ - } - }/*for(strip = 0; )*/ - - _TIFFfree(buf); - TIFFClose(tif); - - return image; - }/*RGB(A)*/ - - if(tiPhoto == PHOTOMETRIC_MINISBLACK) /* GRAY(A) */ - { - numcomps = 1 + has_alpha; - color_space = OPJ_CLRSPC_GRAY; - - for(j = 0; j < numcomps; ++j) - { - cmptparm[j].prec = tiBps; - cmptparm[j].bpp = tiBps; - cmptparm[j].dx = (OPJ_UINT32)subsampling_dx; - cmptparm[j].dy = (OPJ_UINT32)subsampling_dy; - cmptparm[j].w = (OPJ_UINT32)w; - cmptparm[j].h = (OPJ_UINT32)h; - } -#ifdef USETILEMODE - image = opj_image_tile_create(numcomps,&cmptparm[0],color_space); -#else - image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); -#endif - - if(!image) - { - TIFFClose(tif); - return NULL; - } - /* set image offset and reference grid -*/ - image->x0 = (OPJ_UINT32)parameters->image_offset_x0; - image->y0 = (OPJ_UINT32)parameters->image_offset_y0; - image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : - image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; - image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : - image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; - - buf = _TIFFmalloc(TIFFStripSize(tif)); - - strip_size = TIFFStripSize(tif); - index = 0; - imgsize = (int)(image->comps[0].w * image->comps[0].h); - /* Read the Image components -*/ - for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++) - { - unsigned char *dat8; - tsize_t i, ssize; - int step; - - ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); - dat8 = (unsigned char*)buf; - - if(tiBps == 16) - { - step = 2 + has_alpha + has_alpha; - - for(i = 0; i < ssize; i += step) - { - if(index < imgsize) - { - image->comps[0].data[index] = ( dat8[i+1] << 8 ) | dat8[i+0]; - if(has_alpha) - image->comps[1].data[index] = ( dat8[i+3] << 8 ) | dat8[i+2]; - index++; - } - else - break; - }/*for(i )*/ - } - else - if(tiBps == 8) - { - step = 1 + has_alpha; - - for(i = 0; i < ssize; i += step) - { - if(index < imgsize) - { - image->comps[0].data[index] = dat8[i+0]; - if(has_alpha) - image->comps[1].data[index] = dat8[i+1]; - index++; - } - else - break; - }/*for(i )*/ - } - }/*for(strip = 0;*/ - - _TIFFfree(buf); - TIFFClose(tif); - - }/*GRAY(A)*/ - - return image; - -}/* tiftoimage() */ - -#endif /* OPJ_HAVE_LIBTIFF */ - /* -->> -->> -->> -->> RAW IMAGE FORMAT @@ -2977,7 +2013,7 @@ static opj_image_t* rawtoimage_common(const char *filename, opj_cparameters_t *p numcomps = raw_cp->rawComp; /* FIXME ADE at this point, tcp_mct has not been properly set in calling function */ - if (numcomps == 0) { + if (numcomps == 1) { color_space = OPJ_CLRSPC_GRAY; } else if ((numcomps >= 3) && (parameters->tcp_mct == 0)) { color_space = OPJ_CLRSPC_SYCC; @@ -2988,10 +2024,14 @@ static opj_image_t* rawtoimage_common(const char *filename, opj_cparameters_t *p } w = raw_cp->rawWidth; h = raw_cp->rawHeight; - cmptparm = (opj_image_cmptparm_t*) malloc((size_t)numcomps * sizeof(opj_image_cmptparm_t)); - + cmptparm = (opj_image_cmptparm_t*) calloc((OPJ_UINT32)numcomps,sizeof(opj_image_cmptparm_t)); + if (!cmptparm) { + fprintf(stderr, "Failed to allocate image components parameters !!\n"); + fprintf(stderr,"Aborting\n"); + fclose(f); + return NULL; + } /* initialize image components */ - memset(&cmptparm[0], 0, (size_t)numcomps * sizeof(opj_image_cmptparm_t)); for(i = 0; i < numcomps; i++) { cmptparm[i].prec = (OPJ_UINT32)raw_cp->rawBitDepth; cmptparm[i].bpp = (OPJ_UINT32)raw_cp->rawBitDepth; @@ -3018,10 +2058,12 @@ static opj_image_t* rawtoimage_common(const char *filename, opj_cparameters_t *p { unsigned char value = 0; for(compno = 0; compno < numcomps; compno++) { - int nloop = (w*h)/(raw_cp->rawComps[compno].dx*raw_cp->rawComps[compno].dx); + int nloop = (w*h)/(raw_cp->rawComps[compno].dx*raw_cp->rawComps[compno].dy); for (i = 0; i < nloop; i++) { if (!fread(&value, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); return NULL; } image->comps[compno].data[i] = raw_cp->rawSigned?(char)value:value; @@ -3032,16 +2074,20 @@ static opj_image_t* rawtoimage_common(const char *filename, opj_cparameters_t *p { unsigned short value; for(compno = 0; compno < numcomps; compno++) { - int nloop = (w*h)/(raw_cp->rawComps[compno].dx*raw_cp->rawComps[compno].dx); + int nloop = (w*h)/(raw_cp->rawComps[compno].dx*raw_cp->rawComps[compno].dy); for (i = 0; i < nloop; i++) { unsigned char temp1; unsigned char temp2; if (!fread(&temp1, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); return NULL; } if (!fread(&temp2, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); return NULL; } if( big_endian ) @@ -3058,6 +2104,8 @@ static opj_image_t* rawtoimage_common(const char *filename, opj_cparameters_t *p } else { fprintf(stderr,"OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + opj_image_destroy(image); + fclose(f); return NULL; } @@ -3105,7 +2153,7 @@ static int imagetoraw_common(opj_image_t * image, const char *outfile, OPJ_BOOL for(compno = 0; compno < image->numcomps; compno++) { - fprintf(stdout,"Component %d characteristics: %dx%dx%d %s\n", compno, image->comps[compno].w, + fprintf(stdout,"Component %u characteristics: %dx%dx%d %s\n", compno, image->comps[compno].w, image->comps[compno].h, image->comps[compno].prec, image->comps[compno].sgnd==1 ? "signed": "unsigned"); w = (int)image->comps[compno].w; @@ -3179,7 +2227,7 @@ static int imagetoraw_common(opj_image_t * image, const char *outfile, OPJ_BOOL for (line = 0; line < h; line++) { for(row = 0; row < w; row++) { curr = *ptr; - if(curr > 65536 ) curr = 65536; else if( curr < 0) curr = 0; + if(curr > 65535 ) curr = 65535; else if( curr < 0) curr = 0; uc16.val = (unsigned short)(curr & mask); res = fwrite(uc16.vals, 1, 2, rawFile); if( res < 2 ) { @@ -3218,559 +2266,3 @@ int imagetorawl(opj_image_t * image, const char *outfile) return imagetoraw_common(image, outfile, OPJ_FALSE); } -#ifdef OPJ_HAVE_LIBPNG - -#define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a" -#define MAGIC_SIZE 8 -/* PNG allows bits per sample: 1, 2, 4, 8, 16 */ - -opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) -{ - png_structp png; - png_infop info; - double gamma, display_exponent; - int bit_depth, interlace_type,compression_type, filter_type; - int unit; - png_uint_32 resx, resy; - unsigned int i, j; - png_uint_32 width, height; - int color_type, has_alpha, is16; - unsigned char *s; - FILE *reader; - unsigned char **rows; - /* j2k: */ - opj_image_t *image; - opj_image_cmptparm_t cmptparm[4]; - int sub_dx, sub_dy; - unsigned int nr_comp; - int *r, *g, *b, *a = NULL; - unsigned char sigbuf[8]; - - if((reader = fopen(read_idf, "rb")) == NULL) - { - fprintf(stderr,"pngtoimage: can not open %s\n",read_idf); - return NULL; - } - image = NULL; png = NULL; rows = NULL; - - if(fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE - || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0) - { - fprintf(stderr,"pngtoimage: %s is no valid PNG file\n",read_idf); - goto fin; - } - /* libpng-VERSION/example.c: - * PC : screen_gamma = 2.2; - * Mac: screen_gamma = 1.7 or 1.0; -*/ - display_exponent = 2.2; - - if((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL)) == NULL) - goto fin; - if((info = png_create_info_struct(png)) == NULL) - goto fin; - - if(setjmp(png_jmpbuf(png))) - goto fin; - - png_init_io(png, reader); - png_set_sig_bytes(png, MAGIC_SIZE); - - png_read_info(png, info); - - if(png_get_IHDR(png, info, &width, &height, - &bit_depth, &color_type, &interlace_type, - &compression_type, &filter_type) == 0) - goto fin; - - /* png_set_expand(): - * 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. -*/ - if(color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png); - else - if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand(png); - - if(png_get_valid(png, info, PNG_INFO_tRNS)) - png_set_expand(png); - - is16 = (bit_depth == 16); - - /* GRAY => RGB; GRAY_ALPHA => RGBA -*/ - if(color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - png_set_gray_to_rgb(png); - color_type = - (color_type == PNG_COLOR_TYPE_GRAY? PNG_COLOR_TYPE_RGB: - PNG_COLOR_TYPE_RGB_ALPHA); - } - if( !png_get_gAMA(png, info, &gamma)) - gamma = 0.45455; - - png_set_gamma(png, display_exponent, gamma); - - png_read_update_info(png, info); - - png_get_pHYs(png, info, &resx, &resy, &unit); - - color_type = png_get_color_type(png, info); - - has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA); - - nr_comp = 3 + (unsigned int)has_alpha; - - bit_depth = png_get_bit_depth(png, info); - - rows = (unsigned char**)calloc(height+1, sizeof(unsigned char*)); - for(i = 0; i < height; ++i) - rows[i] = (unsigned char*)malloc(png_get_rowbytes(png,info)); - - png_read_image(png, rows); - - memset(cmptparm, 0, sizeof(cmptparm)); - - sub_dx = params->subsampling_dx; sub_dy = params->subsampling_dy; - - for(i = 0; i < nr_comp; ++i) - { - cmptparm[i].prec = (OPJ_UINT32)bit_depth; - /* bits_per_pixel: 8 or 16 */ - cmptparm[i].bpp = (OPJ_UINT32)bit_depth; - cmptparm[i].sgnd = 0; - cmptparm[i].dx = (OPJ_UINT32)sub_dx; - cmptparm[i].dy = (OPJ_UINT32)sub_dy; - cmptparm[i].w = (OPJ_UINT32)width; - cmptparm[i].h = (OPJ_UINT32)height; - } - - image = opj_image_create(nr_comp, &cmptparm[0], OPJ_CLRSPC_SRGB); - - if(image == NULL) goto fin; - - image->x0 = (OPJ_UINT32)params->image_offset_x0; - image->y0 = (OPJ_UINT32)params->image_offset_y0; - image->x1 = (OPJ_UINT32)(image->x0 + (width - 1) * (OPJ_UINT32)sub_dx + 1 + image->x0); - image->y1 = (OPJ_UINT32)(image->y0 + (height - 1) * (OPJ_UINT32)sub_dy + 1 + image->y0); - - r = image->comps[0].data; - g = image->comps[1].data; - b = image->comps[2].data; - if(has_alpha) a = image->comps[3].data; - - for(i = 0; i < height; ++i) - { - s = rows[i]; - - for(j = 0; j < width; ++j) - { - if(is16) - { - *r++ = s[0]<<8|s[1]; s += 2; - - *g++ = s[0]<<8|s[1]; s += 2; - - *b++ = s[0]<<8|s[1]; s += 2; - - if(has_alpha) { *a++ = s[0]<<8|s[1]; s += 2; } - - continue; - } - *r++ = *s++; *g++ = *s++; *b++ = *s++; - - if(has_alpha) *a++ = *s++; - } - } -fin: - if(rows) - { - for(i = 0; i < height; ++i) - free(rows[i]); - free(rows); - } - if(png) - png_destroy_read_struct(&png, &info, NULL); - - fclose(reader); - - return image; - -}/* pngtoimage() */ - -int imagetopng(opj_image_t * image, const char *write_idf) -{ - FILE *writer; - png_structp png; - png_infop info; - int *red, *green, *blue, *alpha; - unsigned char *row_buf, *d; - int has_alpha, width, height, nr_comp, color_type; - int adjustR, adjustG, adjustB, adjustA, x, y, fails; - int prec, ushift, dshift, is16, force16, force8; - unsigned short mask = 0xffff; - png_color_8 sig_bit; - - is16 = force16 = force8 = ushift = dshift = 0; fails = 1; - prec = (int)image->comps[0].prec; - nr_comp = (int)image->numcomps; - - if(prec > 8 && prec < 16) - { - ushift = 16 - prec; dshift = prec - ushift; - prec = 16; force16 = 1; - } - else - if(prec < 8 && nr_comp > 1)/* GRAY_ALPHA, RGB, RGB_ALPHA */ - { - ushift = 8 - prec; dshift = 8 - ushift; - prec = 8; force8 = 1; - } - - if(prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) - { - fprintf(stderr,"imagetopng: can not create %s" - "\n\twrong bit_depth %d\n", write_idf, prec); - return fails; - } - writer = fopen(write_idf, "wb"); - - if(writer == NULL) return fails; - - info = NULL; has_alpha = 0; - - /* 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 = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); - /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ - - if(png == NULL) goto fin; - - /* Allocate/initialize the image information data. REQUIRED -*/ - info = png_create_info_struct(png); - - if(info == NULL) goto fin; - - /* Set error handling. REQUIRED if you are not supplying your own - * error handling functions in the png_create_write_struct() call. -*/ - if(setjmp(png_jmpbuf(png))) goto fin; - - /* I/O initialization functions is REQUIRED -*/ - png_init_io(png, writer); - - /* 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 - * - * ERRORS: - * - * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8 - * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8 - * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8 - * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8 - * -*/ - png_set_compression_level(png, Z_BEST_COMPRESSION); - - if(prec == 16) mask = 0xffff; - else - if(prec == 8) mask = 0x00ff; - else - if(prec == 4) mask = 0x000f; - else - if(prec == 2) mask = 0x0003; - else - if(prec == 1) mask = 0x0001; - - if(nr_comp >= 3 - && image->comps[0].dx == image->comps[1].dx - && image->comps[1].dx == image->comps[2].dx - && image->comps[0].dy == image->comps[1].dy - && image->comps[1].dy == image->comps[2].dy - && image->comps[0].prec == image->comps[1].prec - && image->comps[1].prec == image->comps[2].prec) - { - int v; - - has_alpha = (nr_comp > 3); - - is16 = (prec == 16); - - width = (int)image->comps[0].w; - height = (int)image->comps[0].h; - - red = image->comps[0].data; - green = image->comps[1].data; - blue = image->comps[2].data; - - sig_bit.red = sig_bit.green = sig_bit.blue = (png_byte)prec; - - if(has_alpha) - { - sig_bit.alpha = (png_byte)prec; - alpha = image->comps[3].data; - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - adjustA = (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); - } - else - { - sig_bit.alpha = 0; alpha = NULL; - color_type = PNG_COLOR_TYPE_RGB; - adjustA = 0; - } - png_set_sBIT(png, info, &sig_bit); - - png_set_IHDR(png, info, (png_uint_32)width, (png_uint_32)height, prec, - color_type, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_set_gamma(png, 2.2, 1./2.2); - png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL); - /*=============================*/ - png_write_info(png, info); - /*=============================*/ - if(prec < 8) - { - png_set_packing(png); - } -printf("%s:%d:sgnd(%d,%d,%d) w(%d) h(%d) alpha(%d)\n",__FILE__,__LINE__, -image->comps[0].sgnd, -image->comps[1].sgnd,image->comps[2].sgnd,width,height,has_alpha); - - adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - - row_buf = (unsigned char*)malloc((size_t)width * (size_t)nr_comp * 2); - - for(y = 0; y < height; ++y) - { - d = row_buf; - - for(x = 0; x < width; ++x) - { - if(is16) - { - v = *red + adjustR; ++red; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - - v = *green + adjustG; ++green; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - - v = *blue + adjustB; ++blue; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - - if(has_alpha) - { - v = *alpha + adjustA; ++alpha; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - } - continue; - }/* if(is16) */ - - v = *red + adjustR; ++red; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - - v = *green + adjustG; ++green; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - - v = *blue + adjustB; ++blue; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - - if(has_alpha) - { - v = *alpha + adjustA; ++alpha; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - } - } /* for(x) */ - - png_write_row(png, row_buf); - - } /* for(y) */ - free(row_buf); - - }/* nr_comp >= 3 */ - else - if(nr_comp == 1 /* GRAY */ - || ( nr_comp == 2 /* GRAY_ALPHA */ - && image->comps[0].dx == image->comps[1].dx - && image->comps[0].dy == image->comps[1].dy - && image->comps[0].prec == image->comps[1].prec)) - { - int v; - - red = image->comps[0].data; - - sig_bit.gray = (png_byte)prec; - sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.alpha = 0; - alpha = NULL; adjustA = 0; - color_type = PNG_COLOR_TYPE_GRAY; - - if(nr_comp == 2) - { - has_alpha = 1; sig_bit.alpha = (png_byte)prec; - alpha = image->comps[1].data; - color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - adjustA = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - } - width = (int)image->comps[0].w; - height = (int)image->comps[0].h; - - png_set_IHDR(png, info, (png_uint_32)width, (png_uint_32)height, sig_bit.gray, - color_type, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_set_sBIT(png, info, &sig_bit); - - png_set_gamma(png, 2.2, 1./2.2); - png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL); - /*=============================*/ - png_write_info(png, info); - /*=============================*/ - adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - if(prec < 8) - { - png_set_packing(png); - } - - if(prec > 8) - { - row_buf = (unsigned char*) - malloc((size_t)width * (size_t)nr_comp * sizeof(unsigned short)); - - for(y = 0; y < height; ++y) - { - d = row_buf; - - for(x = 0; x < width; ++x) - { - v = *red + adjustR; ++red; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - - if(has_alpha) - { - v = *alpha++; - if(v > 65535) v = 65535; else if(v < 0) v = 0; - - if(force16) { v = (v<>dshift); } - - *d++ = (unsigned char)(v>>8); *d++ = (unsigned char)v; - } - }/* for(x) */ - png_write_row(png, row_buf); - - } /* for(y) */ - free(row_buf); - } - else /* prec <= 8 */ - { - row_buf = (unsigned char*)calloc((size_t)width, (size_t)nr_comp * 2); - - for(y = 0; y < height; ++y) - { - d = row_buf; - - for(x = 0; x < width; ++x) - { - v = *red + adjustR; ++red; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - - if(has_alpha) - { - v = *alpha + adjustA; ++alpha; - if(v > 255) v = 255; else if(v < 0) v = 0; - - if(force8) { v = (v<>dshift); } - - *d++ = (unsigned char)(v & mask); - } - }/* for(x) */ - - png_write_row(png, row_buf); - - } /* for(y) */ - free(row_buf); - } - } - else - { - fprintf(stderr,"imagetopng: can not create %s\n",write_idf); - goto fin; - } - png_write_end(png, info); - - fails = 0; - -fin: - - if(png) - { - png_destroy_write_struct(&png, &info); - } - fclose(writer); - - if(fails) remove(write_idf); - - return fails; -}/* imagetopng() */ -#endif /* OPJ_HAVE_LIBPNG */ diff --git a/src/bin/jp2/convert.h b/src/bin/jp2/convert.h index ec498eeb..ab1d61a8 100644 --- a/src/bin/jp2/convert.h +++ b/src/bin/jp2/convert.h @@ -65,6 +65,23 @@ typedef struct raw_cparameters { /*@}*/ } raw_cparameters_t; +/* Component precision clipping */ +void clip_component(opj_image_comp_t* component, OPJ_UINT32 precision); +/* Component precision scaling */ +void scale_component(opj_image_comp_t* component, OPJ_UINT32 precision); + +/* planar / interleaved conversions */ +typedef void (* convert_32s_CXPX)(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, OPJ_SIZE_T length); +extern const convert_32s_CXPX convert_32s_CXPX_LUT[5]; +typedef void (* convert_32s_PXCX)(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length, OPJ_INT32 adjust); +extern const convert_32s_PXCX convert_32s_PXCX_LUT[5]; +/* bit depth conversions */ +typedef void (* convert_XXx32s_C1R)(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length); +extern const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9]; /* up to 8bpp */ +typedef void (* convert_32sXXx_C1R)(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length); +extern const convert_32sXXx_C1R convert_32sXXu_C1R_LUT[9]; /* up to 8bpp */ + + /* TGA conversion */ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters); int imagetotga(opj_image_t * image, const char *outfile); @@ -86,7 +103,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters); int imagetopgx(opj_image_t *image, const char *outfile); opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters); -int imagetopnm(opj_image_t *image, const char *outfile); +int imagetopnm(opj_image_t *image, const char *outfile, int force_split); /* RAW conversion */ int imagetoraw(opj_image_t * image, const char *outfile); diff --git a/src/bin/jp2/convertbmp.c b/src/bin/jp2/convertbmp.c new file mode 100644 index 00000000..910574b8 --- /dev/null +++ b/src/bin/jp2/convertbmp.c @@ -0,0 +1,978 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 COPYRIGHT OWNER 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. + */ +#include "opj_apps_config.h" + +#include +#include +#include +#include + +#include "openjpeg.h" +#include "convert.h" + +typedef struct { + OPJ_UINT16 bfType; /* 'BM' for Bitmap (19776) */ + OPJ_UINT32 bfSize; /* Size of the file */ + OPJ_UINT16 bfReserved1; /* Reserved : 0 */ + OPJ_UINT16 bfReserved2; /* Reserved : 0 */ + OPJ_UINT32 bfOffBits; /* Offset */ +} OPJ_BITMAPFILEHEADER; + +typedef struct { + OPJ_UINT32 biSize; /* Size of the structure in bytes */ + OPJ_UINT32 biWidth; /* Width of the image in pixels */ + OPJ_UINT32 biHeight; /* Heigth of the image in pixels */ + OPJ_UINT16 biPlanes; /* 1 */ + OPJ_UINT16 biBitCount; /* Number of color bits by pixels */ + OPJ_UINT32 biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ + OPJ_UINT32 biSizeImage; /* Size of the image in bytes */ + OPJ_UINT32 biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ + OPJ_UINT32 biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ + OPJ_UINT32 biClrUsed; /* Number of color used in the image (0: ALL) */ + OPJ_UINT32 biClrImportant; /* Number of important color (0: ALL) */ + OPJ_UINT32 biRedMask; /* Red channel bit mask */ + OPJ_UINT32 biGreenMask; /* Green channel bit mask */ + OPJ_UINT32 biBlueMask; /* Blue channel bit mask */ + OPJ_UINT32 biAlphaMask; /* Alpha channel bit mask */ + OPJ_UINT32 biColorSpaceType; /* Color space type */ + OPJ_UINT8 biColorSpaceEP[36]; /* Color space end points */ + OPJ_UINT32 biRedGamma; /* Red channel gamma */ + OPJ_UINT32 biGreenGamma; /* Green channel gamma */ + OPJ_UINT32 biBlueGamma; /* Blue channel gamma */ + OPJ_UINT32 biIntent; /* Intent */ + OPJ_UINT32 biIccProfileData; /* ICC profile data */ + OPJ_UINT32 biIccProfileSize; /* ICC profile size */ + OPJ_UINT32 biReserved; /* Reserved */ +} OPJ_BITMAPINFOHEADER; + +static void opj_applyLUT8u_8u32s_C1R( + OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, + OPJ_INT32* pDst, OPJ_INT32 dstStride, + OPJ_UINT8 const* pLUT, + OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 y; + + for (y = height; y != 0U; --y) { + OPJ_UINT32 x; + + for(x = 0; x < width; x++) + { + pDst[x] = (OPJ_INT32)pLUT[pSrc[x]]; + } + pSrc += srcStride; + pDst += dstStride; + } +} + +static void opj_applyLUT8u_8u32s_C1P3R( + OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, + OPJ_INT32* const* pDst, OPJ_INT32 const* pDstStride, + OPJ_UINT8 const* const* pLUT, + OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 y; + OPJ_INT32* pR = pDst[0]; + OPJ_INT32* pG = pDst[1]; + OPJ_INT32* pB = pDst[2]; + OPJ_UINT8 const* pLUT_R = pLUT[0]; + OPJ_UINT8 const* pLUT_G = pLUT[1]; + OPJ_UINT8 const* pLUT_B = pLUT[2]; + + for (y = height; y != 0U; --y) { + OPJ_UINT32 x; + + for(x = 0; x < width; x++) + { + OPJ_UINT8 idx = pSrc[x]; + pR[x] = (OPJ_INT32)pLUT_R[idx]; + pG[x] = (OPJ_INT32)pLUT_G[idx]; + pB[x] = (OPJ_INT32)pLUT_B[idx]; + } + pSrc += srcStride; + pR += pDstStride[0]; + pG += pDstStride[1]; + pB += pDstStride[2]; + } +} + +static void bmp24toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + + width = image->comps[0].w; + height = image->comps[0].h; + + index = 0; + pSrc = pData + (height - 1U) * stride; + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + image->comps[0].data[index] = (OPJ_INT32)pSrc[3*x+2]; /* R */ + image->comps[1].data[index] = (OPJ_INT32)pSrc[3*x+1]; /* G */ + image->comps[2].data[index] = (OPJ_INT32)pSrc[3*x+0]; /* B */ + index++; + } + pSrc -= stride; + } +} + +static void bmp_mask_get_shift_and_prec(OPJ_UINT32 mask, OPJ_UINT32* shift, OPJ_UINT32* prec) +{ + OPJ_UINT32 l_shift, l_prec; + + l_shift = l_prec = 0U; + + if (mask != 0U) { + while ((mask & 1U) == 0U) { + mask >>= 1; + l_shift++; + } + while (mask & 1U) { + mask >>= 1; + l_prec++; + } + } + *shift = l_shift; *prec = l_prec; +} + +static void bmpmask32toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + OPJ_BOOL hasAlpha = OPJ_FALSE; + OPJ_UINT32 redShift, redPrec; + OPJ_UINT32 greenShift, greenPrec; + OPJ_UINT32 blueShift, bluePrec; + OPJ_UINT32 alphaShift, alphaPrec; + + width = image->comps[0].w; + height = image->comps[0].h; + + hasAlpha = image->numcomps > 3U; + + bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); + bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); + bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); + bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); + + image->comps[0].bpp = redPrec; + image->comps[0].prec = redPrec; + image->comps[1].bpp = greenPrec; + image->comps[1].prec = greenPrec; + image->comps[2].bpp = bluePrec; + image->comps[2].prec = bluePrec; + if (hasAlpha) { + image->comps[3].bpp = alphaPrec; + image->comps[3].prec = alphaPrec; + } + + index = 0; + pSrc = pData + (height - 1U) * stride; + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + OPJ_UINT32 value = 0U; + + value |= ((OPJ_UINT32)pSrc[4*x+0]) << 0; + value |= ((OPJ_UINT32)pSrc[4*x+1]) << 8; + value |= ((OPJ_UINT32)pSrc[4*x+2]) << 16; + value |= ((OPJ_UINT32)pSrc[4*x+3]) << 24; + + image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> redShift); /* R */ + image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> greenShift); /* G */ + image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> blueShift); /* B */ + if (hasAlpha) { + image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> alphaShift); /* A */ + } + index++; + } + pSrc -= stride; + } +} + +static void bmpmask16toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + OPJ_BOOL hasAlpha = OPJ_FALSE; + OPJ_UINT32 redShift, redPrec; + OPJ_UINT32 greenShift, greenPrec; + OPJ_UINT32 blueShift, bluePrec; + OPJ_UINT32 alphaShift, alphaPrec; + + width = image->comps[0].w; + height = image->comps[0].h; + + hasAlpha = image->numcomps > 3U; + + bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); + bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); + bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); + bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); + + image->comps[0].bpp = redPrec; + image->comps[0].prec = redPrec; + image->comps[1].bpp = greenPrec; + image->comps[1].prec = greenPrec; + image->comps[2].bpp = bluePrec; + image->comps[2].prec = bluePrec; + if (hasAlpha) { + image->comps[3].bpp = alphaPrec; + image->comps[3].prec = alphaPrec; + } + + index = 0; + pSrc = pData + (height - 1U) * stride; + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + OPJ_UINT32 value = 0U; + + value |= ((OPJ_UINT32)pSrc[2*x+0]) << 0; + value |= ((OPJ_UINT32)pSrc[2*x+1]) << 8; + + image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> redShift); /* R */ + image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> greenShift); /* G */ + image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> blueShift); /* B */ + if (hasAlpha) { + image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> alphaShift); /* A */ + } + index++; + } + pSrc -= stride; + } +} + +static opj_image_t* bmp8toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT8 const* const* pLUT) +{ + OPJ_UINT32 width, height; + const OPJ_UINT8 *pSrc = NULL; + + width = image->comps[0].w; + height = image->comps[0].h; + + pSrc = pData + (height - 1U) * stride; + if (image->numcomps == 1U) { + opj_applyLUT8u_8u32s_C1R(pSrc, -(OPJ_INT32)stride, image->comps[0].data, (OPJ_INT32)width, pLUT[0], width, height); + } + else { + OPJ_INT32* pDst[3]; + OPJ_INT32 pDstStride[3]; + + pDst[0] = image->comps[0].data; pDst[1] = image->comps[1].data; pDst[2] = image->comps[2].data; + pDstStride[0] = (OPJ_INT32)width; pDstStride[1] = (OPJ_INT32)width; pDstStride[2] = (OPJ_INT32)width; + opj_applyLUT8u_8u32s_C1P3R(pSrc, -(OPJ_INT32)stride, pDst, pDstStride, pLUT, width, height); + } + return image; +} + +static OPJ_BOOL bmp_read_file_header(FILE* IN, OPJ_BITMAPFILEHEADER* header) +{ + header->bfType = (OPJ_UINT16)getc(IN); + header->bfType |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + if (header->bfType != 19778) { + fprintf(stderr,"Error, not a BMP file!\n"); + return OPJ_FALSE; + } + + /* FILE HEADER */ + /* ------------- */ + header->bfSize = (OPJ_UINT32)getc(IN); + header->bfSize |= (OPJ_UINT32)getc(IN) << 8; + header->bfSize |= (OPJ_UINT32)getc(IN) << 16; + header->bfSize |= (OPJ_UINT32)getc(IN) << 24; + + header->bfReserved1 = (OPJ_UINT16)getc(IN); + header->bfReserved1 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->bfReserved2 = (OPJ_UINT16)getc(IN); + header->bfReserved2 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->bfOffBits = (OPJ_UINT32)getc(IN); + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 8; + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 16; + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 24; + return OPJ_TRUE; +} +static OPJ_BOOL bmp_read_info_header(FILE* IN, OPJ_BITMAPINFOHEADER* header) +{ + memset(header, 0, sizeof(*header)); + /* INFO HEADER */ + /* ------------- */ + header->biSize = (OPJ_UINT32)getc(IN); + header->biSize |= (OPJ_UINT32)getc(IN) << 8; + header->biSize |= (OPJ_UINT32)getc(IN) << 16; + header->biSize |= (OPJ_UINT32)getc(IN) << 24; + + switch (header->biSize) { + case 12U: /* BITMAPCOREHEADER */ + case 40U: /* BITMAPINFOHEADER */ + case 52U: /* BITMAPV2INFOHEADER */ + case 56U: /* BITMAPV3INFOHEADER */ + case 108U: /* BITMAPV4HEADER */ + case 124U: /* BITMAPV5HEADER */ + break; + default: + fprintf(stderr,"Error, unknown BMP header size %d\n", header->biSize); + return OPJ_FALSE; + } + + header->biWidth = (OPJ_UINT32)getc(IN); + header->biWidth |= (OPJ_UINT32)getc(IN) << 8; + header->biWidth |= (OPJ_UINT32)getc(IN) << 16; + header->biWidth |= (OPJ_UINT32)getc(IN) << 24; + + header->biHeight = (OPJ_UINT32)getc(IN); + header->biHeight |= (OPJ_UINT32)getc(IN) << 8; + header->biHeight |= (OPJ_UINT32)getc(IN) << 16; + header->biHeight |= (OPJ_UINT32)getc(IN) << 24; + + header->biPlanes = (OPJ_UINT16)getc(IN); + header->biPlanes |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->biBitCount = (OPJ_UINT16)getc(IN); + header->biBitCount |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + if(header->biSize >= 40U) { + header->biCompression = (OPJ_UINT32)getc(IN); + header->biCompression |= (OPJ_UINT32)getc(IN) << 8; + header->biCompression |= (OPJ_UINT32)getc(IN) << 16; + header->biCompression |= (OPJ_UINT32)getc(IN) << 24; + + header->biSizeImage = (OPJ_UINT32)getc(IN); + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 8; + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 16; + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 24; + + header->biXpelsPerMeter = (OPJ_UINT32)getc(IN); + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; + + header->biYpelsPerMeter = (OPJ_UINT32)getc(IN); + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; + + header->biClrUsed = (OPJ_UINT32)getc(IN); + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 8; + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 16; + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 24; + + header->biClrImportant = (OPJ_UINT32)getc(IN); + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 8; + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 16; + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 24; + } + + if(header->biSize >= 56U) { + header->biRedMask = (OPJ_UINT32)getc(IN); + header->biRedMask |= (OPJ_UINT32)getc(IN) << 8; + header->biRedMask |= (OPJ_UINT32)getc(IN) << 16; + header->biRedMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biGreenMask = (OPJ_UINT32)getc(IN); + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 8; + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 16; + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biBlueMask = (OPJ_UINT32)getc(IN); + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 8; + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 16; + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biAlphaMask = (OPJ_UINT32)getc(IN); + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 8; + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 16; + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 24; + } + + if(header->biSize >= 108U) { + header->biColorSpaceType = (OPJ_UINT32)getc(IN); + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 8; + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 16; + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 24; + + if (fread(&(header->biColorSpaceEP), 1U, sizeof(header->biColorSpaceEP), IN) != sizeof(header->biColorSpaceEP)) { + fprintf(stderr,"Error, can't read BMP header\n"); + return OPJ_FALSE; + } + + header->biRedGamma = (OPJ_UINT32)getc(IN); + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 24; + + header->biGreenGamma = (OPJ_UINT32)getc(IN); + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 24; + + header->biBlueGamma = (OPJ_UINT32)getc(IN); + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 24; + } + + if(header->biSize >= 124U) { + header->biIntent = (OPJ_UINT32)getc(IN); + header->biIntent |= (OPJ_UINT32)getc(IN) << 8; + header->biIntent |= (OPJ_UINT32)getc(IN) << 16; + header->biIntent |= (OPJ_UINT32)getc(IN) << 24; + + header->biIccProfileData = (OPJ_UINT32)getc(IN); + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 8; + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 16; + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 24; + + header->biIccProfileSize = (OPJ_UINT32)getc(IN); + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 8; + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 16; + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 24; + + header->biReserved = (OPJ_UINT32)getc(IN); + header->biReserved |= (OPJ_UINT32)getc(IN) << 8; + header->biReserved |= (OPJ_UINT32)getc(IN) << 16; + header->biReserved |= (OPJ_UINT32)getc(IN) << 24; + } + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_raw_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_ARG_NOT_USED(width); + + if ( fread(pData, sizeof(OPJ_UINT8), stride * height, IN) != (stride * height) ) + { + fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); + return OPJ_FALSE; + } + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 x, y; + OPJ_UINT8 *pix; + const OPJ_UINT8 *beyond; + + beyond = pData + stride * height; + pix = pData; + + x = y = 0U; + while (y < height) + { + int c = getc(IN); + + if (c) { + int j; + OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); + + for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + *pix = c1; + } + } + else { + c = getc(IN); + if (c == 0x00) { /* EOL */ + x = 0; + ++y; + pix = pData + y * stride + x; + } + else if (c == 0x01) { /* EOP */ + break; + } + else if (c == 0x02) { /* MOVE by dxdy */ + c = getc(IN); + x += (OPJ_UINT32)c; + c = getc(IN); + y += (OPJ_UINT32)c; + pix = pData + y * stride + x; + } + else /* 03 .. 255 */ + { + int j; + for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) + { + OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); + *pix = c1; + } + if ((OPJ_UINT32)c & 1U) { /* skip padding byte */ + getc(IN); + } + } + } + }/* while() */ + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_rle4_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 x, y; + OPJ_UINT8 *pix; + const OPJ_UINT8 *beyond; + + beyond = pData + stride * height; + pix = pData; + x = y = 0U; + while(y < height) + { + int c = getc(IN); + if(c == EOF) break; + + if(c) {/* encoded mode */ + int j; + OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); + + for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + *pix = (OPJ_UINT8)((j&1) ? (c1 & 0x0fU) : ((c1>>4)&0x0fU)); + } + } + else { /* absolute mode */ + c = getc(IN); + if(c == EOF) break; + + if(c == 0x00) { /* EOL */ + x = 0; y++; pix = pData + y * stride; + } + else if(c == 0x01) { /* EOP */ + break; + } + else if(c == 0x02) { /* MOVE by dxdy */ + c = getc(IN); x += (OPJ_UINT32)c; + c = getc(IN); y += (OPJ_UINT32)c; + pix = pData + y * stride + x; + } + else { /* 03 .. 255 : absolute mode */ + int j; + OPJ_UINT8 c1 = 0U; + + for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + if((j&1) == 0) { + c1 = (OPJ_UINT8)getc(IN); + } + *pix = (OPJ_UINT8)((j&1) ? (c1 & 0x0fU) : ((c1>>4)&0x0fU)); + } + if(((c&3) == 1) || ((c&3) == 2)) { /* skip padding byte */ + getc(IN); + } + } + } + } /* while(y < height) */ + return OPJ_TRUE; +} + +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) +{ + opj_image_cmptparm_t cmptparm[4]; /* maximum of 4 components */ + OPJ_UINT8 lut_R[256], lut_G[256], lut_B[256]; + OPJ_UINT8 const* pLUT[3]; + opj_image_t * image = NULL; + FILE *IN; + OPJ_BITMAPFILEHEADER File_h; + OPJ_BITMAPINFOHEADER Info_h; + OPJ_UINT32 i, palette_len, numcmpts = 1U; + OPJ_BOOL l_result = OPJ_FALSE; + OPJ_UINT8* pData = NULL; + OPJ_UINT32 stride; + + pLUT[0] = lut_R; pLUT[1] = lut_G; pLUT[2] = lut_B; + + IN = fopen(filename, "rb"); + if (!IN) + { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return NULL; + } + + if (!bmp_read_file_header(IN, &File_h)) { + fclose(IN); + return NULL; + } + if (!bmp_read_info_header(IN, &Info_h)) { + fclose(IN); + return NULL; + } + + /* Load palette */ + if (Info_h.biBitCount <= 8U) + { + memset(&lut_R[0], 0, sizeof(lut_R)); + memset(&lut_G[0], 0, sizeof(lut_G)); + memset(&lut_B[0], 0, sizeof(lut_B)); + + palette_len = Info_h.biClrUsed; + if((palette_len == 0U) && (Info_h.biBitCount <= 8U)) { + palette_len = (1U << Info_h.biBitCount); + } + if (palette_len > 256U) { + palette_len = 256U; + } + if (palette_len > 0U) { + OPJ_UINT8 has_color = 0U; + for (i = 0U; i < palette_len; i++) { + lut_B[i] = (OPJ_UINT8)getc(IN); + lut_G[i] = (OPJ_UINT8)getc(IN); + lut_R[i] = (OPJ_UINT8)getc(IN); + (void)getc(IN); /* padding */ + has_color |= (lut_B[i] ^ lut_G[i]) | (lut_G[i] ^ lut_R[i]); + } + if(has_color) { + numcmpts = 3U; + } + } + } else { + numcmpts = 3U; + if ((Info_h.biCompression == 3) && (Info_h.biAlphaMask != 0U)) { + numcmpts++; + } + } + + stride = ((Info_h.biWidth * Info_h.biBitCount + 31U) / 32U) * 4U; /* rows are aligned on 32bits */ + if (Info_h.biBitCount == 4 && Info_h.biCompression == 2) { /* RLE 4 gets decoded as 8 bits data for now... */ + stride = ((Info_h.biWidth * 8U + 31U) / 32U) * 4U; + } + pData = (OPJ_UINT8 *) calloc(1, stride * Info_h.biHeight * sizeof(OPJ_UINT8)); + if (pData == NULL) { + fclose(IN); + return NULL; + } + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, (long)File_h.bfOffBits, SEEK_SET); + + switch (Info_h.biCompression) { + case 0: + case 3: + /* read raw data */ + l_result = bmp_read_raw_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); + break; + case 1: + /* read rle8 data */ + l_result = bmp_read_rle8_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); + break; + case 2: + /* read rle4 data */ + l_result = bmp_read_rle4_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); + break; + default: + fprintf(stderr, "Unsupported BMP compression\n"); + l_result = OPJ_FALSE; + break; + } + if (!l_result) { + free(pData); + fclose(IN); + return NULL; + } + + /* create the image */ + memset(&cmptparm[0], 0, sizeof(cmptparm)); + for(i = 0; i < 4U; i++) + { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)parameters->subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)parameters->subsampling_dy; + cmptparm[i].w = Info_h.biWidth; + cmptparm[i].h = Info_h.biHeight; + } + + image = opj_image_create(numcmpts, &cmptparm[0], (numcmpts == 1U) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB); + if(!image) { + fclose(IN); + free(pData); + return NULL; + } + if (numcmpts == 4U) { + image->comps[3].alpha = 1; + } + + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = image->x0 + (Info_h.biWidth - 1U) * (OPJ_UINT32)parameters->subsampling_dx + 1U; + image->y1 = image->y0 + (Info_h.biHeight - 1U) * (OPJ_UINT32)parameters->subsampling_dy + 1U; + + /* Read the data */ + if (Info_h.biBitCount == 24 && Info_h.biCompression == 0) { /*RGB */ + bmp24toimage(pData, stride, image); + } + else if (Info_h.biBitCount == 8 && Info_h.biCompression == 0) { /* RGB 8bpp Indexed */ + bmp8toimage(pData, stride, image, pLUT); + } + else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { /*RLE8*/ + bmp8toimage(pData, stride, image, pLUT); + } + else if (Info_h.biBitCount == 4 && Info_h.biCompression == 2) { /*RLE4*/ + bmp8toimage(pData, stride, image, pLUT); /* RLE 4 gets decoded as 8 bits data for now */ + } + else if (Info_h.biBitCount == 32 && Info_h.biCompression == 0) { /* RGBX */ + bmpmask32toimage(pData, stride, image, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, 0x00000000U); + } + else if (Info_h.biBitCount == 32 && Info_h.biCompression == 3) { /* bitmask */ + bmpmask32toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, Info_h.biBlueMask, Info_h.biAlphaMask); + } + else if (Info_h.biBitCount == 16 && Info_h.biCompression == 0) { /* RGBX */ + bmpmask16toimage(pData, stride, image, 0x7C00U, 0x03E0U, 0x001FU, 0x0000U); + } + else if (Info_h.biBitCount == 16 && Info_h.biCompression == 3) { /* bitmask */ + if ((Info_h.biRedMask == 0U) && (Info_h.biGreenMask == 0U) && (Info_h.biBlueMask == 0U)) { + Info_h.biRedMask = 0xF800U; + Info_h.biGreenMask = 0x07E0U; + Info_h.biBlueMask = 0x001FU; + } + bmpmask16toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, Info_h.biBlueMask, Info_h.biAlphaMask); + } + else { + opj_image_destroy(image); + image = NULL; + fprintf(stderr, "Other system than 24 bits/pixels or 8 bits (no RLE coding) is not yet implemented [%d]\n", Info_h.biBitCount); + } + free(pData); + fclose(IN); + return image; +} + +int imagetobmp(opj_image_t * image, const char *outfile) { + int w, h; + int i, pad; + FILE *fdest = NULL; + int adjustR, adjustG, adjustB; + + if (image->comps[0].prec < 8) { + fprintf(stderr, "Unsupported number of components: %d\n", image->comps[0].prec); + return 1; + } + if (image->numcomps >= 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> -->> + 24 bits color + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = (int)image->comps[0].w; + h = (int)image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (OPJ_UINT8) (h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff,((54) >> 16) & 0xff, ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) ((w) & 0xff), + (OPJ_UINT8) ((w) >> 8) & 0xff, + (OPJ_UINT8) ((w) >> 16) & 0xff, + (OPJ_UINT8) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) ((h) & 0xff), + (OPJ_UINT8) ((h) >> 8) & 0xff, + (OPJ_UINT8) ((h) >> 16) & 0xff, + (OPJ_UINT8) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) (3 * h * w + 3 * h * (w % 2)) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8) ((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = (int)image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + } + else + adjustR = 0; + if (image->comps[1].prec > 8) { + adjustG = (int)image->comps[1].prec - 8; + printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); + } + else + adjustG = 0; + if (image->comps[2].prec > 8) { + adjustB = (int)image->comps[2].prec - 8; + printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); + } + else + adjustB = 0; + + for (i = 0; i < w * h; i++) { + OPJ_UINT8 rc, gc, bc; + int r, g, b; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + r = ((r >> adjustR)+((r >> (adjustR-1))%2)); + if(r > 255) r = 255; else if(r < 0) r = 0; + rc = (OPJ_UINT8)r; + + g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + g = ((g >> adjustG)+((g >> (adjustG-1))%2)); + if(g > 255) g = 255; else if(g < 0) g = 0; + gc = (OPJ_UINT8)g; + + b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + b = ((b >> adjustB)+((b >> (adjustB-1))%2)); + if(b > 255) b = 255; else if(b < 0) b = 0; + bc = (OPJ_UINT8)b; + + fprintf(fdest, "%c%c%c", bc, gc, rc); + + if ((i + 1) % w == 0) { + for (pad = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } else { /* Gray-scale */ + + /* -->> -->> -->> -->> + 8 bits non code (Gray scale) + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + w = (int)image->comps[0].w; + h = (int)image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) (h * w + 54 + 1024 + h * (w % 2)) & 0xff, + (OPJ_UINT8) ((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8) ((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8) ((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, + ((54 + 1024) >> 16) & 0xff, + ((54 + 1024) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) ((w) & 0xff), + (OPJ_UINT8) ((w) >> 8) & 0xff, + (OPJ_UINT8) ((w) >> 16) & 0xff, + (OPJ_UINT8) ((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) ((h) & 0xff), + (OPJ_UINT8) ((h) >> 8) & 0xff, + (OPJ_UINT8) ((h) >> 16) & 0xff, + (OPJ_UINT8) ((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8) (h * w + h * (w % 2)) & 0xff, + (OPJ_UINT8) ((h * w + h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8) ((h * w + h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8) ((h * w + h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = (int)image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); + }else + adjustR = 0; + + for (i = 0; i < 256; i++) { + fprintf(fdest, "%c%c%c%c", i, i, i, 0); + } + + for (i = 0; i < w * h; i++) { + int r; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + r = ((r >> adjustR)+((r >> (adjustR-1))%2)); + if(r > 255) r = 255; else if(r < 0) r = 0; + + fprintf(fdest, "%c", (OPJ_UINT8)r); + + if ((i + 1) % w == 0) { + for (pad = w % 4 ? 4 - w % 4 : 0; pad > 0; pad--) /* ADD */ + fprintf(fdest, "%c", 0); + } + } + fclose(fdest); + } + + return 0; +} diff --git a/src/bin/jp2/convertpng.c b/src/bin/jp2/convertpng.c new file mode 100644 index 00000000..8d117412 --- /dev/null +++ b/src/bin/jp2/convertpng.c @@ -0,0 +1,492 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 COPYRIGHT OWNER 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. + */ +#include "opj_apps_config.h" + +#include +#include +#include +#include + +#include +#include + +#include "openjpeg.h" +#include "convert.h" + +#define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a" +#define MAGIC_SIZE 8 +/* PNG allows bits per sample: 1, 2, 4, 8, 16 */ + + +static void convert_16u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + OPJ_INT32 val0 = *pSrc++; + OPJ_INT32 val1 = *pSrc++; + pDst[i] = val0 << 8 | val1; + } +} + +opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) +{ + png_structp png = NULL; + png_infop info = NULL; + double gamma; + int bit_depth, interlace_type,compression_type, filter_type; + OPJ_UINT32 i; + png_uint_32 width, height = 0U; + int color_type; + FILE *reader = NULL; + OPJ_BYTE** rows = NULL; + OPJ_INT32* row32s = NULL; + /* j2k: */ + opj_image_t *image = NULL; + opj_image_cmptparm_t cmptparm[4]; + OPJ_UINT32 nr_comp; + OPJ_BYTE sigbuf[8]; + convert_XXx32s_C1R cvtXXTo32s = NULL; + convert_32s_CXPX cvtCxToPx = NULL; + OPJ_INT32* planes[4]; + + if((reader = fopen(read_idf, "rb")) == NULL) + { + fprintf(stderr,"pngtoimage: can not open %s\n",read_idf); + return NULL; + } + + if(fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE + || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0) + { + fprintf(stderr,"pngtoimage: %s is no valid PNG file\n",read_idf); + goto fin; + } + + if((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) + goto fin; + if((info = png_create_info_struct(png)) == NULL) + goto fin; + + if(setjmp(png_jmpbuf(png))) + goto fin; + + png_init_io(png, reader); + png_set_sig_bytes(png, MAGIC_SIZE); + + png_read_info(png, info); + + if(png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type) == 0) + goto fin; + + /* png_set_expand(): + * 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. + */ + if(color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_expand(png); + } + + if(png_get_valid(png, info, PNG_INFO_tRNS)) { + png_set_expand(png); + } + /* We might wan't to expand background */ + /* + if(png_get_valid(png, info, PNG_INFO_bKGD)) { + png_color_16p bgnd; + png_get_bKGD(png, info, &bgnd); + png_set_background(png, bgnd, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + } + */ + + if( !png_get_gAMA(png, info, &gamma)) + gamma = 1.0; + + /* we're not displaying but converting, screen gamma == 1.0 */ + png_set_gamma(png, 1.0, gamma); + + png_read_update_info(png, info); + + color_type = png_get_color_type(png, info); + + switch (color_type) { + case PNG_COLOR_TYPE_GRAY: + nr_comp = 1; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + nr_comp = 2; + break; + case PNG_COLOR_TYPE_RGB: + nr_comp = 3; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + nr_comp = 4; + break; + default: + fprintf(stderr,"pngtoimage: colortype %d is not supported\n", color_type); + goto fin; + } + cvtCxToPx = convert_32s_CXPX_LUT[nr_comp]; + bit_depth = png_get_bit_depth(png, info); + + switch (bit_depth) { + case 1: + case 2: + case 4: + case 8: + cvtXXTo32s = convert_XXu32s_C1R_LUT[bit_depth]; + break; + case 16: /* 16 bpp is specific to PNG */ + cvtXXTo32s = convert_16u32s_C1R; + break; + default: + fprintf(stderr,"pngtoimage: bit depth %d is not supported\n", bit_depth); + goto fin; + } + + + rows = (OPJ_BYTE**)calloc(height+1, sizeof(OPJ_BYTE*)); + for(i = 0; i < height; ++i) + rows[i] = (OPJ_BYTE*)malloc(png_get_rowbytes(png,info)); + + png_read_image(png, rows); + + /* Create image */ + memset(cmptparm, 0, sizeof(cmptparm)); + for(i = 0; i < nr_comp; ++i) + { + cmptparm[i].prec = (OPJ_UINT32)bit_depth; + /* bits_per_pixel: 8 or 16 */ + cmptparm[i].bpp = (OPJ_UINT32)bit_depth; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)params->subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)params->subsampling_dy; + cmptparm[i].w = (OPJ_UINT32)width; + cmptparm[i].h = (OPJ_UINT32)height; + } + + image = opj_image_create(nr_comp, &cmptparm[0], (nr_comp > 2U) ? OPJ_CLRSPC_SRGB : OPJ_CLRSPC_GRAY); + if(image == NULL) goto fin; + image->x0 = (OPJ_UINT32)params->image_offset_x0; + image->y0 = (OPJ_UINT32)params->image_offset_y0; + image->x1 = (OPJ_UINT32)(image->x0 + (width - 1) * (OPJ_UINT32)params->subsampling_dx + 1 + image->x0); + image->y1 = (OPJ_UINT32)(image->y0 + (height - 1) * (OPJ_UINT32)params->subsampling_dy + 1 + image->y0); + + row32s = (OPJ_INT32 *)malloc((size_t)width * nr_comp * sizeof(OPJ_INT32)); + if(row32s == NULL) goto fin; + + /* Set alpha channel */ + image->comps[nr_comp-1U].alpha = 1U - (nr_comp & 1U); + + for(i = 0; i < nr_comp; i++) + { + planes[i] = image->comps[i].data; + } + + for(i = 0; i < height; ++i) + { + cvtXXTo32s(rows[i], row32s, (OPJ_SIZE_T)width * nr_comp); + cvtCxToPx(row32s, planes, width); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } +fin: + if(rows) + { + for(i = 0; i < height; ++i) + free(rows[i]); + free(rows); + } + if (row32s) { + free(row32s); + } + if(png) + png_destroy_read_struct(&png, &info, NULL); + + fclose(reader); + + return image; + +}/* pngtoimage() */ + + +static void convert_32s16u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + OPJ_UINT32 val = (OPJ_UINT32)pSrc[i]; + *pDst++ = (OPJ_BYTE)(val >> 8); + *pDst++ = (OPJ_BYTE)val; + } +} +int imagetopng(opj_image_t * image, const char *write_idf) +{ + FILE * volatile writer = NULL; + png_structp png = NULL; + png_infop info = NULL; + png_bytep volatile row_buf = NULL; + int nr_comp, color_type; + volatile int prec; + png_color_8 sig_bit; + OPJ_INT32 const* planes[4]; + int i; + OPJ_INT32* volatile buffer32s = NULL; + + volatile int fails = 1; + + memset(&sig_bit, 0, sizeof(sig_bit)); + prec = (int)image->comps[0].prec; + planes[0] = image->comps[0].data; + nr_comp = (int)image->numcomps; + + if (nr_comp > 4) { + nr_comp = 4; + } + for (i = 1; i < nr_comp; ++i) { + if (image->comps[0].dx != image->comps[i].dx) { + break; + } + if (image->comps[0].dy != image->comps[i].dy) { + break; + } + if (image->comps[0].prec != image->comps[i].prec) { + break; + } + if (image->comps[0].sgnd != image->comps[i].sgnd) { + break; + } + planes[i] = image->comps[i].data; + } + if (i != nr_comp) { + fprintf(stderr,"imagetopng: All components shall have the same subsampling, same bit depth, same sign.\n"); + fprintf(stderr,"\tAborting\n"); + return 1; + } + for (i = 0; i < nr_comp; ++i) { + clip_component(&(image->comps[i]), image->comps[0].prec); + } + if(prec > 8 && prec < 16) + { + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), 16); + } + prec = 16; + } + else if(prec < 8 && nr_comp > 1)/* GRAY_ALPHA, RGB, RGB_ALPHA */ + { + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), 8); + } + prec = 8; + } else if((prec > 1) && (prec < 8) && ((prec == 6) || ((prec & 1)==1))) { /* GRAY with non native precision */ + if ((prec == 5) || (prec == 6)) { + prec = 8; + } else { + prec++; + } + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), (OPJ_UINT32)prec); + } + } + + if(prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) + { + fprintf(stderr,"imagetopng: can not create %s\n\twrong bit_depth %d\n", write_idf, prec); + return fails; + } + + writer = fopen(write_idf, "wb"); + + if(writer == NULL) return fails; + + /* 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 = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ + + if(png == NULL) goto fin; + + /* Allocate/initialize the image information data. REQUIRED + */ + info = png_create_info_struct(png); + + if(info == NULL) goto fin; + + /* Set error handling. REQUIRED if you are not supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if(setjmp(png_jmpbuf(png))) goto fin; + + /* I/O initialization functions is REQUIRED + */ + png_init_io(png, writer); + + /* 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 + * + * ERRORS: + * + * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8 + * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8 + * + */ + png_set_compression_level(png, Z_BEST_COMPRESSION); + + if(nr_comp >= 3) /* RGB(A) */ + { + color_type = PNG_COLOR_TYPE_RGB; + sig_bit.red = sig_bit.green = sig_bit.blue = (png_byte)prec; + } + else /* GRAY(A) */ + { + color_type = PNG_COLOR_TYPE_GRAY; + sig_bit.gray = (png_byte)prec; + } + if((nr_comp & 1) == 0) /* ALPHA */ + { + color_type |= PNG_COLOR_MASK_ALPHA; + sig_bit.alpha = (png_byte)prec; + } + + png_set_IHDR(png, info, image->comps[0].w, image->comps[0].h, prec, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_sBIT(png, info, &sig_bit); + /* png_set_gamma(png, 2.2, 1./2.2); */ + /* png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL); */ + png_write_info(png, info); + + /* setup conversion */ + { + OPJ_SIZE_T rowStride; + png_size_t png_row_size; + + png_row_size = png_get_rowbytes(png, info); + rowStride = ((OPJ_SIZE_T)image->comps[0].w * (OPJ_SIZE_T)nr_comp * (OPJ_SIZE_T)prec + 7U) / 8U; + if (rowStride != (OPJ_SIZE_T)png_row_size) { + fprintf(stderr, "Invalid PNG row size\n"); + goto fin; + } + row_buf = (png_bytep)malloc(png_row_size); + if (row_buf == NULL) { + fprintf(stderr, "Can't allocate memory for PNG row\n"); + goto fin; + } + buffer32s = (OPJ_INT32*)malloc((OPJ_SIZE_T)image->comps[0].w * (OPJ_SIZE_T)nr_comp * sizeof(OPJ_INT32)); + if (buffer32s == NULL) { + fprintf(stderr, "Can't allocate memory for interleaved 32s row\n"); + goto fin; + } + } + + /* convert */ + { + OPJ_SIZE_T width= image->comps[0].w; + OPJ_UINT32 y; + convert_32s_PXCX cvtPxToCx = convert_32s_PXCX_LUT[nr_comp]; + convert_32sXXx_C1R cvt32sToPack = NULL; + OPJ_INT32 adjust = image->comps[0].sgnd ? 1 << (prec - 1) : 0; + png_bytep row_buf_cpy = row_buf; + OPJ_INT32* buffer32s_cpy = buffer32s; + + switch (prec) { + case 1: + case 2: + case 4: + case 8: + cvt32sToPack = convert_32sXXu_C1R_LUT[prec]; + break; + case 16: + cvt32sToPack = convert_32s16u_C1R; + break; + default: + /* never here */ + break; + } + + for(y = 0; y < image->comps[0].h; ++y) + { + cvtPxToCx(planes, buffer32s_cpy, width, adjust); + cvt32sToPack(buffer32s_cpy, row_buf_cpy, width * (OPJ_SIZE_T)nr_comp); + png_write_row(png, row_buf_cpy); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } + } + + png_write_end(png, info); + + fails = 0; + +fin: + if(png) { + png_destroy_write_struct(&png, &info); + } + if(row_buf) { + free(row_buf); + } + if(buffer32s) { + free(buffer32s); + } + fclose(writer); + + if(fails) (void)remove(write_idf); /* ignore return value */ + + return fails; +}/* imagetopng() */ diff --git a/src/bin/jp2/converttif.c b/src/bin/jp2/converttif.c new file mode 100644 index 00000000..dbda0741 --- /dev/null +++ b/src/bin/jp2/converttif.c @@ -0,0 +1,644 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 COPYRIGHT OWNER 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. + */ +#include "opj_apps_config.h" + +#include +#include +#include +#include + +#ifndef OPJ_HAVE_LIBTIFF +# error OPJ_HAVE_LIBTIFF_NOT_DEFINED +#endif /* OPJ_HAVE_LIBTIFF */ + +#include +#include "openjpeg.h" +#include "convert.h" + +/* -->> -->> -->> -->> + + TIFF IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +static void tif_32sto10u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i+2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i+3]; + + *pDst++ = (OPJ_BYTE)(src0 >> 2); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3U) << 6) | (src1 >> 4)); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 6)); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3FU) << 2) | (src3 >> 8)); + *pDst++ = (OPJ_BYTE)(src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i+1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i+2]; + } + } + *pDst++ = (OPJ_BYTE)(src0 >> 2); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3U) << 6) | (src1 >> 4)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 6)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(((src2 & 0x3FU) << 2)); + } + } + } +} +static void tif_32sto12u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i+=2U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + + *pDst++ = (OPJ_BYTE)(src0 >> 4); + *pDst++ = (OPJ_BYTE)(((src0 & 0xFU) << 4) | (src1 >> 8)); + *pDst++ = (OPJ_BYTE)(src1); + } + + if (length & 1U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + *pDst++ = (OPJ_BYTE)(src0 >> 4); + *pDst++ = (OPJ_BYTE)(((src0 & 0xFU) << 4)); + } +} +static void tif_32sto14u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i+1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i+2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i+3]; + + *pDst++ = (OPJ_BYTE)(src0 >> 6); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3FU) << 2) | (src1 >> 12)); + *pDst++ = (OPJ_BYTE)(src1 >> 4); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 10)); + *pDst++ = (OPJ_BYTE)(src2 >> 2); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6) | (src3 >> 8)); + *pDst++ = (OPJ_BYTE)(src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i+0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i+1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i+2]; + } + } + *pDst++ = (OPJ_BYTE)(src0 >> 6); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3FU) << 2) | (src1 >> 12)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(src1 >> 4); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 10)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(src2 >> 2); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6)); + } + } + } +} +static void tif_32sto16u(const OPJ_INT32* pSrc, OPJ_UINT16* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; ++i) { + pDst[i] = (OPJ_UINT16)pSrc[i]; + } +} + +int imagetotif(opj_image_t * image, const char *outfile) +{ + int width, height; + int bps,adjust, sgnd; + int tiPhoto; + TIFF *tif; + tdata_t buf; + tsize_t strip_size; + OPJ_UINT32 i, numcomps; + OPJ_SIZE_T rowStride; + OPJ_INT32* buffer32s = NULL; + OPJ_INT32 const* planes[4]; + convert_32s_PXCX cvtPxToCx = NULL; + convert_32sXXx_C1R cvt32sToTif = NULL; + + bps = (int)image->comps[0].prec; + planes[0] = image->comps[0].data; + + numcomps = image->numcomps; + + if (image->color_space == OPJ_CLRSPC_CMYK) { + if (numcomps < 4U) { + fprintf(stderr,"imagetotif: CMYK images shall be composed of at least 4 planes.\n"); + fprintf(stderr,"\tAborting\n"); + return 1; + } + tiPhoto = PHOTOMETRIC_SEPARATED; + if (numcomps > 4U) { + numcomps = 4U; /* Alpha not supported */ + } + } + else if (numcomps > 2U) { + tiPhoto = PHOTOMETRIC_RGB; + if (numcomps > 4U) { + numcomps = 4U; + } + } else { + tiPhoto = PHOTOMETRIC_MINISBLACK; + } + for (i = 1U; i < numcomps; ++i) { + if (image->comps[0].dx != image->comps[i].dx) { + break; + } + if (image->comps[0].dy != image->comps[i].dy) { + break; + } + if (image->comps[0].prec != image->comps[i].prec) { + break; + } + if (image->comps[0].sgnd != image->comps[i].sgnd) { + break; + } + planes[i] = image->comps[i].data; + } + if (i != numcomps) { + fprintf(stderr,"imagetotif: All components shall have the same subsampling, same bit depth.\n"); + fprintf(stderr,"\tAborting\n"); + return 1; + } + + if((bps > 16) || ((bps != 1) && (bps & 1))) bps = 0; + if(bps == 0) + { + fprintf(stderr,"imagetotif: Bits=%d, Only 1, 2, 4, 6, 8, 10, 12, 14 and 16 bits implemented\n",bps); + fprintf(stderr,"\tAborting\n"); + return 1; + } + tif = TIFFOpen(outfile, "wb"); + if (!tif) + { + fprintf(stderr, "imagetotif:failed to open %s for writing\n", outfile); + return 1; + } + for (i = 0U; i < numcomps; ++i) { + clip_component(&(image->comps[i]), image->comps[0].prec); + } + cvtPxToCx = convert_32s_PXCX_LUT[numcomps]; + switch (bps) { + case 1: + case 2: + case 4: + case 6: + case 8: + cvt32sToTif = convert_32sXXu_C1R_LUT[bps]; + break; + case 10: + cvt32sToTif = tif_32sto10u; + break; + case 12: + cvt32sToTif = tif_32sto12u; + break; + case 14: + cvt32sToTif = tif_32sto14u; + break; + case 16: + cvt32sToTif = (convert_32sXXx_C1R)tif_32sto16u; + break; + default: + /* never here */ + break; + } + sgnd = (int)image->comps[0].sgnd; + adjust = sgnd ? 1 << (image->comps[0].prec - 1) : 0; + width = (int)image->comps[0].w; + height = (int)image->comps[0].h; + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, numcomps); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, tiPhoto); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + strip_size = TIFFStripSize(tif); + rowStride = ((OPJ_SIZE_T)width * numcomps * (OPJ_SIZE_T)bps + 7U) / 8U; + if (rowStride != (OPJ_SIZE_T)strip_size) { + fprintf(stderr, "Invalid TIFF strip size\n"); + TIFFClose(tif); + return 1; + } + buf = _TIFFmalloc(strip_size); + if (buf == NULL) { + TIFFClose(tif); + return 1; + } + buffer32s = (OPJ_INT32 *)malloc((OPJ_SIZE_T)width * numcomps * sizeof(OPJ_INT32)); + if (buffer32s == NULL) { + _TIFFfree(buf); + TIFFClose(tif); + return 1; + } + + for (i = 0; i < image->comps[0].h; ++i) { + cvtPxToCx(planes, buffer32s, (OPJ_SIZE_T)width, adjust); + cvt32sToTif(buffer32s, (OPJ_BYTE *)buf, (OPJ_SIZE_T)width * numcomps); + (void)TIFFWriteEncodedStrip(tif, i, (void*)buf, strip_size); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } + _TIFFfree((void*)buf); + TIFFClose(tif); + free(buffer32s); + + return 0; +}/* imagetotif() */ + +static void tif_10uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + + pDst[i+0] = (OPJ_INT32)((val0 << 2) | (val1 >> 6)); + pDst[i+1] = (OPJ_INT32)(((val1 & 0x3FU) << 4) | (val2 >> 4)); + pDst[i+2] = (OPJ_INT32)(((val2 & 0xFU) << 6) | (val3 >> 2)); + pDst[i+3] = (OPJ_INT32)(((val3 & 0x3U) << 8) | val4); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + length = length & 3U; + pDst[i+0] = (OPJ_INT32)((val0 << 2) | (val1 >> 6)); + + if (length > 1U) { + OPJ_UINT32 val2 = *pSrc++; + pDst[i+1] = (OPJ_INT32)(((val1 & 0x3FU) << 4) | (val2 >> 4)); + if (length > 2U) { + OPJ_UINT32 val3 = *pSrc++; + pDst[i+2] = (OPJ_INT32)(((val2 & 0xFU) << 6) | (val3 >> 2)); + } + } + } +} +static void tif_12uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i+=2U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + + pDst[i+0] = (OPJ_INT32)((val0 << 4) | (val1 >> 4)); + pDst[i+1] = (OPJ_INT32)(((val1 & 0xFU) << 8) | val2); + } + if (length & 1U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + pDst[i+0] = (OPJ_INT32)((val0 << 4) | (val1 >> 4)); + } +} +static void tif_14uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i+=4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + + pDst[i+0] = (OPJ_INT32)((val0 << 6) | (val1 >> 2)); + pDst[i+1] = (OPJ_INT32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4)); + pDst[i+2] = (OPJ_INT32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6)); + pDst[i+3] = (OPJ_INT32)(((val5 & 0x3FU) << 8) | val6); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + length = length & 3U; + pDst[i+0] = (OPJ_INT32)((val0 << 6) | (val1 >> 2)); + + if (length > 1U) { + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + pDst[i+1] = (OPJ_INT32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4)); + if (length > 2U) { + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + pDst[i+2] = (OPJ_INT32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6)); + } + } + } +} + +/* seems that libtiff decodes this to machine endianness */ +static void tif_16uto32s(const OPJ_UINT16* pSrc, OPJ_INT32* pDst, OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + pDst[i] = pSrc[i]; + } +} + +/* + * libtiff/tif_getimage.c : 1,2,4,8,16 bitspersample accepted + * CINEMA : 12 bit precision + */ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + int j, currentPlane, numcomps = 0, w, h; + OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_UNKNOWN; + opj_image_cmptparm_t cmptparm[4]; /* RGBA */ + opj_image_t *image = NULL; + int has_alpha = 0; + unsigned short tiBps, tiPhoto, tiSf, tiSpp, tiPC; + unsigned int tiWidth, tiHeight; + OPJ_BOOL is_cinema = OPJ_IS_CINEMA(parameters->rsiz); + convert_XXx32s_C1R cvtTifTo32s = NULL; + convert_32s_CXPX cvtCxToPx = NULL; + OPJ_INT32* buffer32s = NULL; + OPJ_INT32* planes[4]; + OPJ_SIZE_T rowStride; + + tif = TIFFOpen(filename, "r"); + + if(!tif) + { + fprintf(stderr, "tiftoimage:Failed to open %s for reading\n", filename); + return 0; + } + tiBps = tiPhoto = tiSf = tiSpp = tiPC = 0; + tiWidth = tiHeight = 0; + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &tiWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &tiHeight); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiBps); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &tiSf); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiSpp); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &tiPhoto); + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &tiPC); + w= (int)tiWidth; + h= (int)tiHeight; + + if((tiBps > 16U) || ((tiBps != 1U) && (tiBps & 1U))) { + fprintf(stderr,"tiftoimage: Bits=%d, Only 1, 2, 4, 6, 8, 10, 12, 14 and 16 bits implemented\n",tiBps); + fprintf(stderr,"\tAborting\n"); + TIFFClose(tif); + return NULL; + } + if(tiPhoto != PHOTOMETRIC_MINISBLACK && tiPhoto != PHOTOMETRIC_RGB) { + fprintf(stderr,"tiftoimage: Bad color format %d.\n\tOnly RGB(A) and GRAY(A) has been implemented\n",(int) tiPhoto); + fprintf(stderr,"\tAborting\n"); + TIFFClose(tif); + return NULL; + } + + switch (tiBps) { + case 1: + case 2: + case 4: + case 6: + case 8: + cvtTifTo32s = convert_XXu32s_C1R_LUT[tiBps]; + break; + /* others are specific to TIFF */ + case 10: + cvtTifTo32s = tif_10uto32s; + break; + case 12: + cvtTifTo32s = tif_12uto32s; + break; + case 14: + cvtTifTo32s = tif_14uto32s; + break; + case 16: + cvtTifTo32s = (convert_XXx32s_C1R)tif_16uto32s; + break; + default: + /* never here */ + break; + } + + {/* From: tiff-4.0.x/libtiff/tif_getimage.c : */ + uint16* sampleinfo; + uint16 extrasamples; + + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extrasamples, &sampleinfo); + + if(extrasamples >= 1) + { + switch(sampleinfo[0]) + { + case EXTRASAMPLE_UNSPECIFIED: + /* Workaround for some images without correct info about alpha channel + */ + if(tiSpp > 3) + has_alpha = 1; + break; + + case EXTRASAMPLE_ASSOCALPHA: /* data pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data not pre-multiplied */ + has_alpha = 1; + break; + } + } + else /* extrasamples == 0 */ + if(tiSpp == 4 || tiSpp == 2) has_alpha = 1; + } + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + if ((tiPhoto == PHOTOMETRIC_RGB) && (is_cinema) && (tiBps != 12U)) { + fprintf(stdout,"WARNING:\n" + "Input image bitdepth is %d bits\n" + "TIF conversion has automatically rescaled to 12-bits\n" + "to comply with cinema profiles.\n", + tiBps); + } else { + is_cinema = 0U; + } + + if(tiPhoto == PHOTOMETRIC_RGB) /* RGB(A) */ + { + numcomps = 3 + has_alpha; + color_space = OPJ_CLRSPC_SRGB; + } + else if (tiPhoto == PHOTOMETRIC_MINISBLACK) /* GRAY(A) */ + { + numcomps = 1 + has_alpha; + color_space = OPJ_CLRSPC_GRAY; + } + + cvtCxToPx = convert_32s_CXPX_LUT[numcomps]; + if (tiPC == PLANARCONFIG_SEPARATE) { + cvtCxToPx = convert_32s_CXPX_LUT[1]; /* override */ + tiSpp = 1U; /* consider only one sample per plane */ + } + + for(j = 0; j < numcomps; j++) + { + cmptparm[j].prec = tiBps; + cmptparm[j].bpp = tiBps; + cmptparm[j].dx = (OPJ_UINT32)subsampling_dx; + cmptparm[j].dy = (OPJ_UINT32)subsampling_dy; + cmptparm[j].w = (OPJ_UINT32)w; + cmptparm[j].h = (OPJ_UINT32)h; + } + + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); + if(!image) + { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : + image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; + image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : + image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; + + for(j = 0; j < numcomps; j++) + { + planes[j] = image->comps[j].data; + } + image->comps[numcomps - 1].alpha = (OPJ_UINT16)(1 - (numcomps & 1)); + + strip_size = TIFFStripSize(tif); + + buf = _TIFFmalloc(strip_size); + if (buf == NULL) { + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + rowStride = ((OPJ_SIZE_T)w * tiSpp * tiBps + 7U) / 8U; + buffer32s = (OPJ_INT32 *)malloc((OPJ_SIZE_T)w * tiSpp * sizeof(OPJ_INT32)); + if (buffer32s == NULL) { + _TIFFfree(buf); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + + strip = 0; + currentPlane = 0; + do + { + planes[0] = image->comps[currentPlane].data; /* to manage planar data */ + h= (int)tiHeight; + /* Read the Image components */ + for(; (h > 0) && (strip < TIFFNumberOfStrips(tif)); strip++) + { + const OPJ_UINT8 *dat8; + OPJ_SIZE_T ssize; + + ssize = (OPJ_SIZE_T)TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (const OPJ_UINT8*)buf; + + while (ssize >= rowStride) { + cvtTifTo32s(dat8, buffer32s, (OPJ_SIZE_T)w * tiSpp); + cvtCxToPx(buffer32s, planes, (OPJ_SIZE_T)w); + planes[0] += w; + planes[1] += w; + planes[2] += w; + planes[3] += w; + dat8 += rowStride; + ssize -= rowStride; + h--; + } + } + currentPlane++; + } while ((tiPC == PLANARCONFIG_SEPARATE) && (currentPlane < numcomps)); + + free(buffer32s); + _TIFFfree(buf); + TIFFClose(tif); + + if (is_cinema) { + for (j=0; j < numcomps; ++j) { + scale_component(&(image->comps[j]), 12); + } + + } + return image; + +}/* tiftoimage() */ + diff --git a/src/bin/jp2/opj_compress.c b/src/bin/jp2/opj_compress.c index f0ff3e4d..9d690a56 100644 --- a/src/bin/jp2/opj_compress.c +++ b/src/bin/jp2/opj_compress.c @@ -57,6 +57,9 @@ #define strncasecmp _strnicmp #else #include +#include +#include +#include #endif /* _WIN32 */ #include "opj_apps_config.h" @@ -66,6 +69,7 @@ #include "index.h" #include "format_defs.h" +#include "opj_string.h" typedef struct dircnt{ /** Buffer for holding images read from Directory*/ @@ -388,6 +392,7 @@ static unsigned int get_num_images(char *imgdirpath){ continue; num_images++; } + closedir(dir); return num_images; } @@ -413,6 +418,7 @@ static int load_images(dircnt_t *dirptr, char *imgdirpath){ strcpy(dirptr->filename[i],content->d_name); i++; } + closedir(dir); return 0; } @@ -451,8 +457,10 @@ static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_c if (parameters->decod_format == -1) return 1; sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); - strncpy(parameters->infile, infilename, sizeof(infilename)); - + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { + return 1; + } + /*Set output file*/ strcpy(temp_ofname,get_file_name(image_filename)); while((temp_p = strtok(NULL,".")) != NULL){ @@ -461,7 +469,9 @@ static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_c } if(img_fol->set_out_format==1){ sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); - strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { + return 1; + } } return 0; } @@ -469,7 +479,7 @@ static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_c /* ------------------------------------------------------------------------------------ */ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters, - img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename) { + img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename, size_t indexfilename_size) { OPJ_UINT32 i, j; int totlen, c; opj_option_t long_option[]={ @@ -523,7 +533,9 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param infile); return 1; } - strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + return 1; + } } break; @@ -541,7 +553,9 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param fprintf(stderr, "Unknown output format image %s [only *.j2k, *.j2c or *.jp2]!! \n", outfile); return 1; } - strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfile) != 0) { + return 1; + } } break; @@ -598,7 +612,7 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param char signo; int width,height,bitdepth,ncomp; OPJ_UINT32 len; - OPJ_BOOL raw_signed; + OPJ_BOOL raw_signed = OPJ_FALSE; substr2 = strchr(opj_optarg,'@'); if (substr2 == NULL) { len = (OPJ_UINT32) strlen(opj_optarg); @@ -607,6 +621,9 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param substr2++; /* skip '@' character */ } substr1 = (char*) malloc((len+1)*sizeof(char)); + if (substr1 == NULL) { + return 1; + } memcpy(substr1,opj_optarg,len); substr1[len] = '\0'; if (sscanf(substr1, "%d,%d,%d,%d,%c", &width, &height, &ncomp, &bitdepth, &signo) == 5) { @@ -621,7 +638,7 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param wrong = OPJ_TRUE; } if (!wrong) { - int i; + int compno; int lastdx = 1; int lastdy = 1; raw_cp->rawWidth = width; @@ -630,10 +647,10 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param raw_cp->rawBitDepth = bitdepth; raw_cp->rawSigned = raw_signed; raw_cp->rawComps = (raw_comp_cparameters_t*) malloc(((OPJ_UINT32)(ncomp))*sizeof(raw_comp_cparameters_t)); - for (i = 0; i < ncomp && !wrong; i++) { + for (compno = 0; compno < ncomp && !wrong; compno++) { if (substr2 == NULL) { - raw_cp->rawComps[i].dx = lastdx; - raw_cp->rawComps[i].dy = lastdy; + raw_cp->rawComps[compno].dx = lastdx; + raw_cp->rawComps[compno].dy = lastdy; } else { int dx,dy; sep = strchr(substr2,':'); @@ -641,16 +658,16 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param if (sscanf(substr2, "%dx%d", &dx, &dy) == 2) { lastdx = dx; lastdy = dy; - raw_cp->rawComps[i].dx = dx; - raw_cp->rawComps[i].dy = dy; + raw_cp->rawComps[compno].dx = dx; + raw_cp->rawComps[compno].dy = dy; substr2 = NULL; } else { wrong = OPJ_TRUE; } } else { if (sscanf(substr2, "%dx%d:%s", &dx, &dy, substr2) == 3) { - raw_cp->rawComps[i].dx = dx; - raw_cp->rawComps[i].dy = dy; + raw_cp->rawComps[compno].dx = dx; + raw_cp->rawComps[compno].dy = dy; } else { wrong = OPJ_TRUE; } @@ -658,7 +675,7 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param } } } - if (substr1) free(substr1); + free(substr1); if (wrong) { fprintf(stderr,"\nError: invalid raw image parameters\n"); fprintf(stderr,"Please use the Format option -F:\n"); @@ -699,7 +716,7 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param OPJ_UINT32 numlayers = 0, numresolution = 0, matrix_width = 0; char *s = opj_optarg; - sscanf(s, "%ud", &numlayers); + sscanf(s, "%u", &numlayers); s++; if (numlayers > 9) s++; @@ -804,8 +821,9 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param case 'x': /* creation of index file */ { - char *index = opj_optarg; - strncpy(indexfilename, index, OPJ_PATH_LEN); + if (opj_strcpy_s(indexfilename, indexfilename_size, opj_optarg) != 0) { + return 1; + } /* FIXME ADE INDEX >> */ fprintf(stderr, "[WARNING] Index file generation is currently broken.\n" @@ -871,7 +889,7 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param char *s = opj_optarg; POC = parameters->POC; - while (sscanf(s, "T%ud=%ud,%ud,%ud,%ud,%ud,%4s", &POC[numpocs].tile, + while (sscanf(s, "T%u=%u,%u,%u,%u,%u,%4s", &POC[numpocs].tile, &POC[numpocs].resno0, &POC[numpocs].compno0, &POC[numpocs].layno1, &POC[numpocs].resno1, &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { @@ -1055,9 +1073,16 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param lStrLen = (size_t)ftell(lFile); fseek(lFile,0,SEEK_SET); lMatrix = (char *) malloc(lStrLen + 1); + if (lMatrix == NULL) { + fclose(lFile); + return 1; + } lStrFread = fread(lMatrix, 1, lStrLen, lFile); fclose(lFile); - if( lStrLen != lStrFread ) return 1; + if( lStrLen != lStrFread ) { + free(lMatrix); + return 1; + } lMatrix[lStrLen] = 0; lCurrentPtr = lMatrix; @@ -1077,6 +1102,10 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param lMctComp = lNbComp * lNbComp; lTotalComp = lMctComp + lNbComp; lSpace = (float *) malloc((size_t)lTotalComp * sizeof(float)); + if(lSpace == NULL) { + free(lMatrix); + return 1; + } lCurrentDoublePtr = lSpace; for (i2=0;i2infile[0] == 0) || (parameters->outfile[0] == 0)) { fprintf(stderr, "[ERROR] Required parameters are missing\n" - "Example: %s -i image.j2k -o image.pgm\n",argv[0]); + "Example: %s -i image.pgm -o image.j2k\n",argv[0]); fprintf(stderr, " Help: %s -h\n",argv[0]); return 1; } @@ -1500,6 +1531,14 @@ static int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *param } } + /* If subsampled image is provided, automatically disable MCT */ + if ( ((parameters->decod_format == RAW_DFMT) || (parameters->decod_format == RAWL_DFMT)) + && ( ((raw_cp->rawComp > 1 ) && ((raw_cp->rawComps[1].dx > 1) || (raw_cp->rawComps[1].dy > 1))) + || ((raw_cp->rawComp > 2 ) && ((raw_cp->rawComps[2].dx > 1) || (raw_cp->rawComps[2].dy > 1))) + )) { + parameters->tcp_mct = 0; + } + return 0; } @@ -1527,6 +1566,31 @@ static void info_callback(const char *msg, void *client_data) { fprintf(stdout, "[INFO] %s", msg); } +OPJ_FLOAT64 opj_clock(void) { +#ifdef _WIN32 + /* _WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return freq.QuadPart ? ( t.QuadPart /(OPJ_FLOAT64) freq.QuadPart ) : 0 ; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + OPJ_FLOAT64 procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = (OPJ_FLOAT64)(t.ru_utime.tv_sec + t.ru_stime.tv_sec); + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (OPJ_FLOAT64)(t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif +} + + /* -------------------------------------------------------------------------- */ /** * OPJ_COMPRESS MAIN @@ -1540,6 +1604,7 @@ int main(int argc, char **argv) { opj_codec_t* l_codec = 00; opj_image_t *image = NULL; raw_cparameters_t raw_cp; + OPJ_SIZE_T num_compressed_files = 0; char indexfilename[OPJ_PATH_LEN]; /* index file name */ @@ -1550,6 +1615,7 @@ int main(int argc, char **argv) { OPJ_BOOL bSuccess; OPJ_BOOL bUseTiles = OPJ_FALSE; /* OPJ_TRUE */ OPJ_UINT32 l_nb_tiles = 4; + OPJ_FLOAT64 t = opj_clock(); /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); @@ -1568,26 +1634,10 @@ int main(int argc, char **argv) { /* parse input and get user encoding parameters */ parameters.tcp_mct = (char) 255; /* This will be set later according to the input image or the provided option */ - if(parse_cmdline_encoder(argc, argv, ¶meters,&img_fol, &raw_cp, indexfilename) == 1) { + if(parse_cmdline_encoder(argc, argv, ¶meters,&img_fol, &raw_cp, indexfilename, sizeof(indexfilename)) == 1) { return 1; } - /* Create comment for codestream */ - if(parameters.cp_comment == NULL) { - const char comment[] = "Created by OpenJPEG version "; - const size_t clen = strlen(comment); - const char *version = opj_version(); - /* UniPG>> */ -#ifdef USE_JPWL - parameters.cp_comment = (char*)malloc(clen+strlen(version)+11); - sprintf(parameters.cp_comment,"%s%s with JPWL", comment, version); -#else - parameters.cp_comment = (char*)malloc(clen+strlen(version)+1); - sprintf(parameters.cp_comment,"%s%s", comment, version); -#endif - /* < +#include +#include +#include #endif /* _WIN32 */ #include "openjpeg.h" @@ -72,6 +75,7 @@ #include "color.h" #include "format_defs.h" +#include "opj_string.h" typedef struct dircnt{ /** Buffer for holding images read from Directory*/ @@ -93,72 +97,143 @@ typedef struct img_folder{ }img_fol_t; +typedef enum opj_prec_mode +{ + OPJ_PREC_MODE_CLIP, + OPJ_PREC_MODE_SCALE +} opj_precision_mode; + +typedef struct opj_prec +{ + OPJ_UINT32 prec; + opj_precision_mode mode; +}opj_precision; + +typedef struct opj_decompress_params +{ + /** core library parameters */ + opj_dparameters_t core; + + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** input file format 0: J2K, 1: JP2, 2: JPT */ + int decod_format; + /** output file format 0: PGX, 1: PxM, 2: BMP */ + int cod_format; + /** index file name */ + char indexfilename[OPJ_PATH_LEN]; + + /** Decoding area left boundary */ + OPJ_UINT32 DA_x0; + /** Decoding area right boundary */ + OPJ_UINT32 DA_x1; + /** Decoding area up boundary */ + OPJ_UINT32 DA_y0; + /** Decoding area bottom boundary */ + OPJ_UINT32 DA_y1; + /** Verbose mode */ + OPJ_BOOL m_verbose; + + /** tile number ot the decoded tile*/ + OPJ_UINT32 tile_index; + /** Nb of tile to decode */ + OPJ_UINT32 nb_tile_to_decode; + + opj_precision* precision; + OPJ_UINT32 nb_precision; + + /* force output colorspace to RGB */ + int force_rgb; + /* upsample components according to their dx/dy values */ + int upsample; + /* split output components to different files */ + int split_pnm; +}opj_decompress_parameters; + /* -------------------------------------------------------------------------- */ /* Declarations */ int get_num_images(char *imgdirpath); int load_images(dircnt_t *dirptr, char *imgdirpath); int get_file_format(const char *filename); -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters); +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters); static int infile_format(const char *fname); -int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename); +int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol); int parse_DA_values( char* inArg, unsigned int *DA_x0, unsigned int *DA_y0, unsigned int *DA_x1, unsigned int *DA_y1); +static opj_image_t* convert_gray_to_rgb(opj_image_t* original); + /* -------------------------------------------------------------------------- */ static void decode_help_display(void) { - fprintf(stdout,"\nThis is the opj_decompress utility from the OpenJPEG project.\n" - "It decompresses JPEG 2000 codestreams to various image formats.\n" - "It has been compiled against openjp2 library v%s.\n\n",opj_version()); + fprintf(stdout,"\nThis is the opj_decompress utility from the OpenJPEG project.\n" + "It decompresses JPEG 2000 codestreams to various image formats.\n" + "It has been compiled against openjp2 library v%s.\n\n",opj_version()); - fprintf(stdout,"Parameters:\n"); - fprintf(stdout,"-----------\n"); - fprintf(stdout,"\n"); - fprintf(stdout," -ImgDir \n"); - fprintf(stdout," Image file Directory path \n"); - fprintf(stdout," -OutFor \n"); - fprintf(stdout," REQUIRED only if -ImgDir is used\n"); - fprintf(stdout," Output format for decompressed images.\n"); - fprintf(stdout," -i \n"); - fprintf(stdout," REQUIRED only if an Input image directory is not specified\n"); - fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); - fprintf(stdout," is identified based on its suffix.\n"); - fprintf(stdout," -o \n"); - fprintf(stdout," REQUIRED\n"); - fprintf(stdout," Currently accepts formats specified above (see OutFor option)\n"); - fprintf(stdout," Binary data is written to the file (not ascii). If a PGX\n"); - fprintf(stdout," filename is given, there will be as many output files as there are\n"); - fprintf(stdout," components: an indice starting from 0 will then be appended to the\n"); - fprintf(stdout," output filename, just before the \"pgx\" extension. If a PGM filename\n"); - fprintf(stdout," is given and there are more than one component, only the first component\n"); - fprintf(stdout," will be written to the file.\n"); - fprintf(stdout," -r \n"); - fprintf(stdout," Set the number of highest resolution levels to be discarded. The\n"); - fprintf(stdout," image resolution is effectively divided by 2 to the power of the\n"); - fprintf(stdout," number of discarded levels. The reduce factor is limited by the\n"); - fprintf(stdout," smallest total number of decomposition levels among tiles.\n"); - fprintf(stdout," -l \n"); - fprintf(stdout," Set the maximum number of quality layers to decode. If there are\n"); - fprintf(stdout," less quality layers than the specified number, all the quality layers\n"); - fprintf(stdout," are decoded.\n"); - fprintf(stdout," -x \n"); - fprintf(stdout," Create an index file *.Idx (-x index_name.Idx) \n"); - fprintf(stdout," -d \n"); - fprintf(stdout," OPTIONAL\n"); - fprintf(stdout," Decoding area\n"); - fprintf(stdout," By default all the image is decoded.\n"); - fprintf(stdout," -t \n"); - fprintf(stdout," OPTIONAL\n"); - fprintf(stdout," Set the tile number of the decoded tile. Follow the JPEG2000 convention from left-up to bottom-up\n"); - fprintf(stdout," By default all tiles are decoded.\n"); - fprintf(stdout,"\n"); + fprintf(stdout,"Parameters:\n" + "-----------\n" + "\n" + " -ImgDir \n" + " Image file Directory path \n" + " -OutFor \n" + " REQUIRED only if -ImgDir is used\n" + " Output format for decompressed images.\n"); + fprintf(stdout," -i \n" + " REQUIRED only if an Input image directory is not specified\n" + " Currently accepts J2K-files, JP2-files and JPT-files. The file type\n" + " is identified based on its suffix.\n"); + fprintf(stdout," -o \n" + " REQUIRED\n" + " Currently accepts formats specified above (see OutFor option)\n" + " Binary data is written to the file (not ascii). If a PGX\n" + " filename is given, there will be as many output files as there are\n" + " components: an indice starting from 0 will then be appended to the\n" + " output filename, just before the \"pgx\" extension. If a PGM filename\n" + " is given and there are more than one component, only the first component\n" + " will be written to the file.\n"); + fprintf(stdout," -r \n" + " Set the number of highest resolution levels to be discarded. The\n" + " image resolution is effectively divided by 2 to the power of the\n" + " number of discarded levels. The reduce factor is limited by the\n" + " smallest total number of decomposition levels among tiles.\n" + " -l \n" + " Set the maximum number of quality layers to decode. If there are\n" + " less quality layers than the specified number, all the quality layers\n" + " are decoded.\n"); + fprintf(stdout," -x \n" + " Create an index file *.Idx (-x index_name.Idx) \n" + " -d \n" + " OPTIONAL\n" + " Decoding area\n" + " By default all the image is decoded.\n" + " -t \n" + " OPTIONAL\n" + " Set the tile number of the decoded tile. Follow the JPEG2000 convention from left-up to bottom-up\n" + " By default all tiles are decoded.\n"); + fprintf(stdout," -p [C|S][,[C|S][,...]]\n" + " OPTIONAL\n" + " Force the precision (bit depth) of components.\n"); + fprintf(stdout," There shall be at least 1 value. Theres no limit on the number of values (comma separated, last values ignored if too much values).\n" + " If there are less values than components, the last value is used for remaining components.\n" + " If 'C' is specified (default), values are clipped.\n" + " If 'S' is specified, values are scaled.\n" + " A 0 value can be specified (meaning original bit depth).\n"); + fprintf(stdout," -force-rgb\n" + " Force output image colorspace to RGB\n" + " -upsample\n" + " Downsampled components will be upsampled to image size\n" + " -split-pnm\n" + " Split output components to different files when writing to PNM\n" + "\n"); /* UniPG>> */ #ifdef USE_JPWL - fprintf(stdout," -W \n"); - fprintf(stdout," Activates the JPWL correction capability, if the codestream complies.\n"); - fprintf(stdout," Options can be a comma separated list of tokens:\n"); - fprintf(stdout," c, c=numcomps\n"); - fprintf(stdout," numcomps is the number of expected components in the codestream\n"); - fprintf(stdout," (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); + fprintf(stdout," -W \n" + " Activates the JPWL correction capability, if the codestream complies.\n" + " Options can be a comma separated list of tokens:\n" + " c, c=numcomps\n" + " numcomps is the number of expected components in the codestream\n" + " (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); #endif /* USE_JPWL */ /* <precision) { + free(parameters->precision); + parameters->precision = NULL; + } + parameters->nb_precision = 0U; + + for(;;) + { + int prec; + char mode; + char comma; + int count; + + count = sscanf(l_remaining, "%d%c%c", &prec, &mode, &comma); + if (count == 1) { + mode = 'C'; + count++; + } + if ((count == 2) || (mode==',')) { + if (mode==',') { + mode = 'C'; + } + comma=','; + count = 3; + } + if (count == 3) { + if ((prec < 1) || (prec > 32)) { + fprintf(stderr,"Invalid precision %d in precision option %s\n", prec, option); + l_result = OPJ_FALSE; + break; + } + if ((mode != 'C') && (mode != 'S')) { + fprintf(stderr,"Invalid precision mode %c in precision option %s\n", mode, option); + l_result = OPJ_FALSE; + break; + } + if (comma != ',') { + fprintf(stderr,"Invalid character %c in precision option %s\n", comma, option); + l_result = OPJ_FALSE; + break; + } + + if (parameters->precision == NULL) { + /* first one */ + parameters->precision = (opj_precision *)malloc(sizeof(opj_precision)); + if (parameters->precision == NULL) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + } else { + OPJ_UINT32 l_new_size = parameters->nb_precision + 1U; + opj_precision* l_new; + + if (l_new_size == 0U) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + + l_new = (opj_precision *)realloc(parameters->precision, l_new_size * sizeof(opj_precision)); + if (l_new == NULL) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + parameters->precision = l_new; + } + + parameters->precision[parameters->nb_precision].prec = (OPJ_UINT32)prec; + switch (mode) { + case 'C': + parameters->precision[parameters->nb_precision].mode = OPJ_PREC_MODE_CLIP; + break; + case 'S': + parameters->precision[parameters->nb_precision].mode = OPJ_PREC_MODE_SCALE; + break; + default: + break; + } + parameters->nb_precision++; + + l_remaining = strchr(l_remaining, ','); + if (l_remaining == NULL) { + break; + } + l_remaining += 1; + } else { + fprintf(stderr,"Could not parse precision option %s\n", option); + l_result = OPJ_FALSE; + break; + } + } + + return l_result; +} + +/* -------------------------------------------------------------------------- */ + int get_num_images(char *imgdirpath){ DIR *dir; struct dirent* content; @@ -184,6 +364,7 @@ int get_num_images(char *imgdirpath){ continue; num_images++; } + closedir(dir); return num_images; } @@ -210,6 +391,7 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){ strcpy(dirptr->filename[i],content->d_name); i++; } + closedir(dir); return 0; } @@ -218,7 +400,7 @@ int get_file_format(const char *filename) { unsigned int i; static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "rawl", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; - char * ext = strrchr(filename, '.'); + const char * ext = strrchr(filename, '.'); if (ext == NULL) return -1; ext++; @@ -233,18 +415,26 @@ int get_file_format(const char *filename) { return -1; } +#ifdef _WIN32 +const char* path_separator = "\\"; +#else +const char* path_separator = "/"; +#endif + /* -------------------------------------------------------------------------- */ -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters){ char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; char *temp_p, temp1[OPJ_PATH_LEN]=""; strcpy(image_filename,dirptr->filename[imageno]); fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); - parameters->decod_format = infile_format(image_filename); + sprintf(infilename, "%s%s%s", img_fol->imgdirpath, path_separator, image_filename); + parameters->decod_format = infile_format(infilename); if (parameters->decod_format == -1) return 1; - sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); - strncpy(parameters->infile, infilename, sizeof(infilename)); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { + return 1; + } /*Set output file*/ strcpy(temp_ofname,strtok(image_filename,".")); @@ -254,7 +444,9 @@ char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparamet } if(img_fol->set_out_format==1){ sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); - strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { + return 1; + } } return 0; } @@ -320,15 +512,18 @@ static int infile_format(const char *fname) * Parse the command line */ /* -------------------------------------------------------------------------- */ -int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { +int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol) { /* parse the command line */ int totlen, c; opj_option_t long_option[]={ - {"ImgDir",REQ_ARG, NULL ,'y'}, - {"OutFor",REQ_ARG, NULL ,'O'} + {"ImgDir", REQ_ARG, NULL,'y'}, + {"OutFor", REQ_ARG, NULL,'O'}, + {"force-rgb", NO_ARG, NULL, 1}, + {"upsample", NO_ARG, NULL, 1}, + {"split-pnm", NO_ARG, NULL, 1} }; - const char optlist[] = "i:o:r:l:x:d:t:" + const char optlist[] = "i:o:r:l:x:d:t:p:" /* UniPG>> */ #ifdef USE_JPWL @@ -336,13 +531,20 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i #endif /* USE_JPWL */ /* <force_rgb); + long_option[3].flag = &(parameters->upsample); + long_option[4].flag = &(parameters->split_pnm); totlen=sizeof(long_option); + opj_reset_options_reading(); img_fol->set_out_format = 0; do { c = opj_getopt_long(argc, argv,optlist,long_option,totlen); if (c == -1) break; switch (c) { + case 0: /* long opt with flag */ + break; case 'i': /* input file */ { char *infile = opj_optarg; @@ -366,7 +568,10 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i infile); return 1; } - strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; @@ -394,10 +599,13 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case PNG_DFMT: break; default: - fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outfile); + fprintf(stderr, "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", outfile); return 1; } - strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; @@ -436,7 +644,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i img_fol->out_format = "png"; break; default: - fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outformat); + fprintf(stderr, "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", outformat); return 1; break; } @@ -448,7 +656,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'r': /* reduce option */ { - sscanf(opj_optarg, "%ud", ¶meters->cp_reduce); + sscanf(opj_optarg, "%u", &(parameters->core.cp_reduce)); } break; @@ -457,7 +665,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'l': /* layering option */ { - sscanf(opj_optarg, "%ud", ¶meters->cp_layer); + sscanf(opj_optarg, "%u", &(parameters->core.cp_layer)); } break; @@ -481,11 +689,14 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'd': /* Input decode ROI */ { - int size_optarg = (int)strlen(opj_optarg) + 1; - char *ROI_values = (char*) malloc((size_t)size_optarg); + size_t size_optarg = (size_t)strlen(opj_optarg) + 1U; + char *ROI_values = (char*) malloc(size_optarg); + if (ROI_values == NULL) { + fprintf(stderr, "[ERROR] Couldn't allocate memory\n"); + return 1; + } ROI_values[0] = '\0'; - strncpy(ROI_values, opj_optarg, strlen(opj_optarg)); - ROI_values[strlen(opj_optarg)] = '\0'; + memcpy(ROI_values, opj_optarg, size_optarg); /*printf("ROI_values = %s [%d / %d]\n", ROI_values, strlen(ROI_values), size_optarg ); */ parse_DA_values( ROI_values, ¶meters->DA_x0, ¶meters->DA_y0, ¶meters->DA_x1, ¶meters->DA_y1); @@ -497,7 +708,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 't': /* Input tile index */ { - sscanf(opj_optarg, "%ud", ¶meters->tile_index); + sscanf(opj_optarg, "%u", ¶meters->tile_index); parameters->nb_tile_to_decode = 1; } break; @@ -506,11 +717,24 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'x': /* Creation of index file */ { - char *index = opj_optarg; - strncpy(indexfilename, index, OPJ_PATH_LEN); + if (opj_strcpy_s(parameters->indexfilename, sizeof(parameters->indexfilename), opj_optarg) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'p': /* Force precision */ + { + if (!parse_precision(opj_optarg, parameters)) + { + return 1; + } } break; /* ----------------------------------------------------- */ + /* UniPG>> */ #ifdef USE_JPWL @@ -648,6 +872,30 @@ int parse_DA_values( char* inArg, unsigned int *DA_x0, unsigned int *DA_y0, unsi } } +OPJ_FLOAT64 opj_clock(void) { +#ifdef _WIN32 + /* _WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : 0; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + OPJ_FLOAT64 procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = (OPJ_FLOAT64)(t.ru_utime.tv_sec + t.ru_stime.tv_sec); + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (OPJ_FLOAT64)(t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif +} + /* -------------------------------------------------------------------------- */ /** @@ -672,6 +920,258 @@ static void info_callback(const char *msg, void *client_data) { fprintf(stdout, "[INFO] %s", msg); } +static void set_default_parameters(opj_decompress_parameters* parameters) +{ + if (parameters) { + memset(parameters, 0, sizeof(opj_decompress_parameters)); + + /* default decoding parameters (command line specific) */ + parameters->decod_format = -1; + parameters->cod_format = -1; + + /* default decoding parameters (core) */ + opj_set_default_decoder_parameters(&(parameters->core)); + } +} + +static void destroy_parameters(opj_decompress_parameters* parameters) +{ + if (parameters) { + if (parameters->precision) { + free(parameters->precision); + parameters->precision = NULL; + } + } +} + +/* -------------------------------------------------------------------------- */ + +static opj_image_t* convert_gray_to_rgb(opj_image_t* original) +{ + OPJ_UINT32 compno; + opj_image_t* l_new_image = NULL; + opj_image_cmptparm_t* l_new_components = NULL; + + l_new_components = (opj_image_cmptparm_t*)malloc((original->numcomps + 2U) * sizeof(opj_image_cmptparm_t)); + if (l_new_components == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for RGB image!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_components[0].bpp = l_new_components[1].bpp = l_new_components[2].bpp = original->comps[0].bpp; + l_new_components[0].dx = l_new_components[1].dx = l_new_components[2].dx = original->comps[0].dx; + l_new_components[0].dy = l_new_components[1].dy = l_new_components[2].dy = original->comps[0].dy; + l_new_components[0].h = l_new_components[1].h = l_new_components[2].h = original->comps[0].h; + l_new_components[0].w = l_new_components[1].w = l_new_components[2].w = original->comps[0].w; + l_new_components[0].prec = l_new_components[1].prec = l_new_components[2].prec = original->comps[0].prec; + l_new_components[0].sgnd = l_new_components[1].sgnd = l_new_components[2].sgnd = original->comps[0].sgnd; + l_new_components[0].x0 = l_new_components[1].x0 = l_new_components[2].x0 = original->comps[0].x0; + l_new_components[0].y0 = l_new_components[1].y0 = l_new_components[2].y0 = original->comps[0].y0; + + for(compno = 1U; compno < original->numcomps; ++compno) { + l_new_components[compno+2U].bpp = original->comps[compno].bpp; + l_new_components[compno+2U].dx = original->comps[compno].dx; + l_new_components[compno+2U].dy = original->comps[compno].dy; + l_new_components[compno+2U].h = original->comps[compno].h; + l_new_components[compno+2U].w = original->comps[compno].w; + l_new_components[compno+2U].prec = original->comps[compno].prec; + l_new_components[compno+2U].sgnd = original->comps[compno].sgnd; + l_new_components[compno+2U].x0 = original->comps[compno].x0; + l_new_components[compno+2U].y0 = original->comps[compno].y0; + } + + l_new_image = opj_image_create(original->numcomps + 2U, l_new_components, OPJ_CLRSPC_SRGB); + free(l_new_components); + if (l_new_image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for RGB image!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_image->x0 = original->x0; + l_new_image->x1 = original->x1; + l_new_image->y0 = original->y0; + l_new_image->y1 = original->y1; + + l_new_image->comps[0].factor = l_new_image->comps[1].factor = l_new_image->comps[2].factor = original->comps[0].factor; + l_new_image->comps[0].alpha = l_new_image->comps[1].alpha = l_new_image->comps[2].alpha = original->comps[0].alpha; + l_new_image->comps[0].resno_decoded = l_new_image->comps[1].resno_decoded = l_new_image->comps[2].resno_decoded = original->comps[0].resno_decoded; + + memcpy(l_new_image->comps[0].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + memcpy(l_new_image->comps[1].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + memcpy(l_new_image->comps[2].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + + for(compno = 1U; compno < original->numcomps; ++compno) { + l_new_image->comps[compno+2U].factor = original->comps[compno].factor; + l_new_image->comps[compno+2U].alpha = original->comps[compno].alpha; + l_new_image->comps[compno+2U].resno_decoded = original->comps[compno].resno_decoded; + memcpy(l_new_image->comps[compno+2U].data, original->comps[compno].data, original->comps[compno].w * original->comps[compno].h * sizeof(OPJ_INT32)); + } + opj_image_destroy(original); + return l_new_image; +} + +/* -------------------------------------------------------------------------- */ + +static opj_image_t* upsample_image_components(opj_image_t* original) +{ + opj_image_t* l_new_image = NULL; + opj_image_cmptparm_t* l_new_components = NULL; + OPJ_BOOL l_upsample_need = OPJ_FALSE; + OPJ_UINT32 compno; + + for (compno = 0U; compno < original->numcomps; ++compno) { + if (original->comps[compno].factor > 0U) { + fprintf(stderr, "ERROR -> opj_decompress: -upsample not supported with reduction\n"); + opj_image_destroy(original); + return NULL; + } + if ((original->comps[compno].dx > 1U) || (original->comps[compno].dy > 1U)) { + l_upsample_need = OPJ_TRUE; + break; + } + } + if (!l_upsample_need) { + return original; + } + /* Upsample is needed */ + l_new_components = (opj_image_cmptparm_t*)malloc(original->numcomps * sizeof(opj_image_cmptparm_t)); + if (l_new_components == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for upsampled components!\n"); + opj_image_destroy(original); + return NULL; + } + + for (compno = 0U; compno < original->numcomps; ++compno) { + opj_image_cmptparm_t* l_new_cmp = &(l_new_components[compno]); + opj_image_comp_t* l_org_cmp = &(original->comps[compno]); + + l_new_cmp->bpp = l_org_cmp->bpp; + l_new_cmp->prec = l_org_cmp->prec; + l_new_cmp->sgnd = l_org_cmp->sgnd; + l_new_cmp->x0 = original->x0; + l_new_cmp->y0 = original->y0; + l_new_cmp->dx = 1; + l_new_cmp->dy = 1; + l_new_cmp->w = l_org_cmp->w; /* should be original->x1 - original->x0 for dx==1 */ + l_new_cmp->h = l_org_cmp->h; /* should be original->y1 - original->y0 for dy==0 */ + + if (l_org_cmp->dx > 1U) { + l_new_cmp->w = original->x1 - original->x0; + } + + if (l_org_cmp->dy > 1U) { + l_new_cmp->h = original->y1 - original->y0; + } + } + + l_new_image = opj_image_create(original->numcomps, l_new_components, original->color_space); + free(l_new_components); + if (l_new_image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for upsampled components!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_image->x0 = original->x0; + l_new_image->x1 = original->x1; + l_new_image->y0 = original->y0; + l_new_image->y1 = original->y1; + + for (compno = 0U; compno < original->numcomps; ++compno) { + opj_image_comp_t* l_new_cmp = &(l_new_image->comps[compno]); + opj_image_comp_t* l_org_cmp = &(original->comps[compno]); + + l_new_cmp->factor = l_org_cmp->factor; + l_new_cmp->alpha = l_org_cmp->alpha; + l_new_cmp->resno_decoded = l_org_cmp->resno_decoded; + + if ((l_org_cmp->dx > 1U) || (l_org_cmp->dy > 1U)) { + const OPJ_INT32* l_src = l_org_cmp->data; + OPJ_INT32* l_dst = l_new_cmp->data; + OPJ_UINT32 y; + OPJ_UINT32 xoff, yoff; + + /* need to take into account dx & dy */ + xoff = l_org_cmp->dx * l_org_cmp->x0 - original->x0; + yoff = l_org_cmp->dy * l_org_cmp->y0 - original->y0; + if ((xoff >= l_org_cmp->dx) || (yoff >= l_org_cmp->dy)) { + fprintf(stderr, "ERROR -> opj_decompress: Invalid image/component parameters found when upsampling\n"); + opj_image_destroy(original); + opj_image_destroy(l_new_image); + return NULL; + } + + for (y = 0U; y < yoff; ++y) { + memset(l_dst, 0U, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + + if(l_new_cmp->h > (l_org_cmp->dy - 1U)) { /* check subtraction overflow for really small images */ + for (; y < l_new_cmp->h - (l_org_cmp->dy - 1U); y += l_org_cmp->dy) { + OPJ_UINT32 x, dy; + OPJ_UINT32 xorg; + + xorg = 0U; + for (x = 0U; x < xoff; ++x) { + l_dst[x] = 0; + } + if (l_new_cmp->w > (l_org_cmp->dx - 1U)) { /* check subtraction overflow for really small images */ + for (; x < l_new_cmp->w - (l_org_cmp->dx - 1U); x += l_org_cmp->dx, ++xorg) { + OPJ_UINT32 dx; + for (dx = 0U; dx < l_org_cmp->dx; ++dx) { + l_dst[x + dx] = l_src[xorg]; + } + } + } + for (; x < l_new_cmp->w; ++x) { + l_dst[x] = l_src[xorg]; + } + l_dst += l_new_cmp->w; + + for (dy = 1U; dy < l_org_cmp->dy; ++dy) { + memcpy(l_dst, l_dst - l_new_cmp->w, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + l_src += l_org_cmp->w; + } + } + if (y < l_new_cmp->h) { + OPJ_UINT32 x; + OPJ_UINT32 xorg; + + xorg = 0U; + for (x = 0U; x < xoff; ++x) { + l_dst[x] = 0; + } + if (l_new_cmp->w > (l_org_cmp->dx - 1U)) { /* check subtraction overflow for really small images */ + for (; x < l_new_cmp->w - (l_org_cmp->dx - 1U); x += l_org_cmp->dx, ++xorg) { + OPJ_UINT32 dx; + for (dx = 0U; dx < l_org_cmp->dx; ++dx) { + l_dst[x + dx] = l_src[xorg]; + } + } + } + for (; x < l_new_cmp->w; ++x) { + l_dst[x] = l_src[xorg]; + } + l_dst += l_new_cmp->w; + ++y; + for (; y < l_new_cmp->h; ++y) { + memcpy(l_dst, l_dst - l_new_cmp->w, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + } + } + else { + memcpy(l_new_cmp->data, l_org_cmp->data, l_org_cmp->w * l_org_cmp->h * sizeof(OPJ_INT32)); + } + } + opj_image_destroy(original); + return l_new_image; +} + /* -------------------------------------------------------------------------- */ /** * OPJ_DECOMPRESS MAIN @@ -679,30 +1179,28 @@ static void info_callback(const char *msg, void *client_data) { /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { - opj_dparameters_t parameters; /* decompression parameters */ + opj_decompress_parameters parameters; /* decompression parameters */ opj_image_t* image = NULL; opj_stream_t *l_stream = NULL; /* Stream */ opj_codec_t* l_codec = NULL; /* Handle to a decompressor */ opj_codestream_index_t* cstr_index = NULL; - char indexfilename[OPJ_PATH_LEN]; /* index file name */ - OPJ_INT32 num_images, imageno; img_fol_t img_fol; dircnt_t *dirptr = NULL; int failed = 0; + OPJ_FLOAT64 t, tCumulative = 0; + OPJ_UINT32 numDecompressedImages = 0; /* set decoding parameters to default values */ - opj_set_default_decoder_parameters(¶meters); - - /* FIXME Initialize indexfilename and img_fol */ - *indexfilename = 0; + set_default_parameters(¶meters); /* Initialize img_fol */ memset(&img_fol,0,sizeof(img_fol_t)); /* parse input and get user encoding parameters */ - if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol) == 1) { + destroy_parameters(¶meters); return EXIT_FAILURE; } @@ -717,6 +1215,7 @@ int main(int argc, char **argv) dirptr->filename = (char**) malloc((size_t)num_images*sizeof(char*)); if(!dirptr->filename_buf){ + destroy_parameters(¶meters); return EXIT_FAILURE; } for(it_image=0;it_image failed to create the stream from the file %s\n", parameters.infile); + destroy_parameters(¶meters); return EXIT_FAILURE; } @@ -779,6 +1282,7 @@ int main(int argc, char **argv) } default: fprintf(stderr, "skipping file..\n"); + destroy_parameters(¶meters); opj_stream_destroy(l_stream); continue; } @@ -788,9 +1292,12 @@ int main(int argc, char **argv) opj_set_warning_handler(l_codec, warning_callback,00); opj_set_error_handler(l_codec, error_callback,00); + t = opj_clock(); + /* Setup the decoder decoding parameters using user parameters */ - if ( !opj_setup_decoder(l_codec, ¶meters) ){ - fprintf(stderr, "ERROR -> opj_compress: failed to setup the decoder\n"); + if ( !opj_setup_decoder(l_codec, &(parameters.core)) ){ + fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n"); + destroy_parameters(¶meters); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); return EXIT_FAILURE; @@ -800,6 +1307,7 @@ int main(int argc, char **argv) /* Read the main header of the codestream and if necessary the JP2 boxes*/ if(! opj_read_header(l_stream, l_codec, &image)){ fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n"); + destroy_parameters(¶meters); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); opj_image_destroy(image); @@ -811,6 +1319,7 @@ int main(int argc, char **argv) if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0, (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1, (OPJ_INT32)parameters.DA_y1)){ fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n"); + destroy_parameters(¶meters); opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); opj_image_destroy(image); @@ -820,6 +1329,7 @@ int main(int argc, char **argv) /* Get the decoded image */ if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) { fprintf(stderr,"ERROR -> opj_decompress: failed to decode image!\n"); + destroy_parameters(¶meters); opj_destroy_codec(l_codec); opj_stream_destroy(l_stream); opj_image_destroy(image); @@ -839,6 +1349,7 @@ int main(int argc, char **argv) if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); + destroy_parameters(¶meters); opj_destroy_codec(l_codec); opj_stream_destroy(l_stream); opj_image_destroy(image); @@ -847,13 +1358,12 @@ int main(int argc, char **argv) fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index); } + tCumulative += opj_clock() - t; + numDecompressedImages++; + /* Close the byte stream */ opj_stream_destroy(l_stream); - if(image->color_space == OPJ_CLRSPC_SYCC){ - color_sycc_to_rgb(image); /* FIXME */ - } - if( image->color_space != OPJ_CLRSPC_SYCC && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy && image->comps[1].dx != 1 ) @@ -861,19 +1371,102 @@ int main(int argc, char **argv) else if (image->numcomps <= 2) image->color_space = OPJ_CLRSPC_GRAY; + if(image->color_space == OPJ_CLRSPC_SYCC){ + color_sycc_to_rgb(image); + } + else if((image->color_space == OPJ_CLRSPC_CMYK) && (parameters.cod_format != TIF_DFMT)){ + color_cmyk_to_rgb(image); + } + else if(image->color_space == OPJ_CLRSPC_EYCC){ + color_esycc_to_rgb(image); + } + if(image->icc_profile_buf) { #if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) - color_apply_icc_profile(image); /* FIXME */ + if(image->icc_profile_len) + color_apply_icc_profile(image); + else + color_cielab_to_rgb(image); #endif free(image->icc_profile_buf); image->icc_profile_buf = NULL; image->icc_profile_len = 0; } + + /* Force output precision */ + /* ---------------------- */ + if (parameters.precision != NULL) + { + OPJ_UINT32 compno; + for (compno = 0; compno < image->numcomps; ++compno) + { + OPJ_UINT32 precno = compno; + OPJ_UINT32 prec; + + if (precno >= parameters.nb_precision) { + precno = parameters.nb_precision - 1U; + } + + prec = parameters.precision[precno].prec; + if (prec == 0) { + prec = image->comps[compno].prec; + } + + switch (parameters.precision[precno].mode) { + case OPJ_PREC_MODE_CLIP: + clip_component(&(image->comps[compno]), prec); + break; + case OPJ_PREC_MODE_SCALE: + scale_component(&(image->comps[compno]), prec); + break; + default: + break; + } + + } + } + + /* Upsample components */ + /* ------------------- */ + if (parameters.upsample) + { + image = upsample_image_components(image); + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to upsample image components!\n"); + destroy_parameters(¶meters); + opj_destroy_codec(l_codec); + return EXIT_FAILURE; + } + } + + /* Force RGB output */ + /* ---------------- */ + if (parameters.force_rgb) + { + switch (image->color_space) { + case OPJ_CLRSPC_SRGB: + break; + case OPJ_CLRSPC_GRAY: + image = convert_gray_to_rgb(image); + break; + default: + fprintf(stderr, "ERROR -> opj_decompress: don't know how to convert image to RGB colorspace!\n"); + opj_image_destroy(image); + image = NULL; + break; + } + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n"); + destroy_parameters(¶meters); + opj_destroy_codec(l_codec); + return EXIT_FAILURE; + } + } /* create output image */ /* ------------------- */ switch (parameters.cod_format) { case PXM_DFMT: /* PNM PGM PPM */ - if (imagetopnm(image, parameters.outfile)) { + if (imagetopnm(image, parameters.outfile, parameters.split_pnm)) { fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); failed = 1; } @@ -972,12 +1565,12 @@ int main(int argc, char **argv) /* destroy the codestream index */ opj_destroy_cstr_index(&cstr_index); - if(failed) remove(parameters.outfile); + if(failed) (void)remove(parameters.outfile); /* ignore return value */ + } + destroy_parameters(¶meters); + if (numDecompressedImages) { + fprintf(stdout, "decode time: %d ms\n", (int)( (tCumulative * 1000.0) / (OPJ_FLOAT64)numDecompressedImages)); } return failed ? EXIT_FAILURE : EXIT_SUCCESS; } /*end main*/ - - - - diff --git a/src/bin/jp2/opj_dump.c b/src/bin/jp2/opj_dump.c index a85cfe90..1e51f43c 100644 --- a/src/bin/jp2/opj_dump.c +++ b/src/bin/jp2/opj_dump.c @@ -57,6 +57,7 @@ #include "index.h" #include "format_defs.h" +#include "opj_string.h" typedef struct dircnt{ /** Buffer for holding images read from Directory*/ @@ -134,6 +135,7 @@ static int get_num_images(char *imgdirpath){ continue; num_images++; } + closedir(dir); return num_images; } @@ -160,6 +162,7 @@ static int load_images(dircnt_t *dirptr, char *imgdirpath){ strcpy(dirptr->filename[i],content->d_name); i++; } + closedir(dir); return 0; } @@ -168,7 +171,7 @@ static int get_file_format(const char *filename) { unsigned int i; static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; - char * ext = strrchr(filename, '.'); + const char *ext = strrchr(filename, '.'); if (ext == NULL) return -1; ext++; @@ -194,7 +197,9 @@ static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_d if (parameters->decod_format == -1) return 1; sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); - strncpy(parameters->infile, infilename, sizeof(infilename)); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { + return 1; + } /*Set output file*/ strcpy(temp_ofname,strtok(image_filename,".")); @@ -204,7 +209,9 @@ static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_d } if(img_fol->set_out_format==1){ sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); - strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { + return 1; + } } return 0; } @@ -301,7 +308,10 @@ static int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *param infile); return 1; } - strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; @@ -309,8 +319,10 @@ static int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *param case 'o': /* output file */ { - char *outfile = opj_optarg; - strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), opj_optarg) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; diff --git a/src/bin/jp2/windirent.h b/src/bin/jp2/windirent.h index 944b7d71..bef28194 100644 --- a/src/bin/jp2/windirent.h +++ b/src/bin/jp2/windirent.h @@ -243,7 +243,7 @@ * Substitute for real dirent structure. Note that `d_name' field is a * true character array although we have it copied in the implementation * dependent data. We could save some memory if we had declared `d_name' - * as a pointer refering the name within implementation dependent data. + * as a pointer referring the name within implementation dependent data. * We have not done that since some code may rely on sizeof(d_name) to be * something other than four. Besides, directory entries are typically so * small that it takes virtually no time to copy them from place to place. @@ -411,7 +411,7 @@ static DIR *opendir(const char *dirname) * capacity of d_name with different macros and some systems do not define * capacity at all (besides actual declaration of the field). If you really * need to find out storage capacity of d_name then you might want to try - * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although * there are many MS-DOS and MS-Windows implementations those do not define * it. There are also systems that declare d_name as "char d_name[1]" and * then allocate suitable amount of memory at run-time. Thanks to Alain @@ -466,7 +466,7 @@ readdir (DIR *dirp) /* fill in entry and return that */ #if defined(DIRENT_WIN32_INTERFACE) if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { - /* Last file has been processed or an error occured */ + /* Last file has been processed or an error occurred */ FindClose (dirp->search_handle); dirp->search_handle = INVALID_HANDLE_VALUE; errno = ENOENT; diff --git a/src/bin/jp3d/windirent.h b/src/bin/jp3d/windirent.h index 72b38cea..2494cd4e 100644 --- a/src/bin/jp3d/windirent.h +++ b/src/bin/jp3d/windirent.h @@ -242,7 +242,7 @@ * Substitute for real dirent structure. Note that `d_name' field is a * true character array although we have it copied in the implementation * dependent data. We could save some memory if we had declared `d_name' - * as a pointer refering the name within implementation dependent data. + * as a pointer referring the name within implementation dependent data. * We have not done that since some code may rely on sizeof(d_name) to be * something other than four. Besides, directory entries are typically so * small that it takes virtually no time to copy them from place to place. @@ -410,7 +410,7 @@ static DIR *opendir(const char *dirname) * capacity of d_name with different macros and some systems do not define * capacity at all (besides actual declaration of the field). If you really * need to find out storage capacity of d_name then you might want to try - * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although * there are many MS-DOS and MS-Windows implementations those do not define * it. There are also systems that declare d_name as "char d_name[1]" and * then allocate suitable amount of memory at run-time. Thanks to Alain @@ -465,7 +465,7 @@ readdir (DIR *dirp) /* fill in entry and return that */ #if defined(DIRENT_WIN32_INTERFACE) if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { - /* Last file has been processed or an error occured */ + /* Last file has been processed or an error occurred */ FindClose (dirp->search_handle); dirp->search_handle = INVALID_HANDLE_VALUE; errno = ENOENT; diff --git a/src/bin/jpwl/convert.c b/src/bin/jpwl/convert.c index 5d9219b3..bf7b5641 100644 --- a/src/bin/jpwl/convert.c +++ b/src/bin/jpwl/convert.c @@ -1436,7 +1436,7 @@ int imagetopgx(opj_image_t * image, const char *outfile) { fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); return 1; } - /* dont need name anymore */ + /* don't need name anymore */ if( total > 256 ) { free(name); } @@ -2858,6 +2858,7 @@ opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw for (i = 0; i < w * h; i++) { if (!fread(&value, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + fclose(f); return NULL; } image->comps[compno].data[i] = raw_cp->rawSigned?(char)value:value; @@ -2872,11 +2873,13 @@ opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw unsigned char temp; if (!fread(&temp, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + fclose(f); return NULL; } value = temp << 8; if (!fread(&temp, 1, 1, f)) { fprintf(stderr,"Error reading raw file. End of file probably reached.\n"); + fclose(f); return NULL; } value += temp; @@ -2886,6 +2889,7 @@ opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw } else { fprintf(stderr,"OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + fclose(f); return NULL; } diff --git a/src/bin/jpwl/opj_jpwl_compress.c b/src/bin/jpwl/opj_jpwl_compress.c index 7537b61d..7410486e 100644 --- a/src/bin/jpwl/opj_jpwl_compress.c +++ b/src/bin/jpwl/opj_jpwl_compress.c @@ -199,7 +199,7 @@ static void encode_help_display(void) { fprintf(stdout," Indicate multiple modes by adding their values. \n"); fprintf(stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); fprintf(stdout,"\n"); - fprintf(stdout,"-TP : devide packets of every tile into tile-parts (-TP R) [R, L, C]\n"); + fprintf(stdout,"-TP : divide packets of every tile into tile-parts (-TP R) [R, L, C]\n"); fprintf(stdout,"\n"); fprintf(stdout,"-x : create an index file *.Idx (-x index_name.Idx) \n"); fprintf(stdout,"\n"); diff --git a/src/bin/jpwl/windirent.h b/src/bin/jpwl/windirent.h index 944b7d71..bef28194 100644 --- a/src/bin/jpwl/windirent.h +++ b/src/bin/jpwl/windirent.h @@ -243,7 +243,7 @@ * Substitute for real dirent structure. Note that `d_name' field is a * true character array although we have it copied in the implementation * dependent data. We could save some memory if we had declared `d_name' - * as a pointer refering the name within implementation dependent data. + * as a pointer referring the name within implementation dependent data. * We have not done that since some code may rely on sizeof(d_name) to be * something other than four. Besides, directory entries are typically so * small that it takes virtually no time to copy them from place to place. @@ -411,7 +411,7 @@ static DIR *opendir(const char *dirname) * capacity of d_name with different macros and some systems do not define * capacity at all (besides actual declaration of the field). If you really * need to find out storage capacity of d_name then you might want to try - * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although * there are many MS-DOS and MS-Windows implementations those do not define * it. There are also systems that declare d_name as "char d_name[1]" and * then allocate suitable amount of memory at run-time. Thanks to Alain @@ -466,7 +466,7 @@ readdir (DIR *dirp) /* fill in entry and return that */ #if defined(DIRENT_WIN32_INTERFACE) if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { - /* Last file has been processed or an error occured */ + /* Last file has been processed or an error occurred */ FindClose (dirp->search_handle); dirp->search_handle = INVALID_HANDLE_VALUE; errno = ENOENT; diff --git a/src/bin/mj2/meta_out.c b/src/bin/mj2/meta_out.c index b6795045..f5ca0be8 100644 --- a/src/bin/mj2/meta_out.c +++ b/src/bin/mj2/meta_out.c @@ -375,7 +375,7 @@ void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) { } void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) { -/* Univeral Unique IDs of 16 bytes. */ +/* Universal Unique IDs of 16 bytes. */ #ifdef NOTYET /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file. This function supports the top level of the file, but uuid may be elsewhere [not yet supported]. @@ -962,7 +962,7 @@ int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int s fprintf(xmlout, " \n", snum+1); fprintf(xmlout, " \n"); /* There can be multiple codestreams; a particular image is entirely within a single codestream */ - /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */ + /* TO DO: A frame can be represented by two I-guess-contiguous codestreams if its interleaved. */ fprintf(xmlout, " \n"); /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */ xml_out_frame_siz(xmlout, img, cp); /* reqd in main */ diff --git a/src/bin/mj2/mj2_to_metadata.c b/src/bin/mj2/mj2_to_metadata.c index 489f19cb..2ec2829d 100644 --- a/src/bin/mj2/mj2_to_metadata.c +++ b/src/bin/mj2/mj2_to_metadata.c @@ -64,7 +64,7 @@ void help_display() fprintf(stdout,"----------\n"); fprintf(stdout,"The metadata includes the jp2 image and tile headers of the first frame.\n"); fprintf(stdout,"\n"); - fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexidecimal) as stored in the\n"); + fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexadecimal) as stored in the\n"); fprintf(stdout,"file, and, if apt, in a 'derived' form that is more quickly grasped.\n"); fprintf(stdout,"\n"); fprintf(stdout,"Notes explaining the XML are embedded as terse comments. These include\n"); diff --git a/src/bin/mj2/opj_mj2_wrap.c b/src/bin/mj2/opj_mj2_wrap.c index 7daa147f..59fb871d 100644 --- a/src/bin/mj2/opj_mj2_wrap.c +++ b/src/bin/mj2/opj_mj2_wrap.c @@ -356,7 +356,7 @@ static void setparams(opj_mj2_t *movie, opj_image_t *image) { movie->tk[0].jp2_struct.enumcs = 18; /* YUV */ else - movie->tk[0].jp2_struct.enumcs = 0; /* Unkown profile */ + movie->tk[0].jp2_struct.enumcs = 0; /* Unknown profile */ } int main(int argc, char *argv[]) { diff --git a/src/bin/wx/OPJViewer/source/OPJThreads.cpp b/src/bin/wx/OPJViewer/source/OPJThreads.cpp index e3533a72..c9859860 100644 --- a/src/bin/wx/OPJViewer/source/OPJThreads.cpp +++ b/src/bin/wx/OPJViewer/source/OPJThreads.cpp @@ -889,7 +889,7 @@ void OPJMarkerTree::OnSelChanged(wxTreeEvent& event) m_peektextCtrl->WriteText(text); - delete buffer; + delete [] buffer; } /*void LogKeyEvent(const wxChar *name, const wxKeyEvent& event) diff --git a/src/bin/wx/OPJViewer/source/readmebefore.txt b/src/bin/wx/OPJViewer/source/readmebefore.txt index a59b0e87..c945d291 100644 --- a/src/bin/wx/OPJViewer/source/readmebefore.txt +++ b/src/bin/wx/OPJViewer/source/readmebefore.txt @@ -8,4 +8,4 @@ Anybody. As the OpenJPEG library is released under the BSD license, anybody can Who is developing the library ? =============================== -The library is developed by the Communications and Remote Sensing Lab (TELE), in the Université Catholique de Louvain (UCL). The JPWL module is developped and maintained by the Digital Signal Processing Lab (DSPLab) of the University of Perugia, Italy (UNIPG). As our purpose is to make OpenJPEG really useful for those interested in the image compression field, any feedback/advices are obviously welcome ! We will do our best to handle them quickly. \ No newline at end of file +The library is developed by the Communications and Remote Sensing Lab (TELE), in the Université Catholique de Louvain (UCL). The JPWL module is developed and maintained by the Digital Signal Processing Lab (DSPLab) of the University of Perugia, Italy (UNIPG). As our purpose is to make OpenJPEG really useful for those interested in the image compression field, any feedback/advices are obviously welcome ! We will do our best to handle them quickly. diff --git a/src/lib/openjp2/CMakeLists.txt b/src/lib/openjp2/CMakeLists.txt index fcf60ecf..500e905c 100644 --- a/src/lib/openjp2/CMakeLists.txt +++ b/src/lib/openjp2/CMakeLists.txt @@ -10,37 +10,69 @@ include_directories( # Defines the source code for the library set(OPENJPEG_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/bio.c + ${CMAKE_CURRENT_SOURCE_DIR}/bio.h ${CMAKE_CURRENT_SOURCE_DIR}/cio.c + ${CMAKE_CURRENT_SOURCE_DIR}/cio.h ${CMAKE_CURRENT_SOURCE_DIR}/dwt.c + ${CMAKE_CURRENT_SOURCE_DIR}/dwt.h ${CMAKE_CURRENT_SOURCE_DIR}/event.c + ${CMAKE_CURRENT_SOURCE_DIR}/event.h ${CMAKE_CURRENT_SOURCE_DIR}/image.c + ${CMAKE_CURRENT_SOURCE_DIR}/image.h ${CMAKE_CURRENT_SOURCE_DIR}/invert.c + ${CMAKE_CURRENT_SOURCE_DIR}/invert.h ${CMAKE_CURRENT_SOURCE_DIR}/j2k.c + ${CMAKE_CURRENT_SOURCE_DIR}/j2k.h ${CMAKE_CURRENT_SOURCE_DIR}/jp2.c + ${CMAKE_CURRENT_SOURCE_DIR}/jp2.h ${CMAKE_CURRENT_SOURCE_DIR}/mct.c + ${CMAKE_CURRENT_SOURCE_DIR}/mct.h ${CMAKE_CURRENT_SOURCE_DIR}/mqc.c + ${CMAKE_CURRENT_SOURCE_DIR}/mqc.h ${CMAKE_CURRENT_SOURCE_DIR}/openjpeg.c + ${CMAKE_CURRENT_SOURCE_DIR}/openjpeg.h ${CMAKE_CURRENT_SOURCE_DIR}/opj_clock.c + ${CMAKE_CURRENT_SOURCE_DIR}/opj_clock.h ${CMAKE_CURRENT_SOURCE_DIR}/pi.c + ${CMAKE_CURRENT_SOURCE_DIR}/pi.h ${CMAKE_CURRENT_SOURCE_DIR}/raw.c + ${CMAKE_CURRENT_SOURCE_DIR}/raw.h ${CMAKE_CURRENT_SOURCE_DIR}/t1.c + ${CMAKE_CURRENT_SOURCE_DIR}/t1.h ${CMAKE_CURRENT_SOURCE_DIR}/t2.c + ${CMAKE_CURRENT_SOURCE_DIR}/t2.h ${CMAKE_CURRENT_SOURCE_DIR}/tcd.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcd.h ${CMAKE_CURRENT_SOURCE_DIR}/tgt.c + ${CMAKE_CURRENT_SOURCE_DIR}/tgt.h ${CMAKE_CURRENT_SOURCE_DIR}/function_list.c + ${CMAKE_CURRENT_SOURCE_DIR}/function_list.h + ${CMAKE_CURRENT_SOURCE_DIR}/opj_codec.h + ${CMAKE_CURRENT_SOURCE_DIR}/opj_includes.h + ${CMAKE_CURRENT_SOURCE_DIR}/opj_intmath.h + ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c + ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h + ${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.h ) if(BUILD_JPIP) add_definitions(-DUSE_JPIP) set(OPENJPEG_SRCS ${OPENJPEG_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/cidx_manager.c + ${CMAKE_CURRENT_SOURCE_DIR}/cidx_manager.h ${CMAKE_CURRENT_SOURCE_DIR}/phix_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/ppix_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/thix_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/tpix_manager.c + ${CMAKE_CURRENT_SOURCE_DIR}/indexbox_manager.h ) endif() +option(OPJ_DISABLE_TPSOT_FIX "Disable TPsot==TNsot fix. See https://github.com/uclouvain/openjpeg/issues/254." OFF) +if(OPJ_DISABLE_TPSOT_FIX) + add_definitions(-DOPJ_DISABLE_TPSOT_FIX) +endif() + # Build the library if(WIN32) if(BUILD_SHARED_LIBS) @@ -54,6 +86,9 @@ if(UNIX) target_link_libraries(${OPENJPEG_LIBRARY_NAME} m) endif() set_target_properties(${OPENJPEG_LIBRARY_NAME} PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(${OPENJPEG_LIBRARY_NAME} PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS}) +endif() # Install library install(TARGETS ${OPENJPEG_LIBRARY_NAME} @@ -98,3 +133,12 @@ if(OPENJPEG_CPPCHECK) COMMAND ${CPPCHECK_EXECUTABLE} -DWIN32 ${f}) endforeach() endif() + +if(OPJ_USE_DSYMUTIL) + if(BUILD_SHARED_LIBS) + add_custom_command(TARGET ${OPENJPEG_LIBRARY_NAME} POST_BUILD + COMMAND "dsymutil" "$" + COMMENT "dsymutil $" + DEPENDS ${OPENJPEG_LIBRARY_NAME}) + endif() +endif() diff --git a/src/lib/openjp2/bio.c b/src/lib/openjp2/bio.c index 5d495801..e4edb372 100644 --- a/src/lib/openjp2/bio.c +++ b/src/lib/openjp2/bio.c @@ -78,27 +78,27 @@ static OPJ_BOOL opj_bio_bytein(opj_bio_t *bio); ========================================================== */ -OPJ_BOOL opj_bio_byteout(opj_bio_t *bio) { +static OPJ_BOOL opj_bio_byteout(opj_bio_t *bio) { bio->buf = (bio->buf << 8) & 0xffff; bio->ct = bio->buf == 0xff00 ? 7 : 8; - if (bio->bp >= bio->end) { + if ((OPJ_SIZE_T)bio->bp >= (OPJ_SIZE_T)bio->end) { return OPJ_FALSE; } *bio->bp++ = (OPJ_BYTE)(bio->buf >> 8); return OPJ_TRUE; } -OPJ_BOOL opj_bio_bytein(opj_bio_t *bio) { +static OPJ_BOOL opj_bio_bytein(opj_bio_t *bio) { bio->buf = (bio->buf << 8) & 0xffff; bio->ct = bio->buf == 0xff00 ? 7 : 8; - if (bio->bp >= bio->end) { + if ((OPJ_SIZE_T)bio->bp >= (OPJ_SIZE_T)bio->end) { return OPJ_FALSE; } bio->buf |= *bio->bp++; return OPJ_TRUE; } -void opj_bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { +static void opj_bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { if (bio->ct == 0) { opj_bio_byteout(bio); /* MSD: why not check the return value of this function ? */ } @@ -106,7 +106,7 @@ void opj_bio_putbit(opj_bio_t *bio, OPJ_UINT32 b) { bio->buf |= b << bio->ct; } -OPJ_UINT32 opj_bio_getbit(opj_bio_t *bio) { +static OPJ_UINT32 opj_bio_getbit(opj_bio_t *bio) { if (bio->ct == 0) { opj_bio_bytein(bio); /* MSD: why not check the return value of this function ? */ } @@ -169,12 +169,10 @@ OPJ_UINT32 opj_bio_read(opj_bio_t *bio, OPJ_UINT32 n) { } OPJ_BOOL opj_bio_flush(opj_bio_t *bio) { - bio->ct = 0; if (! opj_bio_byteout(bio)) { return OPJ_FALSE; } if (bio->ct == 7) { - bio->ct = 0; if (! opj_bio_byteout(bio)) { return OPJ_FALSE; } @@ -183,12 +181,11 @@ OPJ_BOOL opj_bio_flush(opj_bio_t *bio) { } OPJ_BOOL opj_bio_inalign(opj_bio_t *bio) { - bio->ct = 0; if ((bio->buf & 0xff) == 0xff) { if (! opj_bio_bytein(bio)) { return OPJ_FALSE; } - bio->ct = 0; } + bio->ct = 0; return OPJ_TRUE; } diff --git a/src/lib/openjp2/cio.c b/src/lib/openjp2/cio.c index 1fc23937..b115cf52 100644 --- a/src/lib/openjp2/cio.c +++ b/src/lib/openjp2/cio.c @@ -46,7 +46,7 @@ void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes) { - const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value) + p_nb_bytes; + const OPJ_BYTE * l_data_ptr = ((const OPJ_BYTE *) &p_value)+sizeof(OPJ_UINT32)-p_nb_bytes; assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); @@ -72,7 +72,7 @@ void opj_read_bytes_BE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT assert(p_nb_bytes > 0 && p_nb_bytes <= sizeof(OPJ_UINT32)); *p_value = 0; - memcpy(l_data_ptr+4-p_nb_bytes,p_buffer,p_nb_bytes); + memcpy(l_data_ptr+sizeof(OPJ_UINT32)-p_nb_bytes,p_buffer,p_nb_bytes); } void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes) @@ -151,12 +151,11 @@ void opj_read_float_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value) opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size,OPJ_BOOL l_is_input) { opj_stream_private_t * l_stream = 00; - l_stream = (opj_stream_private_t*) opj_malloc(sizeof(opj_stream_private_t)); + l_stream = (opj_stream_private_t*) opj_calloc(1,sizeof(opj_stream_private_t)); if (! l_stream) { return 00; } - memset(l_stream,0,sizeof(opj_stream_private_t)); l_stream->m_buffer_size = p_buffer_size; l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_buffer_size); if (! l_stream->m_stored_data) { @@ -167,12 +166,12 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size,OPJ_BOOL l l_stream->m_current_data = l_stream->m_stored_data; if (l_is_input) { - l_stream->m_status |= opj_stream_e_input; + l_stream->m_status |= OPJ_STREAM_STATUS_INPUT; l_stream->m_opj_skip = opj_stream_read_skip; l_stream->m_opj_seek = opj_stream_read_seek; } else { - l_stream->m_status |= opj_stream_e_output; + l_stream->m_status |= OPJ_STREAM_STATUS_OUTPUT; l_stream->m_opj_skip = opj_stream_write_skip; l_stream->m_opj_seek = opj_stream_write_seek; } @@ -208,7 +207,7 @@ void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_strea { opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; - if ((!l_stream) || (! (l_stream->m_status & opj_stream_e_input))) { + if ((!l_stream) || (! (l_stream->m_status & OPJ_STREAM_STATUS_INPUT))) { return; } @@ -229,7 +228,7 @@ void OPJ_CALLCONV opj_stream_set_write_function(opj_stream_t* p_stream, opj_stre { opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; - if ((!l_stream )|| (! (l_stream->m_status & opj_stream_e_output))) { + if ((!l_stream )|| (! (l_stream->m_status & OPJ_STREAM_STATUS_OUTPUT))) { return; } @@ -277,7 +276,7 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu } /* we are now in the case when the remaining data if not sufficient */ - if (p_stream->m_status & opj_stream_e_end) { + if (p_stream->m_status & OPJ_STREAM_STATUS_END) { l_read_nb_bytes += p_stream->m_bytes_in_buffer; memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); p_stream->m_current_data += p_stream->m_bytes_in_buffer; @@ -303,7 +302,7 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu p_stream->m_current_data = p_stream->m_stored_data; } - while(1){ + for (;;) { /* we should read less than a chunk -> read a chunk */ if (p_size < p_stream->m_buffer_size) { /* we should do an actual read on the media */ @@ -314,7 +313,7 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); p_stream->m_bytes_in_buffer = 0; - p_stream->m_status |= opj_stream_e_end; + p_stream->m_status |= OPJ_STREAM_STATUS_END; /* end of stream */ return l_read_nb_bytes ? l_read_nb_bytes : (OPJ_SIZE_T)-1; } @@ -346,7 +345,7 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); p_stream->m_bytes_in_buffer = 0; - p_stream->m_status |= opj_stream_e_end; + p_stream->m_status |= OPJ_STREAM_STATUS_END; /* end of stream */ return l_read_nb_bytes ? l_read_nb_bytes : (OPJ_SIZE_T)-1; } @@ -379,11 +378,11 @@ OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream, OPJ_SIZE_T l_remaining_bytes = 0; OPJ_SIZE_T l_write_nb_bytes = 0; - if (p_stream->m_status & opj_stream_e_error) { + if (p_stream->m_status & OPJ_STREAM_STATUS_ERROR) { return (OPJ_SIZE_T)-1; } - while(1) { + for (;;) { l_remaining_bytes = p_stream->m_buffer_size - p_stream->m_bytes_in_buffer; /* we have more memory than required */ @@ -433,7 +432,7 @@ OPJ_BOOL opj_stream_flush (opj_stream_private_t * p_stream, opj_event_mgr_t * p_ p_stream->m_user_data); if (l_current_write_nb_bytes == (OPJ_SIZE_T)-1) { - p_stream->m_status |= opj_stream_e_error; + p_stream->m_status |= OPJ_STREAM_STATUS_ERROR; opj_event_msg(p_event_mgr, EVT_INFO, "Error on writing stream!\n"); return OPJ_FALSE; @@ -466,7 +465,7 @@ OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_siz } /* we are now in the case when the remaining data if not sufficient */ - if (p_stream->m_status & opj_stream_e_end) { + if (p_stream->m_status & OPJ_STREAM_STATUS_END) { l_skip_nb_bytes += (OPJ_OFF_T)p_stream->m_bytes_in_buffer; p_stream->m_current_data += p_stream->m_bytes_in_buffer; p_stream->m_bytes_in_buffer = 0; @@ -488,7 +487,7 @@ OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_siz if (l_current_skip_nb_bytes == (OPJ_OFF_T) -1) { opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); - p_stream->m_status |= opj_stream_e_end; + p_stream->m_status |= OPJ_STREAM_STATUS_END; p_stream->m_byte_offset += l_skip_nb_bytes; /* end if stream */ return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_OFF_T) -1; @@ -508,14 +507,14 @@ OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_si OPJ_OFF_T l_current_skip_nb_bytes = 0; OPJ_OFF_T l_skip_nb_bytes = 0; - if (p_stream->m_status & opj_stream_e_error) { + if (p_stream->m_status & OPJ_STREAM_STATUS_ERROR) { return (OPJ_OFF_T) -1; } /* we should flush data */ l_is_written = opj_stream_flush (p_stream, p_event_mgr); if (! l_is_written) { - p_stream->m_status |= opj_stream_e_error; + p_stream->m_status |= OPJ_STREAM_STATUS_ERROR; p_stream->m_bytes_in_buffer = 0; return (OPJ_OFF_T) -1; } @@ -528,7 +527,7 @@ OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_si if (l_current_skip_nb_bytes == (OPJ_OFF_T)-1) { opj_event_msg(p_event_mgr, EVT_INFO, "Stream error!\n"); - p_stream->m_status |= opj_stream_e_error; + p_stream->m_status |= OPJ_STREAM_STATUS_ERROR; p_stream->m_byte_offset += l_skip_nb_bytes; /* end if stream */ return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_OFF_T)-1; @@ -569,12 +568,12 @@ OPJ_BOOL opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size p_stream->m_bytes_in_buffer = 0; if( !(p_stream->m_seek_fn(p_size,p_stream->m_user_data)) ) { - p_stream->m_status |= opj_stream_e_end; + p_stream->m_status |= OPJ_STREAM_STATUS_END; return OPJ_FALSE; } else { /* reset stream status */ - p_stream->m_status &= (~opj_stream_e_end); + p_stream->m_status &= (~OPJ_STREAM_STATUS_END); p_stream->m_byte_offset = p_size; } @@ -585,7 +584,7 @@ OPJ_BOOL opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size OPJ_BOOL opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { if (! opj_stream_flush(p_stream,p_event_mgr)) { - p_stream->m_status |= opj_stream_e_error; + p_stream->m_status |= OPJ_STREAM_STATUS_ERROR; return OPJ_FALSE; } @@ -593,7 +592,7 @@ OPJ_BOOL opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_siz p_stream->m_bytes_in_buffer = 0; if (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) { - p_stream->m_status |= opj_stream_e_error; + p_stream->m_status |= OPJ_STREAM_STATUS_ERROR; return OPJ_FALSE; } else { diff --git a/src/lib/openjp2/cio.h b/src/lib/openjp2/cio.h index 6dfa5bb8..4ea03ff3 100644 --- a/src/lib/openjp2/cio.h +++ b/src/lib/openjp2/cio.h @@ -70,16 +70,10 @@ The functions in CIO.C have for goal to realize a byte input / output process. #endif - -typedef enum -{ - opj_signed_sentinel = -1, /* do not use in code */ - opj_stream_e_output = 0x1, - opj_stream_e_input = 0x2, - opj_stream_e_end = 0x4, - opj_stream_e_error = 0x8 -} -opj_stream_flag ; +#define OPJ_STREAM_STATUS_OUTPUT 0x1U +#define OPJ_STREAM_STATUS_INPUT 0x2U +#define OPJ_STREAM_STATUS_END 0x4U +#define OPJ_STREAM_STATUS_ERROR 0x8U /** Byte input-output stream. @@ -162,8 +156,9 @@ typedef struct opj_stream_private /** * Flags to tell the status of the stream. + * Used with OPJ_STREAM_STATUS_* defines. */ - opj_stream_flag m_status; + OPJ_UINT32 m_status; } opj_stream_private_t; @@ -184,7 +179,7 @@ void opj_write_bytes_BE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_n * @param p_buffer pointer the data buffer to read data from. * @param p_value pointer to the value that will store the data. * @param p_nb_bytes the nb bytes to read. - * @return the number of bytes read or -1 if an error occured. + * @return the number of bytes read or -1 if an error occurred. */ void opj_read_bytes_BE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); @@ -193,7 +188,7 @@ void opj_read_bytes_BE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT * @param p_buffer pointer the data buffer to write data to. * @param p_value the value to write * @param p_nb_bytes the number of bytes to write - * @return the number of bytes written or -1 if an error occured + * @return the number of bytes written or -1 if an error occurred */ void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_nb_bytes); @@ -202,7 +197,7 @@ void opj_write_bytes_LE (OPJ_BYTE * p_buffer, OPJ_UINT32 p_value, OPJ_UINT32 p_n * @param p_buffer pointer the data buffer to read data from. * @param p_value pointer to the value that will store the data. * @param p_nb_bytes the nb bytes to read. - * @return the number of bytes read or -1 if an error occured. + * @return the number of bytes read or -1 if an error occurred. */ void opj_read_bytes_LE(const OPJ_BYTE * p_buffer, OPJ_UINT32 * p_value, OPJ_UINT32 p_nb_bytes); @@ -269,7 +264,7 @@ void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); * @param p_buffer pointer to the data buffer that will receive the data. * @param p_size number of bytes to read. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. + * @return the number of bytes read, or -1 if an error occurred or if the stream is at the end. */ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); @@ -279,7 +274,7 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu * @param p_buffer pointer to the data buffer holds the data to be writtent. * @param p_size number of bytes to write. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes writtent, or -1 if an error occured. + * @return the number of bytes writtent, or -1 if an error occurred. */ OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); @@ -296,7 +291,7 @@ OPJ_BOOL opj_stream_flush (opj_stream_private_t * p_stream, struct opj_event_mgr * @param p_stream the stream to skip data from. * @param p_size the number of bytes to skip. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes skipped, or -1 if an error occured. + * @return the number of bytes skipped, or -1 if an error occurred. */ OPJ_OFF_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); @@ -324,7 +319,7 @@ OPJ_OFF_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_stream * @param p_stream the stream to skip data from. * @param p_size the number of bytes to skip. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes skipped, or -1 if an error occured. + * @return the number of bytes skipped, or -1 if an error occurred. */ OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); @@ -333,7 +328,7 @@ OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_si * @param p_stream the stream to skip data from. * @param p_size the number of bytes to skip. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes skipped, or -1 if an error occured. + * @return the number of bytes skipped, or -1 if an error occurred. */ OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); @@ -342,7 +337,7 @@ OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_siz * @param p_stream the stream to skip data from. * @param p_size the number of bytes to skip. * @param p_event_mgr the user event manager to be notified of special events. - * @return OPJ_TRUE if success, or OPJ_FALSE if an error occured. + * @return OPJ_TRUE if success, or OPJ_FALSE if an error occurred. */ OPJ_BOOL opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); @@ -351,7 +346,7 @@ OPJ_BOOL opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size * @param p_stream the stream to skip data from. * @param p_size the number of bytes to skip. * @param p_event_mgr the user event manager to be notified of special events. - * @return the number of bytes skipped, or -1 if an error occured. + * @return the number of bytes skipped, or -1 if an error occurred. */ OPJ_BOOL opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); diff --git a/src/lib/openjp2/dwt.c b/src/lib/openjp2/dwt.c index e1f8a337..a4ff01ba 100644 --- a/src/lib/openjp2/dwt.c +++ b/src/lib/openjp2/dwt.c @@ -193,7 +193,7 @@ static const OPJ_FLOAT64 opj_dwt_norms_real[4][10] = { /* */ /* Forward lazy transform (horizontal). */ /* */ -void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { +static void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { OPJ_INT32 i; OPJ_INT32 * l_dest = b; OPJ_INT32 * l_src = a+cas; @@ -215,7 +215,7 @@ void opj_dwt_deinterleave_h(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 /* */ /* Forward lazy transform (vertical). */ /* */ -void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas) { +static void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 x, OPJ_INT32 cas) { OPJ_INT32 i = sn; OPJ_INT32 * l_dest = b; OPJ_INT32 * l_src = a+cas; @@ -240,7 +240,7 @@ void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, OPJ_INT32 /* */ /* Inverse lazy transform (horizontal). */ /* */ -void opj_dwt_interleave_h(opj_dwt_t* h, OPJ_INT32 *a) { +static void opj_dwt_interleave_h(opj_dwt_t* h, OPJ_INT32 *a) { OPJ_INT32 *ai = a; OPJ_INT32 *bi = h->mem + h->cas; OPJ_INT32 i = h->sn; @@ -260,7 +260,7 @@ void opj_dwt_interleave_h(opj_dwt_t* h, OPJ_INT32 *a) { /* */ /* Inverse lazy transform (vertical). */ /* */ -void opj_dwt_interleave_v(opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) { +static void opj_dwt_interleave_v(opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) { OPJ_INT32 *ai = a; OPJ_INT32 *bi = v->mem + v->cas; OPJ_INT32 i = v->sn; @@ -283,7 +283,7 @@ void opj_dwt_interleave_v(opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) { /* */ /* Forward 5-3 wavelet transform in 1-D. */ /* */ -void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { +static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { OPJ_INT32 i; if (!cas) { @@ -304,7 +304,7 @@ void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { /* */ /* Inverse 5-3 wavelet transform in 1-D. */ /* */ -void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { +static void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { OPJ_INT32 i; if (!cas) { @@ -325,14 +325,14 @@ void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) /* */ /* Inverse 5-3 wavelet transform in 1-D. */ /* */ -void opj_dwt_decode_1(opj_dwt_t *v) { +static void opj_dwt_decode_1(opj_dwt_t *v) { opj_dwt_decode_1_(v->mem, v->dn, v->sn, v->cas); } /* */ /* Forward 9-7 wavelet transform in 1-D. */ /* */ -void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { +static void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas) { OPJ_INT32 i; if (!cas) { if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ @@ -367,7 +367,7 @@ void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 c } } -void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize) { +static void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_t *bandno_stepsize) { OPJ_INT32 p, n; p = opj_int_floorlog2(stepsize) - 13; n = 11 - opj_int_floorlog2(stepsize); @@ -385,7 +385,7 @@ void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, opj_stepsize_ /* */ /* Forward 5-3 wavelet transform in 2-D. */ /* */ -INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ) +static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_function)(OPJ_INT32 *, OPJ_INT32,OPJ_INT32,OPJ_INT32) ) { OPJ_INT32 i, j, k; OPJ_INT32 *a = 00; @@ -409,7 +409,9 @@ INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec,void (*p_fun l_data_size = opj_dwt_max_resolution( tilec->resolutions,tilec->numresolutions) * (OPJ_UINT32)sizeof(OPJ_INT32); bj = (OPJ_INT32*)opj_malloc((size_t)l_data_size); - if (! bj) { + /* l_data_size is equal to 0 when numresolutions == 1 but bj is not used */ + /* in that case, so do not error out */ + if (l_data_size != 0 && ! bj) { return OPJ_FALSE; } i = l; @@ -541,7 +543,7 @@ void opj_dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, OPJ_UINT32 prec) { /* */ /* Determine maximum computed resolution level for inverse wavelet transform */ /* */ -OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i) { +static OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i) { OPJ_UINT32 mr = 0; OPJ_UINT32 w; while( --i ) { @@ -557,7 +559,7 @@ OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* restrict r, OPJ_UINT32 i /* */ /* Inverse wavelet transform in 2-D. */ /* */ -OPJ_BOOL opj_dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1DFN dwt_1D) { +static OPJ_BOOL opj_dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1DFN dwt_1D) { opj_dwt_t h; opj_dwt_t v; @@ -567,10 +569,13 @@ OPJ_BOOL opj_dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1D OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - tr->y0); /* height of the resolution level computed */ OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0); - - h.mem = (OPJ_INT32*) - opj_aligned_malloc(opj_dwt_max_resolution(tr, numres) * sizeof(OPJ_INT32)); + + if (numres == 1U) { + return OPJ_TRUE; + } + h.mem = (OPJ_INT32*)opj_aligned_malloc(opj_dwt_max_resolution(tr, numres) * sizeof(OPJ_INT32)); if (! h.mem){ + /* FIXME event manager error callback */ return OPJ_FALSE; } @@ -612,7 +617,7 @@ OPJ_BOOL opj_dwt_decode_tile(opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres, DWT1D return OPJ_TRUE; } -void opj_v4dwt_interleave_h(opj_v4dwt_t* restrict w, OPJ_FLOAT32* restrict a, OPJ_INT32 x, OPJ_INT32 size){ +static void opj_v4dwt_interleave_h(opj_v4dwt_t* restrict w, OPJ_FLOAT32* restrict a, OPJ_INT32 x, OPJ_INT32 size){ OPJ_FLOAT32* restrict bi = (OPJ_FLOAT32*) (w->wavelet + w->cas); OPJ_INT32 count = w->sn; OPJ_INT32 i, k; @@ -655,7 +660,7 @@ void opj_v4dwt_interleave_h(opj_v4dwt_t* restrict w, OPJ_FLOAT32* restrict a, OP } } -void opj_v4dwt_interleave_v(opj_v4dwt_t* restrict v , OPJ_FLOAT32* restrict a , OPJ_INT32 x, OPJ_INT32 nb_elts_read){ +static void opj_v4dwt_interleave_v(opj_v4dwt_t* restrict v , OPJ_FLOAT32* restrict a , OPJ_INT32 x, OPJ_INT32 nb_elts_read){ opj_v4_t* restrict bi = v->wavelet + v->cas; OPJ_INT32 i; @@ -673,7 +678,7 @@ void opj_v4dwt_interleave_v(opj_v4dwt_t* restrict v , OPJ_FLOAT32* restrict a , #ifdef __SSE__ -void opj_v4dwt_decode_step1_sse(opj_v4_t* w, OPJ_INT32 count, const __m128 c){ +static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, OPJ_INT32 count, const __m128 c){ __m128* restrict vw = (__m128*) w; OPJ_INT32 i; /* 4x unrolled loop */ @@ -722,7 +727,7 @@ void opj_v4dwt_decode_step2_sse(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, OPJ_INT32 #else -void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, const OPJ_FLOAT32 c) +static void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, const OPJ_FLOAT32 c) { OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; OPJ_INT32 i; @@ -738,10 +743,10 @@ void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, const OPJ_FLOAT32 c) } } -void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, OPJ_INT32 m, OPJ_FLOAT32 c) +static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, OPJ_INT32 m, OPJ_FLOAT32 c) { - OPJ_FLOAT32* restrict fl = (OPJ_FLOAT32*) l; - OPJ_FLOAT32* restrict fw = (OPJ_FLOAT32*) w; + OPJ_FLOAT32* fl = (OPJ_FLOAT32*) l; + OPJ_FLOAT32* fw = (OPJ_FLOAT32*) w; OPJ_INT32 i; for(i = 0; i < m; ++i){ OPJ_FLOAT32 tmp1_1 = fl[0]; @@ -792,7 +797,7 @@ void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, OPJ_INT32 m, /* */ /* Inverse 9-7 wavelet transform in 1-D. */ /* */ -void opj_v4dwt_decode(opj_v4dwt_t* restrict dwt) +static void opj_v4dwt_decode(opj_v4dwt_t* restrict dwt) { OPJ_INT32 a, b; if(dwt->cas == 0) { @@ -842,6 +847,10 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, OPJ_UINT32 numr OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0); h.wavelet = (opj_v4_t*) opj_aligned_malloc((opj_dwt_max_resolution(res, numres)+5) * sizeof(opj_v4_t)); + if (!h.wavelet) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } v.wavelet = h.wavelet; while( --numres) { diff --git a/src/lib/openjp2/dwt.h b/src/lib/openjp2/dwt.h index f8b57bc0..21fe942a 100644 --- a/src/lib/openjp2/dwt.h +++ b/src/lib/openjp2/dwt.h @@ -54,14 +54,14 @@ DWT.C are used by some function in TCD.C. /*@{*/ /* ----------------------------------------------------------------------- */ /** -Forward 5-3 wavelet tranform in 2-D. +Forward 5-3 wavelet transform in 2-D. Apply a reversible DWT transform to a component of an image. @param tilec Tile component information (current tile) */ OPJ_BOOL opj_dwt_encode(opj_tcd_tilecomp_t * tilec); /** -Inverse 5-3 wavelet tranform in 2-D. +Inverse 5-3 wavelet transform in 2-D. Apply a reversible inverse DWT transform to a component of an image. @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode diff --git a/src/lib/openjp2/event.h b/src/lib/openjp2/event.h index 88e0395b..fa8604ed 100644 --- a/src/lib/openjp2/event.h +++ b/src/lib/openjp2/event.h @@ -95,6 +95,12 @@ OPJ_BOOL opj_event_msg(opj_event_mgr_t* event_mgr, OPJ_INT32 event_type, const c */ void opj_set_default_event_handler(opj_event_mgr_t * p_manager); +/* +#ifdef __GNUC__ +#pragma GCC poison printf fprintf +#endif +*/ + /*@}*/ /*@}*/ diff --git a/src/lib/openjp2/function_list.c b/src/lib/openjp2/function_list.c index 4c8aae62..a7ea11d5 100644 --- a/src/lib/openjp2/function_list.c +++ b/src/lib/openjp2/function_list.c @@ -39,22 +39,19 @@ opj_procedure_list_t * opj_procedure_list_create() { /* memory allocation */ - opj_procedure_list_t * l_validation = (opj_procedure_list_t *) opj_malloc(sizeof(opj_procedure_list_t)); + opj_procedure_list_t * l_validation = (opj_procedure_list_t *) opj_calloc(1,sizeof(opj_procedure_list_t)); if (! l_validation) { return 00; } /* initialization */ - memset(l_validation,0,sizeof(opj_procedure_list_t)); l_validation->m_nb_max_procedures = OPJ_VALIDATION_SIZE; - l_validation->m_procedures = (opj_procedure*)opj_malloc( - OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); + l_validation->m_procedures = (opj_procedure*)opj_calloc(OPJ_VALIDATION_SIZE, sizeof(opj_procedure)); if (! l_validation->m_procedures) { opj_free(l_validation); return 00; } - memset(l_validation->m_procedures,0,OPJ_VALIDATION_SIZE * sizeof(opj_procedure)); return l_validation; } @@ -72,8 +69,11 @@ void opj_procedure_list_destroy(opj_procedure_list_t * p_list) opj_free(p_list); } -OPJ_BOOL opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure) +OPJ_BOOL opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure, opj_event_mgr_t* p_manager ) { + + assert(p_manager != NULL); + if (p_validation_list->m_nb_max_procedures == p_validation_list->m_nb_procedures) { opj_procedure * new_procedures; @@ -87,9 +87,7 @@ OPJ_BOOL opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_l opj_free(p_validation_list->m_procedures); p_validation_list->m_nb_max_procedures = 0; p_validation_list->m_nb_procedures = 0; - /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to add a new validation procedure\n"); */ - fprintf(stderr, "Not enough memory to add a new validation procedure\n"); - + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to add a new validation procedure\n"); return OPJ_FALSE; } else diff --git a/src/lib/openjp2/function_list.h b/src/lib/openjp2/function_list.h index 749ad9e4..ab091b7b 100644 --- a/src/lib/openjp2/function_list.h +++ b/src/lib/openjp2/function_list.h @@ -95,7 +95,7 @@ void opj_procedure_list_destroy(opj_procedure_list_t * p_list); * * @return OPJ_TRUE if the procedure could be added. */ -OPJ_BOOL opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure); +OPJ_BOOL opj_procedure_list_add_procedure (opj_procedure_list_t * p_validation_list, opj_procedure p_procedure, opj_event_mgr_t* p_manager); /** * Gets the number of validation procedures. diff --git a/src/lib/openjp2/image.c b/src/lib/openjp2/image.c index 2c3540c5..23462f05 100644 --- a/src/lib/openjp2/image.c +++ b/src/lib/openjp2/image.c @@ -47,7 +47,8 @@ opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptpa /* allocate memory for the per-component information */ image->comps = (opj_image_comp_t*)opj_calloc(1,image->numcomps * sizeof(opj_image_comp_t)); if(!image->comps) { - fprintf(stderr,"Unable to allocate memory for image.\n"); + /* TODO replace with event manager, breaks API */ + /* fprintf(stderr,"Unable to allocate memory for image.\n"); */ opj_image_destroy(image); return NULL; } @@ -65,7 +66,8 @@ opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptpa comp->sgnd = cmptparms[compno].sgnd; comp->data = (OPJ_INT32*) opj_calloc(comp->w * comp->h, sizeof(OPJ_INT32)); if(!comp->data) { - fprintf(stderr,"Unable to allocate memory for image.\n"); + /* TODO replace with event manager, breaks API */ + /* fprintf(stderr,"Unable to allocate memory for image.\n"); */ opj_image_destroy(image); return NULL; } @@ -107,27 +109,29 @@ void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) { void opj_image_comp_header_update(opj_image_t * p_image_header, const struct opj_cp * p_cp) { OPJ_UINT32 i, l_width, l_height; - OPJ_INT32 l_x0, l_y0, l_x1, l_y1; - OPJ_INT32 l_comp_x0, l_comp_y0, l_comp_x1, l_comp_y1; + OPJ_UINT32 l_x0, l_y0, l_x1, l_y1; + OPJ_UINT32 l_comp_x0, l_comp_y0, l_comp_x1, l_comp_y1; opj_image_comp_t* l_img_comp = NULL; - l_x0 = opj_int_max((OPJ_INT32)p_cp->tx0 , (OPJ_INT32)p_image_header->x0); - l_y0 = opj_int_max((OPJ_INT32)p_cp->ty0 , (OPJ_INT32)p_image_header->y0); - l_x1 = opj_int_min((OPJ_INT32)(p_cp->tx0 + p_cp->tw * p_cp->tdx), (OPJ_INT32)p_image_header->x1); - l_y1 = opj_int_min((OPJ_INT32)(p_cp->ty0 + p_cp->th * p_cp->tdy), (OPJ_INT32)p_image_header->y1); + l_x0 = opj_uint_max(p_cp->tx0 , p_image_header->x0); + l_y0 = opj_uint_max(p_cp->ty0 , p_image_header->y0); + l_x1 = p_cp->tx0 + (p_cp->tw - 1U) * p_cp->tdx; /* validity of p_cp members used here checked in opj_j2k_read_siz. Can't overflow. */ + l_y1 = p_cp->ty0 + (p_cp->th - 1U) * p_cp->tdy; /* can't overflow */ + l_x1 = opj_uint_min(opj_uint_adds(l_x1, p_cp->tdx), p_image_header->x1); /* use add saturated to prevent overflow */ + l_y1 = opj_uint_min(opj_uint_adds(l_y1, p_cp->tdy), p_image_header->y1); /* use add saturated to prevent overflow */ l_img_comp = p_image_header->comps; for (i = 0; i < p_image_header->numcomps; ++i) { - l_comp_x0 = opj_int_ceildiv(l_x0, (OPJ_INT32)l_img_comp->dx); - l_comp_y0 = opj_int_ceildiv(l_y0, (OPJ_INT32)l_img_comp->dy); - l_comp_x1 = opj_int_ceildiv(l_x1, (OPJ_INT32)l_img_comp->dx); - l_comp_y1 = opj_int_ceildiv(l_y1, (OPJ_INT32)l_img_comp->dy); - l_width = (OPJ_UINT32)opj_int_ceildivpow2(l_comp_x1 - l_comp_x0, (OPJ_INT32)l_img_comp->factor); - l_height = (OPJ_UINT32)opj_int_ceildivpow2(l_comp_y1 - l_comp_y0, (OPJ_INT32)l_img_comp->factor); + l_comp_x0 = opj_uint_ceildiv(l_x0, l_img_comp->dx); + l_comp_y0 = opj_uint_ceildiv(l_y0, l_img_comp->dy); + l_comp_x1 = opj_uint_ceildiv(l_x1, l_img_comp->dx); + l_comp_y1 = opj_uint_ceildiv(l_y1, l_img_comp->dy); + l_width = opj_uint_ceildivpow2(l_comp_x1 - l_comp_x0, l_img_comp->factor); + l_height = opj_uint_ceildivpow2(l_comp_y1 - l_comp_y0, l_img_comp->factor); l_img_comp->w = l_width; l_img_comp->h = l_height; - l_img_comp->x0 = (OPJ_UINT32)l_comp_x0/*l_x0*/; - l_img_comp->y0 = (OPJ_UINT32)l_comp_y0/*l_y0*/; + l_img_comp->x0 = l_comp_x0; + l_img_comp->y0 = l_comp_y0; ++l_img_comp; } } @@ -205,21 +209,19 @@ opj_image_t* OPJ_CALLCONV opj_image_tile_create(OPJ_UINT32 numcmpts, opj_image_c OPJ_UINT32 compno; opj_image_t *image = 00; - image = (opj_image_t*) opj_malloc(sizeof(opj_image_t)); + image = (opj_image_t*) opj_calloc(1,sizeof(opj_image_t)); if (image) { - memset(image,0,sizeof(opj_image_t)); image->color_space = clrspc; image->numcomps = numcmpts; /* allocate memory for the per-component information */ - image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t)); + image->comps = (opj_image_comp_t*)opj_calloc(image->numcomps, sizeof(opj_image_comp_t)); if (!image->comps) { opj_image_destroy(image); return 00; } - memset(image->comps,0,image->numcomps * sizeof(opj_image_comp_t)); /* create the individual image components */ for(compno = 0; compno < numcmpts; compno++) { diff --git a/src/lib/openjp2/indexbox_manager.h b/src/lib/openjp2/indexbox_manager.h index ec5525f5..ebcde8fe 100644 --- a/src/lib/openjp2/indexbox_manager.h +++ b/src/lib/openjp2/indexbox_manager.h @@ -108,7 +108,7 @@ int opj_write_phix( int coff, opj_codestream_info_t cstr_info, OPJ_BOOL EPHused, opj_event_mgr_t * p_manager ); /* - * Wriet manifest box (box) + * Write manifest box (box) * * @param[in] second number to be visited * @param[in] v number of boxes diff --git a/src/lib/openjp2/invert.c b/src/lib/openjp2/invert.c index 4c1ee780..7efaf6ec 100644 --- a/src/lib/openjp2/invert.c +++ b/src/lib/openjp2/invert.c @@ -103,7 +103,7 @@ OPJ_BOOL opj_matrix_inversion_f(OPJ_FLOAT32 * pSrcMatrix, Local functions ========================================================== */ -OPJ_BOOL opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, +static OPJ_BOOL opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, OPJ_FLOAT32 * p_swap_area, OPJ_UINT32 nb_compo) { @@ -125,7 +125,7 @@ OPJ_BOOL opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, { *tmpPermutations++ = i; } - /* now make a pivot with colum switch */ + /* now make a pivot with column switch */ tmpPermutations = permutations; for (k = 0; k < lLastColum; ++k) { p = 0.0; @@ -204,7 +204,7 @@ OPJ_BOOL opj_lupDecompose(OPJ_FLOAT32 * matrix,OPJ_UINT32 * permutations, return OPJ_TRUE; } -void opj_lupSolve (OPJ_FLOAT32 * pResult, +static void opj_lupSolve (OPJ_FLOAT32 * pResult, OPJ_FLOAT32 * pMatrix, OPJ_FLOAT32 * pVector, OPJ_UINT32* pPermutations, @@ -266,7 +266,7 @@ void opj_lupSolve (OPJ_FLOAT32 * pResult, } -void opj_lupInvert (OPJ_FLOAT32 * pSrcMatrix, +static void opj_lupInvert (OPJ_FLOAT32 * pSrcMatrix, OPJ_FLOAT32 * pDestMatrix, OPJ_UINT32 nb_compo, OPJ_UINT32 * pPermutations, diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 881cc72c..f0e565ea 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -51,7 +51,7 @@ /** * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. */ -static void opj_j2k_setup_header_reading (opj_j2k_t *p_j2k); +static OPJ_BOOL opj_j2k_setup_header_reading (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager); /** * The read header procedure. @@ -90,19 +90,19 @@ static OPJ_BOOL opj_j2k_decoding_validation ( opj_j2k_t * p_j2k, * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k); +static OPJ_BOOL opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager); /** * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k); +static OPJ_BOOL opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager); /** * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_j2k_setup_end_compress (opj_j2k_t *p_j2k); +static OPJ_BOOL opj_j2k_setup_end_compress (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager); /** * The mct encoding validation procedure. @@ -212,6 +212,18 @@ static void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp); */ static void opj_j2k_cp_destroy (opj_cp_t *p_cp); +/** + * Compare 2 a SPCod/ SPCoc elements, i.e. the coding style of a given component of a tile. + * + * @param p_j2k J2K codec. + * @param p_tile_no Tile number + * @param p_first_comp_no The 1st component number to compare. + * @param p_second_comp_no The 1st component number to compare. + * + * @return OPJ_TRUE if SPCdod are equals. + */ +static OPJ_BOOL opj_j2k_compare_SPCod_SPCoc(opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no); + /** * Writes a SPCod or SPCoc element, i.e. the coding style of a given component of a tile. * @@ -271,6 +283,19 @@ static OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no ); +/** + * Compares 2 SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. + * + * @param p_j2k J2K codec. + * @param p_tile_no the tile to output. + * @param p_first_comp_no the first component number to compare. + * @param p_second_comp_no the second component number to compare. + * + * @return OPJ_TRUE if equals. + */ +static OPJ_BOOL opj_j2k_compare_SQcd_SQcc(opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no); + + /** * Writes a SQcd or SQcc element, i.e. the quantization values of a band in the QCD or QCC. * @@ -338,11 +363,21 @@ static OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image); +static void opj_get_tile_dimensions(opj_image_t * l_image, + opj_tcd_tilecomp_t * l_tilec, + opj_image_comp_t * l_img_comp, + OPJ_UINT32* l_size_comp, + OPJ_UINT32* l_width, + OPJ_UINT32* l_height, + OPJ_UINT32* l_offset_x, + OPJ_UINT32* l_offset_y, + OPJ_UINT32* l_image_width, + OPJ_UINT32* l_stride, + OPJ_UINT32* l_tile_offset); + static void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data); static OPJ_BOOL opj_j2k_post_write_tile (opj_j2k_t * p_j2k, - OPJ_BYTE * p_data, - OPJ_UINT32 p_data_size, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); @@ -350,7 +385,7 @@ static OPJ_BOOL opj_j2k_post_write_tile (opj_j2k_t * p_j2k, * Sets up the procedures to do on writing header. * Developers wanting to extend the library can add their own writing procedures. */ -static void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k); +static OPJ_BOOL opj_j2k_setup_header_writing (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager); static OPJ_BOOL opj_j2k_write_first_tile_part( opj_j2k_t *p_j2k, OPJ_BYTE * p_data, @@ -474,7 +509,17 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager); -#if 0 +/** + * Compares 2 COC markers (Coding style component) + * + * @param p_j2k J2K codec. + * @param p_first_comp_no the index of the first component to compare. + * @param p_second_comp_no the index of the second component to compare. + * + * @return OPJ_TRUE if equals + */ +static OPJ_BOOL opj_j2k_compare_coc(opj_j2k_t *p_j2k, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no); + /** * Writes the COC marker (Coding style component) * @@ -487,9 +532,7 @@ static OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); -#endif -#if 0 /** * Writes the COC marker (Coding style component) * @@ -504,7 +547,6 @@ static void opj_j2k_write_coc_in_memory(opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, opj_event_mgr_t * p_manager ); -#endif /** * Gets the maximum size taken by a coc. @@ -547,7 +589,18 @@ static OPJ_BOOL opj_j2k_read_qcd ( opj_j2k_t *p_j2k, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); -#if 0 + +/** + * Compare QCC markers (quantization component) + * + * @param p_j2k J2K codec. + * @param p_first_comp_no the index of the first component to compare. + * @param p_second_comp_no the index of the second component to compare. + * + * @return OPJ_TRUE if equals. + */ +static OPJ_BOOL opj_j2k_compare_qcc(opj_j2k_t *p_j2k, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no); + /** * Writes the QCC marker (quantization component) * @@ -560,9 +613,7 @@ static OPJ_BOOL opj_j2k_write_qcc( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); -#endif -#if 0 /** * Writes the QCC marker (quantization component) * @@ -577,7 +628,6 @@ static void opj_j2k_write_qcc_in_memory(opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, opj_event_mgr_t * p_manager ); -#endif /** * Gets the maximum size taken by a qcc. @@ -708,28 +758,28 @@ static OPJ_BOOL opj_j2k_read_plt ( opj_j2k_t *p_j2k, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); -#if 0 /** - * Reads a PPM marker (Packed packet headers, main header) + * Reads a PPM marker (Packed headers, main header) * * @param p_header_data the data contained in the POC box. * @param p_j2k the jpeg2000 codec. * @param p_header_size the size of the data contained in the POC marker. * @param p_manager the user event manager. -*/ -static OPJ_BOOL j2k_read_ppm_v2 ( - opj_j2k_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager - ); -#endif + */ -static OPJ_BOOL j2k_read_ppm_v3 ( - opj_j2k_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - opj_event_mgr_t * p_manager ); +static OPJ_BOOL opj_j2k_read_ppm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + opj_event_mgr_t * p_manager ); + +/** + * Merges all PPM markers read (Packed headers, main header) + * + * @param p_cp main coding parameters. + * @param p_manager the user event manager. + */ +static OPJ_BOOL opj_j2k_merge_ppm ( opj_cp_t *p_cp, opj_event_mgr_t * p_manager ); /** * Reads a PPT marker (Packed packet headers, tile-part header) @@ -743,6 +793,17 @@ static OPJ_BOOL opj_j2k_read_ppt ( opj_j2k_t *p_j2k, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); + +/** + * Merges all PPT markers read (Packed headers, tile-part header) + * + * @param p_tcp the tile. + * @param p_manager the user event manager. + */ +static OPJ_BOOL opj_j2k_merge_ppt ( opj_tcp_t *p_tcp, + opj_event_mgr_t * p_manager ); + + /** * Writes the TLM marker (Tile Length Marker) * @@ -770,12 +831,32 @@ static OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager ); /** - * Reads a PPT marker (Packed packet headers, tile-part header) + * Reads values from a SOT marker (Start of tile-part) * - * @param p_header_data the data contained in the PPT box. - * @param p_j2k the jpeg2000 codec. + * the j2k decoder state is not affected. No side effects, no checks except for p_header_size. + * + * @param p_header_data the data contained in the SOT marker. + * @param p_header_size the size of the data contained in the SOT marker. + * @param p_tile_no Isot. + * @param p_tot_len Psot. + * @param p_current_part TPsot. + * @param p_num_parts TNsot. + * @param p_manager the user event manager. + */ +static OPJ_BOOL opj_j2k_get_sot_values(OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + OPJ_UINT32* p_tile_no, + OPJ_UINT32* p_tot_len, + OPJ_UINT32* p_current_part, + OPJ_UINT32* p_num_parts, + opj_event_mgr_t * p_manager ); +/** + * Reads a SOT marker (Start of tile-part) + * + * @param p_header_data the data contained in the SOT marker. + * @param p_j2k the jpeg2000 codec. * @param p_header_size the size of the data contained in the PPT marker. - * @param p_manager the user event manager. + * @param p_manager the user event manager. */ static OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, OPJ_BYTE * p_header_data, @@ -811,7 +892,7 @@ static OPJ_BOOL opj_j2k_read_sod( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); -void opj_j2k_update_tlm (opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_part_size ) +static void opj_j2k_update_tlm (opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_part_size ) { opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,p_j2k->m_current_tile_number,1); /* PSOT */ ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current; @@ -1056,7 +1137,7 @@ static OPJ_BOOL opj_j2k_read_cbd ( opj_j2k_t *p_j2k, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager); -#if 0 + /** * Writes COC marker for each component. * @@ -1067,9 +1148,7 @@ static OPJ_BOOL opj_j2k_read_cbd ( opj_j2k_t *p_j2k, static OPJ_BOOL opj_j2k_write_all_coc( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); -#endif -#if 0 /** * Writes QCC marker for each component. * @@ -1080,7 +1159,6 @@ static OPJ_BOOL opj_j2k_write_all_coc( opj_j2k_t *p_j2k, static OPJ_BOOL opj_j2k_write_all_qcc( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ); -#endif /** * Writes regions of interests. @@ -1169,6 +1247,18 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_ima static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager); +/** + * Checks for invalid number of tile-parts in SOT marker (TPsot==TNsot). See issue 254. + * + * @param p_stream the stream to read data from. + * @param tile_no tile number we're looking for. + * @param p_correction_needed output value. if true, non conformant codestream needs TNsot correction. + * @param p_manager the user event manager. + * + * @return true if the function was successful, false else. + */ +static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t *p_stream, OPJ_UINT32 tile_no, OPJ_BOOL* p_correction_needed, opj_event_mgr_t * p_manager ); + /*@}*/ /*@}*/ @@ -1179,7 +1269,7 @@ typedef struct j2k_prog_order{ char str_prog[5]; }j2k_prog_order_t; -j2k_prog_order_t j2k_prog_order_list[] = { +static j2k_prog_order_t j2k_prog_order_list[] = { {OPJ_CPRL, "CPRL"}, {OPJ_LRCP, "LRCP"}, {OPJ_PCRL, "PCRL"}, @@ -1201,7 +1291,7 @@ static const OPJ_UINT32 MCT_ELEMENT_SIZE [] = typedef void (* opj_j2k_mct_function) (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem); -const opj_j2k_mct_function j2k_mct_read_functions_to_float [] = +static const opj_j2k_mct_function j2k_mct_read_functions_to_float [] = { opj_j2k_read_int16_to_float, opj_j2k_read_int32_to_float, @@ -1209,7 +1299,7 @@ const opj_j2k_mct_function j2k_mct_read_functions_to_float [] = opj_j2k_read_float64_to_float }; -const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] = +static const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] = { opj_j2k_read_int16_to_int32, opj_j2k_read_int32_to_int32, @@ -1217,7 +1307,7 @@ const opj_j2k_mct_function j2k_mct_read_functions_to_int32 [] = opj_j2k_read_float64_to_int32 }; -const opj_j2k_mct_function j2k_mct_write_functions_from_float [] = +static const opj_j2k_mct_function j2k_mct_write_functions_from_float [] = { opj_j2k_write_float_to_int16, opj_j2k_write_float_to_int32, @@ -1239,7 +1329,7 @@ typedef struct opj_dec_memory_marker_handler } opj_dec_memory_marker_handler_t; -const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = +static const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = { {J2K_MS_SOT, J2K_STATE_MH | J2K_STATE_TPHSOT, opj_j2k_read_sot}, {J2K_MS_COD, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_cod}, @@ -1252,7 +1342,7 @@ const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = {J2K_MS_TLM, J2K_STATE_MH, opj_j2k_read_tlm}, {J2K_MS_PLM, J2K_STATE_MH, opj_j2k_read_plm}, {J2K_MS_PLT, J2K_STATE_TPH, opj_j2k_read_plt}, - {J2K_MS_PPM, J2K_STATE_MH, j2k_read_ppm_v3}, + {J2K_MS_PPM, J2K_STATE_MH, opj_j2k_read_ppm}, {J2K_MS_PPT, J2K_STATE_TPH, opj_j2k_read_ppt}, {J2K_MS_SOP, 0, 0}, {J2K_MS_CRG, J2K_STATE_MH, opj_j2k_read_crg}, @@ -1276,7 +1366,7 @@ const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = {J2K_MS_UNK, J2K_STATE_MH | J2K_STATE_TPH, 0}/*opj_j2k_read_unk is directly used*/ }; -void opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; @@ -1292,7 +1382,7 @@ void opj_j2k_read_int16_to_float (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; @@ -1308,7 +1398,7 @@ void opj_j2k_read_int32_to_float (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; @@ -1324,7 +1414,7 @@ void opj_j2k_read_float32_to_float (const void * p_src_data, void * p_dest_data } } -void opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_FLOAT32 * l_dest_data = (OPJ_FLOAT32 *) p_dest_data; @@ -1340,7 +1430,7 @@ void opj_j2k_read_float64_to_float (const void * p_src_data, void * p_dest_data } } -void opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; @@ -1356,7 +1446,7 @@ void opj_j2k_read_int16_to_int32 (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; @@ -1372,7 +1462,7 @@ void opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; @@ -1388,7 +1478,7 @@ void opj_j2k_read_float32_to_int32 (const void * p_src_data, void * p_dest_data } } -void opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data; OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data; @@ -1404,7 +1494,7 @@ void opj_j2k_read_float64_to_int32 (const void * p_src_data, void * p_dest_data } } -void opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; @@ -1420,7 +1510,7 @@ void opj_j2k_write_float_to_int16 (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; @@ -1436,7 +1526,7 @@ void opj_j2k_write_float_to_int32 (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; @@ -1452,7 +1542,7 @@ void opj_j2k_write_float_to_float (const void * p_src_data, void * p_dest_data, } } -void opj_j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) +static void opj_j2k_write_float_to_float64 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem) { OPJ_BYTE * l_dest_data = (OPJ_BYTE *) p_dest_data; OPJ_FLOAT32 * l_src_data = (OPJ_FLOAT32 *) p_src_data; @@ -1478,7 +1568,7 @@ char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){ return po->str_prog; } -OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs, +static OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs, OPJ_UINT32 p_nb_pocs, OPJ_UINT32 p_nb_resolutions, OPJ_UINT32 p_num_comps, @@ -1499,7 +1589,6 @@ OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs, opj_event_msg(p_manager , EVT_ERROR, "Not enough memory for checking the poc values.\n"); return OPJ_FALSE; } - memset(packet_array,0,step_l * p_num_layers* sizeof(OPJ_UINT32)); if (p_nb_pocs == 0) { opj_free(packet_array); @@ -1583,7 +1672,7 @@ OPJ_BOOL opj_j2k_check_poc_val( const opj_poc_t *p_pocs, /* ----------------------------------------------------------------------- */ -OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno) +static OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno) { const OPJ_CHAR *prog = 00; OPJ_INT32 i; @@ -1641,7 +1730,7 @@ OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, OPJ_UINT32 tileno) return tpnum; } -OPJ_BOOL opj_j2k_calculate_tp( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_calculate_tp( opj_j2k_t *p_j2k, opj_cp_t *cp, OPJ_UINT32 * p_nb_tiles, opj_image_t *image, @@ -1719,7 +1808,7 @@ OPJ_BOOL opj_j2k_calculate_tp( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_soc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_soc( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -1797,7 +1886,7 @@ static OPJ_BOOL opj_j2k_read_soc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_siz( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_siz( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -1910,7 +1999,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, OPJ_UINT32 l_nb_comp_remain; OPJ_UINT32 l_remaining_size; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_tmp; + OPJ_UINT32 l_tmp, l_tx1, l_ty1; opj_image_t *l_image = 00; opj_cp_t *l_cp = 00; opj_image_comp_t * l_img_comp = 00; @@ -1972,8 +2061,9 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, } /* testcase 4035.pdf.SIGSEGV.d8b.3375 */ - if (l_image->x0 > l_image->x1 || l_image->y0 > l_image->y1) { - opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0); + /* testcase issue427-null-image-size.jp2 */ + if ((l_image->x0 >= l_image->x1) || (l_image->y0 >= l_image->y1)) { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative or zero image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0); return OPJ_FALSE; } /* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */ @@ -1988,6 +2078,14 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_FALSE; } + /* testcase issue427-illegal-tile-offset.jp2 */ + l_tx1 = opj_uint_adds(l_cp->tx0, l_cp->tdx); /* manage overflow */ + l_ty1 = opj_uint_adds(l_cp->ty0, l_cp->tdy); /* manage overflow */ + if ((l_cp->tx0 > l_image->x0) || (l_cp->ty0 > l_image->y0) || (l_tx1 <= l_image->x0) || (l_ty1 <= l_image->y0) ) { + opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: illegal tile offset\n"); + return OPJ_FALSE; + } + #ifdef USE_JPWL if (l_cp->correct) { /* if JPWL is on, we check whether TX errors have damaged @@ -2038,7 +2136,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_FALSE; } - memset(l_image->comps,0,l_image->numcomps * sizeof(opj_image_comp_t)); l_img_comp = l_image->comps; /* Read the component information */ @@ -2167,7 +2264,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(l_cp->tcps,0,l_nb_tiles*sizeof(opj_tcp_t)); #ifdef USE_JPWL if (l_cp->correct) { @@ -2188,27 +2284,24 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->tccps ,0,l_image->numcomps*sizeof(opj_tccp_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records = - (opj_mct_data_t*)opj_malloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); + (opj_mct_data_t*)opj_calloc(OPJ_J2K_MCT_DEFAULT_NB_RECORDS ,sizeof(opj_mct_data_t)); if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mct_records,0,OPJ_J2K_MCT_DEFAULT_NB_RECORDS * sizeof(opj_mct_data_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mct_records = OPJ_J2K_MCT_DEFAULT_NB_RECORDS; p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*) - opj_malloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); + opj_calloc(OPJ_J2K_MCC_DEFAULT_NB_RECORDS, sizeof(opj_simple_mcc_decorrelation_data_t)); if (! p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(p_j2k->m_specific_param.m_decoder.m_default_tcp->m_mcc_records,0,OPJ_J2K_MCC_DEFAULT_NB_RECORDS * sizeof(opj_simple_mcc_decorrelation_data_t)); p_j2k->m_specific_param.m_decoder.m_default_tcp->m_nb_max_mcc_records = OPJ_J2K_MCC_DEFAULT_NB_RECORDS; /* set up default dc level shift */ @@ -2220,12 +2313,11 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, l_current_tile_param = l_cp->tcps; for (i = 0; i < l_nb_tiles; ++i) { - l_current_tile_param->tccps = (opj_tccp_t*) opj_malloc(l_image->numcomps * sizeof(opj_tccp_t)); + l_current_tile_param->tccps = (opj_tccp_t*) opj_calloc(l_image->numcomps, sizeof(opj_tccp_t)); if (l_current_tile_param->tccps == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to take in charge SIZ marker\n"); return OPJ_FALSE; } - memset(l_current_tile_param->tccps,0,l_image->numcomps * sizeof(opj_tccp_t)); ++l_current_tile_param; } @@ -2236,7 +2328,7 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_com( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_com( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -2310,7 +2402,7 @@ static OPJ_BOOL opj_j2k_read_com ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_cod( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_cod( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -2413,7 +2505,14 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k, l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH) ? &l_cp->tcps[p_j2k->m_current_tile_number] : p_j2k->m_specific_param.m_decoder.m_default_tcp; - + + /* Only one COD per tile */ + if (l_tcp->cod) { + opj_event_msg(p_manager, EVT_ERROR, "COD marker already read. No more than one COD marker per tile.\n"); + return OPJ_FALSE; + } + l_tcp->cod = 1; + /* Make sure room is sufficient */ if (p_header_size < 5) { opj_event_msg(p_manager, EVT_ERROR, "Error reading COD marker\n"); @@ -2422,11 +2521,26 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k, opj_read_bytes(p_header_data,&l_tcp->csty,1); /* Scod */ ++p_header_data; + /* Make sure we know how to decode this */ + if ((l_tcp->csty & ~(OPJ_UINT32)(J2K_CP_CSTY_PRT | J2K_CP_CSTY_SOP | J2K_CP_CSTY_EPH)) != 0U) { + opj_event_msg(p_manager, EVT_ERROR, "Unknown Scod value in COD marker\n"); + return OPJ_FALSE; + } opj_read_bytes(p_header_data,&l_tmp,1); /* SGcod (A) */ ++p_header_data; l_tcp->prg = (OPJ_PROG_ORDER) l_tmp; + /* Make sure progression order is valid */ + if (l_tcp->prg > OPJ_CPRL ) { + opj_event_msg(p_manager, EVT_ERROR, "Unknown progression order in COD marker\n"); + l_tcp->prg = OPJ_PROG_UNKNOWN; + } opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */ p_header_data+=2; + + if ((l_tcp->numlayers < 1U) || (l_tcp->numlayers > 65535U)) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid number of layers in COD marker : %d not in range [1-65535]\n", l_tcp->numlayers); + return OPJ_FALSE; + } /* If user didn't set a number layer to decode take the max specify in the codestream. */ if (l_cp->m_specific_param.m_dec.m_layer) { @@ -2473,8 +2587,7 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#if 0 -OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -2518,10 +2631,27 @@ OPJ_BOOL opj_j2k_write_coc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#endif -#if 0 -void opj_j2k_write_coc_in_memory( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_compare_coc(opj_j2k_t *p_j2k, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no) +{ + opj_cp_t *l_cp = NULL; + opj_tcp_t *l_tcp = NULL; + + /* preconditions */ + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number]; + + if (l_tcp->tccps[p_first_comp_no].csty != l_tcp->tccps[p_second_comp_no].csty) { + return OPJ_FALSE; + } + + + return opj_j2k_compare_SPCod_SPCoc(p_j2k, p_j2k->m_current_tile_number, p_first_comp_no, p_second_comp_no); +} + +static void opj_j2k_write_coc_in_memory( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, @@ -2565,9 +2695,8 @@ void opj_j2k_write_coc_in_memory( opj_j2k_t *p_j2k, opj_j2k_write_SPCod_SPCoc(p_j2k,p_j2k->m_current_tile_number,0,l_current_data,&l_remaining_size,p_manager); * p_data_written = l_coc_size; } -#endif -OPJ_UINT32 opj_j2k_get_max_coc_size(opj_j2k_t *p_j2k) +static OPJ_UINT32 opj_j2k_get_max_coc_size(opj_j2k_t *p_j2k) { OPJ_UINT32 i,j; OPJ_UINT32 l_nb_comp; @@ -2649,7 +2778,7 @@ static OPJ_BOOL opj_j2k_read_coc ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_qcd( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_qcd( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -2739,8 +2868,7 @@ static OPJ_BOOL opj_j2k_read_qcd ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#if 0 -OPJ_BOOL opj_j2k_write_qcc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_qcc( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager @@ -2778,10 +2906,13 @@ OPJ_BOOL opj_j2k_write_qcc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#endif -#if 0 -void opj_j2k_write_qcc_in_memory( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_compare_qcc(opj_j2k_t *p_j2k, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no) +{ + return opj_j2k_compare_SQcd_SQcc(p_j2k,p_j2k->m_current_tile_number,p_first_comp_no, p_second_comp_no); +} + +static void opj_j2k_write_qcc_in_memory( opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, @@ -2829,9 +2960,8 @@ void opj_j2k_write_qcc_in_memory( opj_j2k_t *p_j2k, *p_data_written = l_qcc_size; } -#endif -OPJ_UINT32 opj_j2k_get_max_qcc_size (opj_j2k_t *p_j2k) +static OPJ_UINT32 opj_j2k_get_max_qcc_size (opj_j2k_t *p_j2k) { return opj_j2k_get_max_coc_size(p_j2k); } @@ -2923,7 +3053,7 @@ static OPJ_BOOL opj_j2k_read_qcc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_poc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_poc( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -2974,7 +3104,7 @@ OPJ_BOOL opj_j2k_write_poc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -void opj_j2k_write_poc_in_memory( opj_j2k_t *p_j2k, +static void opj_j2k_write_poc_in_memory( opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, opj_event_mgr_t * p_manager @@ -3049,7 +3179,7 @@ void opj_j2k_write_poc_in_memory( opj_j2k_t *p_j2k, *p_data_written = l_poc_size; } -OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k) +static OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k) { opj_tcp_t * l_tcp = 00; OPJ_UINT32 l_nb_tiles = 0; @@ -3069,7 +3199,7 @@ OPJ_UINT32 opj_j2k_get_max_poc_size(opj_j2k_t *p_j2k) return 4 + 9 * l_max_poc; } -OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k) +static OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k) { OPJ_UINT32 i; OPJ_UINT32 l_nb_tiles; @@ -3088,7 +3218,7 @@ OPJ_UINT32 opj_j2k_get_max_toc_size (opj_j2k_t *p_j2k) return 12 * l_max; } -OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) +static OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) { OPJ_UINT32 l_nb_bytes = 0; OPJ_UINT32 l_nb_comps; @@ -3418,347 +3548,220 @@ static OPJ_BOOL opj_j2k_read_plt ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#if 0 -OPJ_BOOL j2k_read_ppm_v2 ( - opj_j2k_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager - ) +/** + * Reads a PPM marker (Packed packet headers, main header) + * + * @param p_header_data the data contained in the POC box. + * @param p_j2k the jpeg2000 codec. + * @param p_header_size the size of the data contained in the POC marker. + * @param p_manager the user event manager. + */ + +static OPJ_BOOL opj_j2k_read_ppm ( + opj_j2k_t *p_j2k, + OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + opj_event_mgr_t * p_manager ) { + opj_cp_t *l_cp = 00; + OPJ_UINT32 l_Z_ppm; + + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); + + /* We need to have the Z_ppm element + 1 byte of Nppm/Ippm at minimum */ + if (p_header_size < 2) { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); + return OPJ_FALSE; + } + + l_cp = &(p_j2k->m_cp); + l_cp->ppm = 1; + + opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ + ++p_header_data; + --p_header_size; + + /* check allocation needed */ + if (l_cp->ppm_markers == NULL) { /* first PPM marker */ + OPJ_UINT32 l_newCount = l_Z_ppm + 1U; /* can't overflow, l_Z_ppm is UINT8 */ + assert(l_cp->ppm_markers_count == 0U); + + l_cp->ppm_markers = (opj_ppx *) opj_calloc(l_newCount, sizeof(opj_ppx)); + if (l_cp->ppm_markers == NULL) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n"); + return OPJ_FALSE; + } + l_cp->ppm_markers_count = l_newCount; + } else if (l_cp->ppm_markers_count <= l_Z_ppm) { + OPJ_UINT32 l_newCount = l_Z_ppm + 1U; /* can't overflow, l_Z_ppm is UINT8 */ + opj_ppx *new_ppm_markers; + new_ppm_markers = (opj_ppx *) opj_realloc(l_cp->ppm_markers, l_newCount * sizeof(opj_ppx)); + if (new_ppm_markers == NULL) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n"); + return OPJ_FALSE; + } + l_cp->ppm_markers = new_ppm_markers; + memset(l_cp->ppm_markers + l_cp->ppm_markers_count, 0, (l_newCount - l_cp->ppm_markers_count) * sizeof(opj_ppx)); + l_cp->ppm_markers_count = l_newCount; + } + + if (l_cp->ppm_markers[l_Z_ppm].m_data != NULL) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Zppm %u already read\n", l_Z_ppm); + return OPJ_FALSE; + } + + l_cp->ppm_markers[l_Z_ppm].m_data = (OPJ_BYTE *) opj_malloc(p_header_size); + if (l_cp->ppm_markers[l_Z_ppm].m_data == NULL) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n"); + return OPJ_FALSE; + } + l_cp->ppm_markers[l_Z_ppm].m_data_size = p_header_size; + memcpy(l_cp->ppm_markers[l_Z_ppm].m_data, p_header_data, p_header_size); - opj_cp_t *l_cp = 00; - OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; - - /* preconditions */ - assert(p_header_data != 00); - assert(p_j2k != 00); - assert(p_manager != 00); - - if (p_header_size < 1) { - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); - return OPJ_FALSE; - } - - l_cp = &(p_j2k->m_cp); - l_cp->ppm = 1; - - opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ - ++p_header_data; - --p_header_size; - - /* First PPM marker */ - if (l_Z_ppm == 0) { - if (p_header_size < 4) { - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); - return OPJ_FALSE; - } - - opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ - p_header_data+=4; - p_header_size-=4; - - /* First PPM marker: Initialization */ - l_cp->ppm_len = l_N_ppm; - l_cp->ppm_data_size = 0; - - l_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len); - if (l_cp->ppm_buffer == 00) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); - return OPJ_FALSE; - } - memset(l_cp->ppm_buffer,0,l_cp->ppm_len); - - l_cp->ppm_data = l_cp->ppm_buffer; - } - - while (1) { - if (l_cp->ppm_data_size == l_cp->ppm_len) { - if (p_header_size >= 4) { - /* read a N_ppm */ - opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ - p_header_data+=4; - p_header_size-=4; - l_cp->ppm_len += l_N_ppm ; - - OPJ_BYTE *new_ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len); - if (! new_ppm_buffer) { - opj_free(l_cp->ppm_buffer); - l_cp->ppm_buffer = NULL; - l_cp->ppm_len = 0; - l_cp->ppm_data = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory reading ppm marker\n"); - return OPJ_FALSE; - } - l_cp->ppm_buffer = new_ppm_buffer; - memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm); - l_cp->ppm_data = l_cp->ppm_buffer; - } - else { - return OPJ_FALSE; - } - } - - l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size; - - if (l_remaining_data <= p_header_size) { - /* we must store less information than available in the packet */ - memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data); - l_cp->ppm_data_size = l_cp->ppm_len; - p_header_size -= l_remaining_data; - p_header_data += l_remaining_data; - } - else { - memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size); - l_cp->ppm_data_size += p_header_size; - p_header_data += p_header_size; - p_header_size = 0; - break; - } - } - - return OPJ_TRUE; + return OPJ_TRUE; } -#endif -OPJ_BOOL j2k_read_ppm_v3 ( - opj_j2k_t *p_j2k, - OPJ_BYTE * p_header_data, - OPJ_UINT32 p_header_size, - struct opj_event_mgr * p_manager - ) +/** + * Merges all PPM markers read (Packed headers, main header) + * + * @param p_cp main coding parameters. + * @param p_manager the user event manager. + */ +static OPJ_BOOL opj_j2k_merge_ppm ( opj_cp_t *p_cp, opj_event_mgr_t * p_manager ) { - opj_cp_t *l_cp = 00; - OPJ_UINT32 l_remaining_data, l_Z_ppm, l_N_ppm; + OPJ_UINT32 i, l_ppm_data_size, l_N_ppm_remaining; + + /* preconditions */ + assert(p_cp != 00); + assert(p_manager != 00); + assert(p_cp->ppm_buffer == NULL); + + if (p_cp->ppm == 0U) { + return OPJ_TRUE; + } + + l_ppm_data_size = 0U; + l_N_ppm_remaining = 0U; + for (i = 0U; i < p_cp->ppm_markers_count; ++i) { + if (p_cp->ppm_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppm */ + OPJ_UINT32 l_N_ppm; + OPJ_UINT32 l_data_size = p_cp->ppm_markers[i].m_data_size; + const OPJ_BYTE* l_data = p_cp->ppm_markers[i].m_data; + + if (l_N_ppm_remaining >= l_data_size) { + l_N_ppm_remaining -= l_data_size; + l_data_size = 0U; + } else { + l_data += l_N_ppm_remaining; + l_data_size -= l_N_ppm_remaining; + l_N_ppm_remaining = 0U; + } + + if (l_data_size > 0U) { + do + { + /* read Nppm */ + if (l_data_size < 4U) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes to read Nppm\n"); + return OPJ_FALSE; + } + opj_read_bytes(l_data, &l_N_ppm, 4); + l_data+=4; + l_data_size-=4; + l_ppm_data_size += l_N_ppm; /* can't overflow, max 256 markers of max 65536 bytes, that is when PPM markers are not corrupted which is checked elsewhere */ + + if (l_data_size >= l_N_ppm) { + l_data_size -= l_N_ppm; + l_data += l_N_ppm; + } else { + l_N_ppm_remaining = l_N_ppm - l_data_size; + l_data_size = 0U; + } + } while (l_data_size > 0U); + } + } + } + + if (l_N_ppm_remaining != 0U) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Corrupted PPM markers\n"); + return OPJ_FALSE; + } + + p_cp->ppm_buffer = (OPJ_BYTE *) opj_malloc(l_ppm_data_size); + if (p_cp->ppm_buffer == 00) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPM marker\n"); + return OPJ_FALSE; + } + p_cp->ppm_len = l_ppm_data_size; + l_ppm_data_size = 0U; + l_N_ppm_remaining = 0U; + for (i = 0U; i < p_cp->ppm_markers_count; ++i) { + if (p_cp->ppm_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppm */ + OPJ_UINT32 l_N_ppm; + OPJ_UINT32 l_data_size = p_cp->ppm_markers[i].m_data_size; + const OPJ_BYTE* l_data = p_cp->ppm_markers[i].m_data; + + if (l_N_ppm_remaining >= l_data_size) { + memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_data_size); + l_ppm_data_size += l_data_size; + l_N_ppm_remaining -= l_data_size; + l_data_size = 0U; + } else { + memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_N_ppm_remaining); + l_ppm_data_size += l_N_ppm_remaining; + l_data += l_N_ppm_remaining; + l_data_size -= l_N_ppm_remaining; + l_N_ppm_remaining = 0U; + } - /* preconditions */ - assert(p_header_data != 00); - assert(p_j2k != 00); - assert(p_manager != 00); - - /* Minimum size of PPM marker is equal to the size of Zppm element */ - if (p_header_size < 1) { - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); - return OPJ_FALSE; - } - - l_cp = &(p_j2k->m_cp); - l_cp->ppm = 1; - - opj_read_bytes(p_header_data,&l_Z_ppm,1); /* Z_ppm */ - ++p_header_data; - --p_header_size; - - /* First PPM marker */ - if (l_Z_ppm == 0) { - /* We need now at least the Nppm^0 element */ - if (p_header_size < 4) { - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n"); - return OPJ_FALSE; - } - - opj_read_bytes(p_header_data,&l_N_ppm,4); /* First N_ppm */ - p_header_data+=4; - p_header_size-=4; - - /* sanity check: how much bytes is left for Ippm */ - if( p_header_size < l_N_ppm ) - { - opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes (%u) to hold Ippm series (%u), Index (%d)\n", p_header_size, l_N_ppm, l_Z_ppm ); - opj_free(l_cp->ppm_data); - l_cp->ppm_data = NULL; - l_cp->ppm_buffer = NULL; - l_cp->ppm = 0; /* do not use PPM */ - return OPJ_FALSE; - } - - /* First PPM marker: Initialization */ - l_cp->ppm_len = l_N_ppm; - l_cp->ppm_data_read = 0; - - l_cp->ppm_data = (OPJ_BYTE *) opj_malloc(l_cp->ppm_len); - l_cp->ppm_buffer = l_cp->ppm_data; - if (l_cp->ppm_data == 00) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read ppm marker\n"); - return OPJ_FALSE; - } - memset(l_cp->ppm_data,0,l_cp->ppm_len); - - l_cp->ppm_data_current = l_cp->ppm_data; - - /*l_cp->ppm_data = l_cp->ppm_buffer;*/ - } - else { - if (p_header_size < 4) { - opj_event_msg(p_manager, EVT_WARNING, "Empty PPM marker\n"); - return OPJ_TRUE; - } - else { - /* Uncompleted Ippm series in the previous PPM marker?*/ - if (l_cp->ppm_data_read < l_cp->ppm_len) { - /* Get the place where add the remaining Ippm series*/ - l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_data_read]); - l_N_ppm = l_cp->ppm_len - l_cp->ppm_data_read; - } - else { - OPJ_BYTE *new_ppm_data; - opj_read_bytes(p_header_data,&l_N_ppm,4); /* First N_ppm */ - p_header_data+=4; - p_header_size-=4; - - /* sanity check: how much bytes is left for Ippm */ - if( p_header_size < l_N_ppm ) - { - opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes (%u) to hold Ippm series (%u), Index (%d)\n", p_header_size, l_N_ppm, l_Z_ppm ); - opj_free(l_cp->ppm_data); - l_cp->ppm_data = NULL; - l_cp->ppm_buffer = NULL; - l_cp->ppm = 0; /* do not use PPM */ - return OPJ_FALSE; - } - /* Increase the size of ppm_data to add the new Ippm series*/ - assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); - new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - if (! new_ppm_data) { - opj_free(l_cp->ppm_data); - l_cp->ppm_data = NULL; - l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ - l_cp->ppm_len = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new Ippm series\n"); - return OPJ_FALSE; - } - l_cp->ppm_data = new_ppm_data; - l_cp->ppm_buffer = l_cp->ppm_data; - - /* Keep the position of the place where concatenate the new series*/ - l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); - l_cp->ppm_len += l_N_ppm; - } - } - } - - l_remaining_data = p_header_size; - - while (l_remaining_data >= l_N_ppm) { - /* read a complete Ippm series*/ - memcpy(l_cp->ppm_data_current, p_header_data, l_N_ppm); - p_header_size -= l_N_ppm; - p_header_data += l_N_ppm; - - l_cp->ppm_data_read += l_N_ppm; /* Increase the number of data read*/ - - if (p_header_size) - { - opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm^i */ - p_header_data+=4; - p_header_size-=4; - } - else { - l_remaining_data = p_header_size; - break; - } - - l_remaining_data = p_header_size; - - /* Next Ippm series is a complete series ?*/ - if (l_remaining_data >= l_N_ppm) { - OPJ_BYTE *new_ppm_data; - /* Increase the size of ppm_data to add the new Ippm series*/ - assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); - new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - if (! new_ppm_data) { - opj_free(l_cp->ppm_data); - l_cp->ppm_data = NULL; - l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ - l_cp->ppm_len = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (complete) Ippm series\n"); - return OPJ_FALSE; - } - l_cp->ppm_data = new_ppm_data; - l_cp->ppm_buffer = l_cp->ppm_data; - - /* Keep the position of the place where concatenate the new series */ - l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); - l_cp->ppm_len += l_N_ppm; - } - - } - - /* Need to read an incomplete Ippm series*/ - if (l_remaining_data) { - OPJ_BYTE *new_ppm_data; - assert(l_cp->ppm_data == l_cp->ppm_buffer && "We need ppm_data and ppm_buffer to be the same when reallocating"); - new_ppm_data = (OPJ_BYTE *) opj_realloc(l_cp->ppm_data, l_cp->ppm_len + l_N_ppm); - if (! new_ppm_data) { - opj_free(l_cp->ppm_data); - l_cp->ppm_data = NULL; - l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */ - l_cp->ppm_len = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to increase the size of ppm_data to add the new (incomplete) Ippm series\n"); - return OPJ_FALSE; - } - l_cp->ppm_data = new_ppm_data; - l_cp->ppm_buffer = l_cp->ppm_data; - - /* Keep the position of the place where concatenate the new series*/ - l_cp->ppm_data_current = &(l_cp->ppm_data[l_cp->ppm_len]); - l_cp->ppm_len += l_N_ppm; - - /* Read incomplete Ippm series*/ - memcpy(l_cp->ppm_data_current, p_header_data, l_remaining_data); - p_header_size -= l_remaining_data; - p_header_data += l_remaining_data; - - l_cp->ppm_data_read += l_remaining_data; /* Increase the number of data read*/ - } - -#ifdef CLEAN_MSD - - if (l_cp->ppm_data_size == l_cp->ppm_len) { - if (p_header_size >= 4) { - /* read a N_ppm*/ - opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm */ - p_header_data+=4; - p_header_size-=4; - l_cp->ppm_len += l_N_ppm ; - - OPJ_BYTE *new_ppm_buffer = (OPJ_BYTE *) opj_realloc(l_cp->ppm_buffer, l_cp->ppm_len); - if (! new_ppm_buffer) { - opj_free(l_cp->ppm_buffer); - l_cp->ppm_buffer = NULL; - l_cp->ppm_len = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read ppm marker\n"); - return OPJ_FALSE; - } - l_cp->ppm_buffer = new_ppm_buffer; - memset(l_cp->ppm_buffer+l_cp->ppm_data_size,0,l_N_ppm); - - l_cp->ppm_data = l_cp->ppm_buffer; - } - else { - return OPJ_FALSE; - } - } - - l_remaining_data = l_cp->ppm_len - l_cp->ppm_data_size; - - if (l_remaining_data <= p_header_size) { - /* we must store less information than available in the packet */ - memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , l_remaining_data); - l_cp->ppm_data_size = l_cp->ppm_len; - p_header_size -= l_remaining_data; - p_header_data += l_remaining_data; - } - else { - memcpy(l_cp->ppm_buffer + l_cp->ppm_data_size , p_header_data , p_header_size); - l_cp->ppm_data_size += p_header_size; - p_header_data += p_header_size; - p_header_size = 0; - break; - } - } -#endif - return OPJ_TRUE; + if (l_data_size > 0U) { + do + { + /* read Nppm */ + if (l_data_size < 4U) { + /* clean up to be done on l_cp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough bytes to read Nppm\n"); + return OPJ_FALSE; + } + opj_read_bytes(l_data, &l_N_ppm, 4); + l_data+=4; + l_data_size-=4; + + if (l_data_size >= l_N_ppm) { + memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_N_ppm); + l_ppm_data_size += l_N_ppm; + l_data_size -= l_N_ppm; + l_data += l_N_ppm; + } else { + memcpy(p_cp->ppm_buffer + l_ppm_data_size, l_data, l_data_size); + l_ppm_data_size += l_data_size; + l_N_ppm_remaining = l_N_ppm - l_data_size; + l_data_size = 0U; + } + } while (l_data_size > 0U); + } + opj_free(p_cp->ppm_markers[i].m_data); + p_cp->ppm_markers[i].m_data = NULL; + p_cp->ppm_markers[i].m_data_size = 0U; + } + } + + p_cp->ppm_data = p_cp->ppm_buffer; + p_cp->ppm_data_size = p_cp->ppm_len; + + p_cp->ppm_markers_count = 0U; + opj_free(p_cp->ppm_markers); + p_cp->ppm_markers = NULL; + + return OPJ_TRUE; } /** @@ -3775,77 +3778,127 @@ static OPJ_BOOL opj_j2k_read_ppt ( opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager ) { - opj_cp_t *l_cp = 00; - opj_tcp_t *l_tcp = 00; - OPJ_UINT32 l_Z_ppt; + opj_cp_t *l_cp = 00; + opj_tcp_t *l_tcp = 00; + OPJ_UINT32 l_Z_ppt; - /* preconditions */ - assert(p_header_data != 00); - assert(p_j2k != 00); - assert(p_manager != 00); + /* preconditions */ + assert(p_header_data != 00); + assert(p_j2k != 00); + assert(p_manager != 00); - /* We need to have the Z_ppt element at minimum */ - if (p_header_size < 1) { - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker\n"); - return OPJ_FALSE; - } + /* We need to have the Z_ppt element + 1 byte of Ippt at minimum */ + if (p_header_size < 2) { + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker\n"); + return OPJ_FALSE; + } - l_cp = &(p_j2k->m_cp); - if (l_cp->ppm){ - opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker: packet header have been previously found in the main header (PPM marker).\n"); - return OPJ_FALSE; - } + l_cp = &(p_j2k->m_cp); + if (l_cp->ppm){ + opj_event_msg(p_manager, EVT_ERROR, "Error reading PPT marker: packet header have been previously found in the main header (PPM marker).\n"); + return OPJ_FALSE; + } - l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]); - l_tcp->ppt = 1; + l_tcp = &(l_cp->tcps[p_j2k->m_current_tile_number]); + l_tcp->ppt = 1; - opj_read_bytes(p_header_data,&l_Z_ppt,1); /* Z_ppt */ - ++p_header_data; - --p_header_size; - - /* Allocate buffer to read the packet header */ - if (l_Z_ppt == 0) { - /* First PPT marker */ - l_tcp->ppt_data_size = 0; - l_tcp->ppt_len = p_header_size; - - opj_free(l_tcp->ppt_buffer); - l_tcp->ppt_buffer = (OPJ_BYTE *) opj_calloc(l_tcp->ppt_len, sizeof(OPJ_BYTE) ); - if (l_tcp->ppt_buffer == 00) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); - return OPJ_FALSE; - } - l_tcp->ppt_data = l_tcp->ppt_buffer; - - /* memset(l_tcp->ppt_buffer,0,l_tcp->ppt_len); */ - } - else { - OPJ_BYTE *new_ppt_buffer; - l_tcp->ppt_len += p_header_size; - - new_ppt_buffer = (OPJ_BYTE *) opj_realloc(l_tcp->ppt_buffer, l_tcp->ppt_len); - if (! new_ppt_buffer) { - opj_free(l_tcp->ppt_buffer); - l_tcp->ppt_buffer = NULL; - l_tcp->ppt_len = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); - return OPJ_FALSE; - } - l_tcp->ppt_buffer = new_ppt_buffer; - l_tcp->ppt_data = l_tcp->ppt_buffer; - - memset(l_tcp->ppt_buffer+l_tcp->ppt_data_size,0,p_header_size); - } - - /* Read packet header from buffer */ - memcpy(l_tcp->ppt_buffer+l_tcp->ppt_data_size,p_header_data,p_header_size); - - l_tcp->ppt_data_size += p_header_size; - - return OPJ_TRUE; + opj_read_bytes(p_header_data,&l_Z_ppt,1); /* Z_ppt */ + ++p_header_data; + --p_header_size; + + /* check allocation needed */ + if (l_tcp->ppt_markers == NULL) { /* first PPT marker */ + OPJ_UINT32 l_newCount = l_Z_ppt + 1U; /* can't overflow, l_Z_ppt is UINT8 */ + assert(l_tcp->ppt_markers_count == 0U); + + l_tcp->ppt_markers = (opj_ppx *) opj_calloc(l_newCount, sizeof(opj_ppx)); + if (l_tcp->ppt_markers == NULL) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + return OPJ_FALSE; + } + l_tcp->ppt_markers_count = l_newCount; + } else if (l_tcp->ppt_markers_count <= l_Z_ppt) { + OPJ_UINT32 l_newCount = l_Z_ppt + 1U; /* can't overflow, l_Z_ppt is UINT8 */ + opj_ppx *new_ppt_markers; + new_ppt_markers = (opj_ppx *) opj_realloc(l_tcp->ppt_markers, l_newCount * sizeof(opj_ppx)); + if (new_ppt_markers == NULL) { + /* clean up to be done on l_tcp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + return OPJ_FALSE; + } + l_tcp->ppt_markers = new_ppt_markers; + memset(l_tcp->ppt_markers + l_tcp->ppt_markers_count, 0, (l_newCount - l_tcp->ppt_markers_count) * sizeof(opj_ppx)); + l_tcp->ppt_markers_count = l_newCount; + } + + if (l_tcp->ppt_markers[l_Z_ppt].m_data != NULL) { + /* clean up to be done on l_tcp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Zppt %u already read\n", l_Z_ppt); + return OPJ_FALSE; + } + + l_tcp->ppt_markers[l_Z_ppt].m_data = (OPJ_BYTE *) opj_malloc(p_header_size); + if (l_tcp->ppt_markers[l_Z_ppt].m_data == NULL) { + /* clean up to be done on l_tcp destruction */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + return OPJ_FALSE; + } + l_tcp->ppt_markers[l_Z_ppt].m_data_size = p_header_size; + memcpy(l_tcp->ppt_markers[l_Z_ppt].m_data, p_header_data, p_header_size); + return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_tlm( opj_j2k_t *p_j2k, +/** + * Merges all PPT markers read (Packed packet headers, tile-part header) + * + * @param p_tcp the tile. + * @param p_manager the user event manager. + */ +static OPJ_BOOL opj_j2k_merge_ppt(opj_tcp_t *p_tcp, opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 i, l_ppt_data_size; + /* preconditions */ + assert(p_tcp != 00); + assert(p_manager != 00); + assert(p_tcp->ppt_buffer == NULL); + + if (p_tcp->ppt == 0U) { + return OPJ_TRUE; + } + + l_ppt_data_size = 0U; + for (i = 0U; i < p_tcp->ppt_markers_count; ++i) { + l_ppt_data_size += p_tcp->ppt_markers[i].m_data_size; /* can't overflow, max 256 markers of max 65536 bytes */ + } + + p_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_ppt_data_size); + if (p_tcp->ppt_buffer == 00) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + return OPJ_FALSE; + } + p_tcp->ppt_len = l_ppt_data_size; + l_ppt_data_size = 0U; + for (i = 0U; i < p_tcp->ppt_markers_count; ++i) { + if (p_tcp->ppt_markers[i].m_data != NULL) { /* standard doesn't seem to require contiguous Zppt */ + memcpy(p_tcp->ppt_buffer + l_ppt_data_size, p_tcp->ppt_markers[i].m_data, p_tcp->ppt_markers[i].m_data_size); + l_ppt_data_size += p_tcp->ppt_markers[i].m_data_size; /* can't overflow, max 256 markers of max 65536 bytes */ + + opj_free(p_tcp->ppt_markers[i].m_data); + p_tcp->ppt_markers[i].m_data = NULL; + p_tcp->ppt_markers[i].m_data_size = 0U; + } + } + + p_tcp->ppt_markers_count = 0U; + opj_free(p_tcp->ppt_markers); + p_tcp->ppt_markers = NULL; + + p_tcp->ppt_data = p_tcp->ppt_buffer; + p_tcp->ppt_data_size = p_tcp->ppt_len; + return OPJ_TRUE; +} + +static OPJ_BOOL opj_j2k_write_tlm( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -3899,7 +3952,7 @@ OPJ_BOOL opj_j2k_write_tlm( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, const opj_stream_private_t *p_stream, @@ -3943,7 +3996,36 @@ OPJ_BOOL opj_j2k_write_sot( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_get_sot_values(OPJ_BYTE * p_header_data, + OPJ_UINT32 p_header_size, + OPJ_UINT32* p_tile_no, + OPJ_UINT32* p_tot_len, + OPJ_UINT32* p_current_part, + OPJ_UINT32* p_num_parts, + opj_event_mgr_t * p_manager ) +{ + /* preconditions */ + assert(p_header_data != 00); + assert(p_manager != 00); + + /* Size of this marker is fixed = 12 (we have already read marker and its size)*/ + if (p_header_size != 8) { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_header_data,p_tile_no,2); /* Isot */ + p_header_data+=2; + opj_read_bytes(p_header_data,p_tot_len,4); /* Psot */ + p_header_data+=4; + opj_read_bytes(p_header_data,p_current_part,1); /* TPsot */ + ++p_header_data; + opj_read_bytes(p_header_data,p_num_parts ,1); /* TNsot */ + ++p_header_data; + return OPJ_TRUE; +} + +static OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ) @@ -3955,19 +4037,16 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, OPJ_UINT32 l_tile_x,l_tile_y; /* preconditions */ - assert(p_header_data != 00); + assert(p_j2k != 00); assert(p_manager != 00); - - /* Size of this marker is fixed = 12 (we have already read marker and its size)*/ - if (p_header_size != 8) { + + if (! opj_j2k_get_sot_values(p_header_data, p_header_size, &(p_j2k->m_current_tile_number), &l_tot_len, &l_current_part, &l_num_parts, p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n"); return OPJ_FALSE; } l_cp = &(p_j2k->m_cp); - opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2); /* Isot */ - p_header_data+=2; /* testcase 2.pdf.SIGFPE.706.1112 */ if (p_j2k->m_current_tile_number >= l_cp->tw * l_cp->th) { @@ -4010,9 +4089,6 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, /* Optimization possible here with a more complex data structure and with the removing of tiles */ /* since the time taken by this function can only grow at the time */ - opj_read_bytes(p_header_data,&l_tot_len,4); /* Psot */ - p_header_data+=4; - /* PSot should be equal to zero or >=14 or <= 2^32-1 */ if ((l_tot_len !=0 ) && (l_tot_len < 14) ) { @@ -4055,13 +4131,8 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1; } - opj_read_bytes(p_header_data,&l_current_part ,1); /* TPsot */ - ++p_header_data; - - opj_read_bytes(p_header_data,&l_num_parts ,1); /* TNsot */ - ++p_header_data; - if (l_num_parts != 0) { /* Number of tile-part header is provided by this tile-part header */ + l_num_parts += p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction; /* Useful to manage the case of textGBR.jp2 file because two values of TNSot are allowed: the correct numbers of * tile-parts for that tile and zero (A.4.2 of 15444-1 : 2002). */ if (l_tcp->m_nb_tile_parts) { @@ -4128,6 +4199,10 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = (opj_tp_index_t*)opj_calloc(l_num_parts, sizeof(opj_tp_index_t)); + if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); + return OPJ_FALSE; + } } else { opj_tp_index_t *new_tp_index = (opj_tp_index_t *) opj_realloc( @@ -4135,7 +4210,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, if (! new_tp_index) { opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index); p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); return OPJ_FALSE; } p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index; @@ -4149,6 +4224,11 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = (opj_tp_index_t*)opj_calloc( p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps, sizeof(opj_tp_index_t)); + if (!p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index) { + p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); + return OPJ_FALSE; + } } if ( l_current_part >= p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps ){ @@ -4161,7 +4241,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, opj_free(p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index); p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = NULL; p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = 0; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n"); + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read SOT marker. Tile index allocation failed\n"); return OPJ_FALSE; } p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index = new_tp_index; @@ -4202,7 +4282,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_sod( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_sod( opj_j2k_t *p_j2k, opj_tcd_t * p_tile_coder, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, @@ -4276,7 +4356,7 @@ OPJ_BOOL opj_j2k_write_sod( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -4316,9 +4396,15 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, /* Patch to support new PHR data */ if (p_j2k->m_specific_param.m_decoder.m_sot_length) { + /* If we are here, we'll try to read the data after allocation */ + /* Check enough bytes left in stream before allocation */ + if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) { + opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n"); + return OPJ_FALSE; + } if (! *l_current_data) { /* LH: oddly enough, in this path, l_tile_len!=0. - * TODO: If this was consistant, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...). + * TODO: If this was consistent, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...). */ *l_current_data = (OPJ_BYTE*) opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length); } @@ -4391,7 +4477,7 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, return OPJ_TRUE; } - OPJ_BOOL opj_j2k_write_rgn(opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_rgn(opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no, OPJ_UINT32 nb_comps, @@ -4448,7 +4534,7 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_eoc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_eoc( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -4558,18 +4644,18 @@ static OPJ_BOOL opj_j2k_read_rgn (opj_j2k_t *p_j2k, } -OPJ_FLOAT32 opj_j2k_get_tp_stride (opj_tcp_t * p_tcp) +static OPJ_FLOAT32 opj_j2k_get_tp_stride (opj_tcp_t * p_tcp) { return (OPJ_FLOAT32) ((p_tcp->m_nb_tile_parts - 1) * 14); } -OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp) +static OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp) { (void)p_tcp; return 0; } -OPJ_BOOL opj_j2k_update_rates( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_update_rates( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -4732,7 +4818,7 @@ OPJ_BOOL opj_j2k_update_rates( opj_j2k_t *p_j2k, } #if 0 -OPJ_BOOL opj_j2k_read_eoc ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_eoc ( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -4782,7 +4868,7 @@ OPJ_BOOL opj_j2k_read_eoc ( opj_j2k_t *p_j2k, } #endif -OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -4796,7 +4882,7 @@ OPJ_BOOL opj_j2k_get_end_header(opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_mct_data_group( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_mct_data_group( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -4844,54 +4930,56 @@ OPJ_BOOL opj_j2k_write_mct_data_group( opj_j2k_t *p_j2k, return OPJ_TRUE; } -#if 0 -OPJ_BOOL opj_j2k_write_all_coc(opj_j2k_t *p_j2k, - struct opj_stream_private *p_stream, - struct opj_event_mgr * p_manager ) +static OPJ_BOOL opj_j2k_write_all_coc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 compno; - - /* preconditions */ - assert(p_j2k != 00); - assert(p_manager != 00); - assert(p_stream != 00); - - for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) - { - if (! opj_j2k_write_coc(p_j2k,compno,p_stream, p_manager)) { - return OPJ_FALSE; - } - } - - return OPJ_TRUE; + OPJ_UINT32 compno; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + for (compno = 1; compno < p_j2k->m_private_image->numcomps; ++compno) + { + /* cod is first component of first tile */ + if (! opj_j2k_compare_coc(p_j2k, 0, compno)) { + if (! opj_j2k_write_coc(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } + } + } + + return OPJ_TRUE; } -#endif -#if 0 -OPJ_BOOL opj_j2k_write_all_qcc(opj_j2k_t *p_j2k, - struct opj_stream_private *p_stream, - struct opj_event_mgr * p_manager ) +static OPJ_BOOL opj_j2k_write_all_qcc( + opj_j2k_t *p_j2k, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) { - OPJ_UINT32 compno; - - /* preconditions */ - assert(p_j2k != 00); - assert(p_manager != 00); - assert(p_stream != 00); - - for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) - { - if (! opj_j2k_write_qcc(p_j2k,compno,p_stream, p_manager)) { - return OPJ_FALSE; - } - } - - return OPJ_TRUE; + OPJ_UINT32 compno; + + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + assert(p_stream != 00); + + for (compno = 1; compno < p_j2k->m_private_image->numcomps; ++compno) + { + /* qcd is first component of first tile */ + if (! opj_j2k_compare_qcc(p_j2k, 0, compno)) { + if (! opj_j2k_write_qcc(p_j2k,compno,p_stream, p_manager)) { + return OPJ_FALSE; + } + } + } + return OPJ_TRUE; } -#endif - -OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -4905,7 +4993,7 @@ OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k, l_tccp = p_j2k->m_cp.tcps->tccps; - for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) { + for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) { if (l_tccp->roishift) { if (! opj_j2k_write_rgn(p_j2k,0,compno,p_j2k->m_private_image->numcomps,p_stream,p_manager)) { @@ -4919,7 +5007,7 @@ OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_epc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_epc( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -4957,7 +5045,7 @@ OPJ_BOOL opj_j2k_write_epc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_unk ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_unk ( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, OPJ_UINT32 *output_marker, opj_event_mgr_t * p_manager @@ -4974,7 +5062,7 @@ OPJ_BOOL opj_j2k_read_unk ( opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_WARNING, "Unknown marker\n"); - while(1) { + for (;;) { /* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer*/ if (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) { opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); @@ -5019,7 +5107,7 @@ OPJ_BOOL opj_j2k_read_unk ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_mct_record( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_mct_record( opj_j2k_t *p_j2k, opj_mct_data_t * p_mct_record, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) @@ -5158,6 +5246,7 @@ static OPJ_BOOL opj_j2k_read_mct ( opj_j2k_t *p_j2k, } l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records; + ++l_tcp->m_nb_mct_records; } if (l_mct_data->m_data) { @@ -5186,12 +5275,11 @@ static OPJ_BOOL opj_j2k_read_mct ( opj_j2k_t *p_j2k, memcpy(l_mct_data->m_data,p_header_data,p_header_size); l_mct_data->m_data_size = p_header_size; - ++l_tcp->m_nb_mct_records; return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_mcc_record( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_mcc_record( opj_j2k_t *p_j2k, struct opj_simple_mcc_decorrelation_data * p_mcc_record, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) @@ -5294,7 +5382,7 @@ OPJ_BOOL opj_j2k_write_mcc_record( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_mcc ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_mcc ( opj_j2k_t *p_j2k, OPJ_BYTE * p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ) @@ -5509,7 +5597,7 @@ OPJ_BOOL opj_j2k_read_mcc ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_mco( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_mco( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) @@ -5526,8 +5614,7 @@ OPJ_BOOL opj_j2k_write_mco( opj_j2k_t *p_j2k, assert(p_stream != 00); l_tcp =&(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); - l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; - + l_mco_size = 5 + l_tcp->m_nb_mcc_records; if (l_mco_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) { @@ -5542,6 +5629,8 @@ OPJ_BOOL opj_j2k_write_mco( opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_encoder.m_header_tile_data = new_header_tile_data; p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_mco_size; } + l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data; + opj_write_bytes(l_current_data,J2K_MS_MCO,2); /* MCO */ l_current_data += 2; @@ -5549,14 +5638,13 @@ OPJ_BOOL opj_j2k_write_mco( opj_j2k_t *p_j2k, opj_write_bytes(l_current_data,l_mco_size-2,2); /* Lmco */ l_current_data += 2; - opj_write_bytes(l_current_data,l_tcp->m_nb_mcc_records,1); /* Nmco : only one tranform stage*/ + opj_write_bytes(l_current_data,l_tcp->m_nb_mcc_records,1); /* Nmco : only one transform stage*/ ++l_current_data; l_mcc_record = l_tcp->m_mcc_records; - for (i=0;im_nb_mcc_records;++i) { + for (i=0;im_nb_mcc_records;++i) { opj_write_bytes(l_current_data,l_mcc_record->m_index,1);/* Imco -> use the mcc indicated by 1*/ ++l_current_data; - ++l_mcc_record; } @@ -5602,7 +5690,7 @@ static OPJ_BOOL opj_j2k_read_mco ( opj_j2k_t *p_j2k, return OPJ_FALSE; } - opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/ + opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one transform stage*/ ++p_header_data; if (l_nb_stages > 1) { @@ -5639,7 +5727,7 @@ static OPJ_BOOL opj_j2k_read_mco ( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index) +static OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index) { OPJ_UINT32 i; opj_simple_mcc_decorrelation_data_t * l_mcc_record; @@ -5721,7 +5809,7 @@ OPJ_BOOL opj_j2k_add_mct(opj_tcp_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_ return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_cbd( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_cbd( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -5853,12 +5941,11 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) opj_j2k_t* opj_j2k_create_compress(void) { - opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t)); if (!l_j2k) { return NULL; } - memset(l_j2k,0,sizeof(opj_j2k_t)); l_j2k->m_is_decoder = 0; l_j2k->m_cp.m_is_decoder = 0; @@ -5888,7 +5975,7 @@ opj_j2k_t* opj_j2k_create_compress(void) return l_j2k; } -int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){ +static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){ POC[0].tile = 1; POC[0].resno0 = 0; POC[0].compno0 = 0; @@ -5906,7 +5993,7 @@ int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){ return 2; } -void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager) +static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager) { /* Configure cinema parameters */ int i; @@ -6043,7 +6130,7 @@ void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *i } -OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager) +static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_event_mgr_t *p_manager) { OPJ_UINT32 i; @@ -6105,7 +6192,7 @@ OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, opj_ev return OPJ_TRUE; } -void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, +OPJ_BOOL opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager) @@ -6114,7 +6201,12 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_cp_t *cp = 00; if(!p_j2k || !parameters || ! image) { - return; + return OPJ_FALSE; + } + + if ((parameters->numresolution <= 0) || (parameters->numresolution > OPJ_J2K_MAXRLVLS)) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid number of resolutions : %d not in range [1,%d]\n", parameters->numresolution, OPJ_J2K_MAXRLVLS); + return OPJ_FALSE; } /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ @@ -6256,6 +6348,10 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, if (parameters->cp_fixed_alloc && parameters->cp_matrice) { size_t array_size = (size_t)parameters->tcp_numlayers * (size_t)parameters->numresolution * 3 * sizeof(OPJ_INT32); cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size); + if (!cp->m_specific_param.m_enc.m_matrice) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of user encoding parameters matrix \n"); + return OPJ_FALSE; + } memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size); } @@ -6269,11 +6365,36 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, /* comment string */ if(parameters->cp_comment) { - cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1); - if(cp->comment) { - strcpy(cp->comment, parameters->cp_comment); - } - } + cp->comment = (char*)opj_malloc(strlen(parameters->cp_comment) + 1U); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate copy of comment string\n"); + return OPJ_FALSE; + } + strcpy(cp->comment, parameters->cp_comment); + } else { + /* Create default comment for codestream */ + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + + /* UniPG>> */ +#ifdef USE_JPWL + cp->comment = (char*)opj_malloc(clen+strlen(version)+11); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n"); + return OPJ_FALSE; + } + sprintf(cp->comment,"%s%s with JPWL", comment, version); +#else + cp->comment = (char*)opj_malloc(clen+strlen(version)+1); + if(!cp->comment) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate comment string\n"); + return OPJ_FALSE; + } + sprintf(cp->comment,"%s%s", comment, version); +#endif + /* <tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t)); + if (!cp->tcps) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile coding parameters\n"); + return OPJ_FALSE; + } if (parameters->numpocs) { /* initialisation of POC */ opj_j2k_check_poc_val(parameters->POC,parameters->numpocs, (OPJ_UINT32)parameters->numresolution, image->numcomps, (OPJ_UINT32)parameters->tcp_numlayers, p_manager); @@ -6408,24 +6533,54 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, } tcp->tccps = (opj_tccp_t*) opj_calloc(image->numcomps, sizeof(opj_tccp_t)); - + if (!tcp->tccps) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate tile component coding parameters\n"); + return OPJ_FALSE; + } if (parameters->mct_data) { OPJ_UINT32 lMctSize = image->numcomps * image->numcomps * (OPJ_UINT32)sizeof(OPJ_FLOAT32); OPJ_FLOAT32 * lTmpBuf = (OPJ_FLOAT32*)opj_malloc(lMctSize); OPJ_INT32 * l_dc_shift = (OPJ_INT32 *) ((OPJ_BYTE *) parameters->mct_data + lMctSize); + if (!lTmpBuf) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate temp buffer\n"); + return OPJ_FALSE; + } + tcp->mct = 2; tcp->m_mct_coding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); + if (! tcp->m_mct_coding_matrix) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT coding matrix \n"); + return OPJ_FALSE; + } memcpy(tcp->m_mct_coding_matrix,parameters->mct_data,lMctSize); memcpy(lTmpBuf,parameters->mct_data,lMctSize); tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(lMctSize); - assert(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps)); + if (! tcp->m_mct_decoding_matrix) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT decoding matrix \n"); + return OPJ_FALSE; + } + if(opj_matrix_inversion_f(lTmpBuf,(tcp->m_mct_decoding_matrix),image->numcomps) == OPJ_FALSE) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Failed to inverse encoder MCT decoding matrix \n"); + return OPJ_FALSE; + } tcp->mct_norms = (OPJ_FLOAT64*) opj_malloc(image->numcomps * sizeof(OPJ_FLOAT64)); - + if (! tcp->mct_norms) { + opj_free(lTmpBuf); + lTmpBuf = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to allocate encoder MCT norms \n"); + return OPJ_FALSE; + } opj_calculate_norms(tcp->mct_norms,image->numcomps,tcp->m_mct_decoding_matrix); opj_free(lTmpBuf); @@ -6434,9 +6589,22 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, tccp->m_dc_level_shift = l_dc_shift[i]; } - opj_j2k_setup_mct_encoding(tcp,image); + if (opj_j2k_setup_mct_encoding(tcp,image) == OPJ_FALSE) { + /* free will be handled by opj_j2k_destroy */ + opj_event_msg(p_manager, EVT_ERROR, "Failed to setup j2k mct encoding\n"); + return OPJ_FALSE; + } } else { + if(tcp->mct==1 && image->numcomps >= 3) { /* RGB->YCC MCT is enabled */ + if ((image->comps[0].dx != image->comps[1].dx) || + (image->comps[0].dx != image->comps[2].dx) || + (image->comps[0].dy != image->comps[1].dy) || + (image->comps[0].dy != image->comps[2].dy)) { + opj_event_msg(p_manager, EVT_WARNING, "Cannot perform MCT on components with different sizes. Disabling MCT.\n"); + tcp->mct = 0; + } + } for (i = 0; i < image->numcomps; i++) { opj_tccp_t *tccp = &tcp->tccps[i]; opj_image_comp_t * l_comp = &(image->comps[i]); @@ -6523,6 +6691,7 @@ void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_free(parameters->mct_data); parameters->mct_data = 00; } + return OPJ_TRUE; } static OPJ_BOOL opj_j2k_add_mhmarker(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) @@ -6626,7 +6795,11 @@ OPJ_BOOL opj_j2k_read_header( opj_stream_private_t *p_stream, } /* customization of the validation */ - opj_j2k_setup_decoding_validation(p_j2k); + if (! opj_j2k_setup_decoding_validation(p_j2k, p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_j2k_exec(p_j2k, p_j2k->m_validation_list, p_stream,p_manager)) { @@ -6636,7 +6809,11 @@ OPJ_BOOL opj_j2k_read_header( opj_stream_private_t *p_stream, } /* customization of the encoding */ - opj_j2k_setup_header_reading(p_j2k); + if (! opj_j2k_setup_header_reading(p_j2k, p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } /* read header */ if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { @@ -6661,30 +6838,42 @@ OPJ_BOOL opj_j2k_read_header( opj_stream_private_t *p_stream, return OPJ_TRUE; } -void opj_j2k_setup_header_reading (opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_setup_header_reading (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* preconditions*/ assert(p_j2k != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_read_header_procedure); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_read_header_procedure, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_copy_default_tcp_and_create_tcd); - + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_copy_default_tcp_and_create_tcd, p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; } -void opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_setup_decoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* preconditions*/ assert(p_j2k != 00); + assert(p_manager != 00); + + if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list,(opj_procedure)opj_j2k_build_decoder, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list,(opj_procedure)opj_j2k_decoding_validation, p_manager)) { + return OPJ_FALSE; + } - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_decoder); - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_decoding_validation); /* DEVELOPER CORNER, add your custom validation procedure */ - + return OPJ_TRUE; } -OPJ_BOOL opj_j2k_mct_validation ( opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_mct_validation ( opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -6870,7 +7059,7 @@ OPJ_BOOL opj_j2k_setup_mct_encoding(opj_tcp_t * p_tcp, opj_image_t * p_image) return OPJ_TRUE; } -OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -6882,7 +7071,7 @@ OPJ_BOOL opj_j2k_build_decoder (opj_j2k_t * p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -6894,7 +7083,7 @@ OPJ_BOOL opj_j2k_build_encoder (opj_j2k_t * p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { @@ -6915,12 +7104,20 @@ OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k, /* make sure a validation list is present */ l_is_valid &= (p_j2k->m_validation_list != 00); - if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + /* ISO 15444-1:2004 states between 1 & 33 (0 -> 32) */ + /* 33 (32) would always fail the check below (if a cast to 64bits was done) */ + /* FIXME Shall we change OPJ_J2K_MAXRLVLS to 32 ? */ + if ((p_j2k->m_cp.tcps->tccps->numresolutions <= 0) || (p_j2k->m_cp.tcps->tccps->numresolutions > 32)) { opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); return OPJ_FALSE; } - if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) { + if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) { + opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); + return OPJ_FALSE; + } + + if ((p_j2k->m_cp.tdy) < (OPJ_UINT32) (1 << (p_j2k->m_cp.tcps->tccps->numresolutions - 1U))) { opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n"); return OPJ_FALSE; } @@ -6929,7 +7126,7 @@ OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k, return l_is_valid; } -OPJ_BOOL opj_j2k_decoding_validation ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_decoding_validation ( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -6959,13 +7156,16 @@ OPJ_BOOL opj_j2k_decoding_validation ( opj_j2k_t *p_j2k, return l_is_valid; } -OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager) { OPJ_UINT32 l_current_marker; OPJ_UINT32 l_marker_size; const opj_dec_memory_marker_handler_t * l_marker_handler = 00; + OPJ_BOOL l_has_siz = 0; + OPJ_BOOL l_has_cod = 0; + OPJ_BOOL l_has_qcd = 0; /* preconditions */ assert(p_stream != 00); @@ -6995,7 +7195,7 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, /* Check if the current marker ID is valid */ if (l_current_marker < 0xff00) { - opj_event_msg(p_manager, EVT_ERROR, "We expected read a marker ID (0xff--) instead of %.8x\n", l_current_marker); + opj_event_msg(p_manager, EVT_ERROR, "A marker ID was expected (0xff--) instead of %.8x\n", l_current_marker); return OPJ_FALSE; } @@ -7015,6 +7215,19 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, l_marker_handler = opj_j2k_get_marker_handler(l_current_marker); } + if (l_marker_handler->id == J2K_MS_SIZ) { + /* Mark required SIZ marker as found */ + l_has_siz = 1; + } + if (l_marker_handler->id == J2K_MS_COD) { + /* Mark required COD marker as found */ + l_has_cod = 1; + } + if (l_marker_handler->id == J2K_MS_QCD) { + /* Mark required QCD marker as found */ + l_has_qcd = 1; + } + /* Check if the marker is known and if it is the right place to find it */ if (! (p_j2k->m_specific_param.m_decoder.m_state & l_marker_handler->states) ) { opj_event_msg(p_manager, EVT_ERROR, "Marker is not compliant with its position\n"); @@ -7077,6 +7290,24 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2); } + if (l_has_siz == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required SIZ marker not found in main header\n"); + return OPJ_FALSE; + } + if (l_has_cod == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required COD marker not found in main header\n"); + return OPJ_FALSE; + } + if (l_has_qcd == 0) { + opj_event_msg(p_manager, EVT_ERROR, "required QCD marker not found in main header\n"); + return OPJ_FALSE; + } + + if (! opj_j2k_merge_ppm(&(p_j2k->m_cp), p_manager)) { + opj_event_msg(p_manager, EVT_ERROR, "Failed to merge PPM data\n"); + return OPJ_FALSE; + } + opj_event_msg(p_manager, EVT_INFO, "Main header has been correctly decoded.\n"); /* Position of the last element if the main header */ @@ -7088,7 +7319,7 @@ OPJ_BOOL opj_j2k_read_header_procedure( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_exec ( opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_exec ( opj_j2k_t * p_j2k, opj_procedure_list_t * p_procedure_list, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -7154,8 +7385,15 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd ( opj_j2k_t * p_j2 /*Copy default coding parameters into the current tile coding parameters*/ memcpy(l_tcp, l_default_tcp, sizeof(opj_tcp_t)); /* Initialize some values of the current tile coding parameters*/ + l_tcp->cod = 0; l_tcp->ppt = 0; l_tcp->ppt_data = 00; + /* Remove memory not owned by this tile in case of early error return. */ + l_tcp->m_mct_decoding_matrix = 00; + l_tcp->m_nb_max_mct_records = 0; + l_tcp->m_mct_records = 00; + l_tcp->m_nb_max_mcc_records = 0; + l_tcp->m_mcc_records = 00; /* Reconnect the tile-compo coding parameters pointer to the current tile coding parameters*/ l_tcp->tccps = l_current_tccp; @@ -7193,6 +7431,8 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd ( opj_j2k_t * p_j2 ++l_src_mct_rec; ++l_dest_mct_rec; + /* Update with each pass to free exactly what has been allocated on early return. */ + l_tcp->m_nb_max_mct_records += 1; } /* Get the mcc_record of the dflt_tile_cp and copy them into the current tile cp*/ @@ -7202,6 +7442,7 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd ( opj_j2k_t * p_j2 return OPJ_FALSE; } memcpy(l_tcp->m_mcc_records,l_default_tcp->m_mcc_records,l_mcc_records_size); + l_tcp->m_nb_max_mcc_records = l_default_tcp->m_nb_max_mcc_records; /* Copy the mcc record data from dflt_tile_cp to the current tile*/ l_src_mcc_rec = l_default_tcp->m_mcc_records; @@ -7246,7 +7487,7 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd ( opj_j2k_t * p_j2 return OPJ_TRUE; } -const opj_dec_memory_marker_handler_t * opj_j2k_get_marker_handler (OPJ_UINT32 p_id) +static const opj_dec_memory_marker_handler_t * opj_j2k_get_marker_handler (OPJ_UINT32 p_id) { const opj_dec_memory_marker_handler_t *e; for (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) { @@ -7359,66 +7600,78 @@ void j2k_destroy_cstr_index (opj_codestream_index_t *p_cstr_ind) } } -void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp) +static void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp) { - if (p_tcp == 00) { - return; - } + if (p_tcp == 00) { + return; + } + + if (p_tcp->ppt_markers != 00) { + OPJ_UINT32 i; + for (i = 0U; i < p_tcp->ppt_markers_count; ++i) { + if (p_tcp->ppt_markers[i].m_data != NULL) { + opj_free(p_tcp->ppt_markers[i].m_data); + } + } + p_tcp->ppt_markers_count = 0U; + opj_free(p_tcp->ppt_markers); + p_tcp->ppt_markers = NULL; + } + + if (p_tcp->ppt_buffer != 00) { + opj_free(p_tcp->ppt_buffer); + p_tcp->ppt_buffer = 00; + } + + if (p_tcp->tccps != 00) { + opj_free(p_tcp->tccps); + p_tcp->tccps = 00; + } + + if (p_tcp->m_mct_coding_matrix != 00) { + opj_free(p_tcp->m_mct_coding_matrix); + p_tcp->m_mct_coding_matrix = 00; + } + + if (p_tcp->m_mct_decoding_matrix != 00) { + opj_free(p_tcp->m_mct_decoding_matrix); + p_tcp->m_mct_decoding_matrix = 00; + } + + if (p_tcp->m_mcc_records) { + opj_free(p_tcp->m_mcc_records); + p_tcp->m_mcc_records = 00; + p_tcp->m_nb_max_mcc_records = 0; + p_tcp->m_nb_mcc_records = 0; + } + + if (p_tcp->m_mct_records) { + opj_mct_data_t * l_mct_data = p_tcp->m_mct_records; + OPJ_UINT32 i; + + for (i=0;im_nb_mct_records;++i) { + if (l_mct_data->m_data) { + opj_free(l_mct_data->m_data); + l_mct_data->m_data = 00; + } + + ++l_mct_data; + } + + opj_free(p_tcp->m_mct_records); + p_tcp->m_mct_records = 00; + } - if (p_tcp->ppt_buffer != 00) { - opj_free(p_tcp->ppt_buffer); - p_tcp->ppt_buffer = 00; - } + if (p_tcp->mct_norms != 00) { + opj_free(p_tcp->mct_norms); + p_tcp->mct_norms = 00; + } - if (p_tcp->tccps != 00) { - opj_free(p_tcp->tccps); - p_tcp->tccps = 00; - } - - if (p_tcp->m_mct_coding_matrix != 00) { - opj_free(p_tcp->m_mct_coding_matrix); - p_tcp->m_mct_coding_matrix = 00; - } - - if (p_tcp->m_mct_decoding_matrix != 00) { - opj_free(p_tcp->m_mct_decoding_matrix); - p_tcp->m_mct_decoding_matrix = 00; - } - - if (p_tcp->m_mcc_records) { - opj_free(p_tcp->m_mcc_records); - p_tcp->m_mcc_records = 00; - p_tcp->m_nb_max_mcc_records = 0; - p_tcp->m_nb_mcc_records = 0; - } - - if (p_tcp->m_mct_records) { - opj_mct_data_t * l_mct_data = p_tcp->m_mct_records; - OPJ_UINT32 i; - - for (i=0;im_nb_mct_records;++i) { - if (l_mct_data->m_data) { - opj_free(l_mct_data->m_data); - l_mct_data->m_data = 00; - } - - ++l_mct_data; - } - - opj_free(p_tcp->m_mct_records); - p_tcp->m_mct_records = 00; - } - - if (p_tcp->mct_norms != 00) { - opj_free(p_tcp->mct_norms); - p_tcp->mct_norms = 00; - } - - opj_j2k_tcp_data_destroy(p_tcp); + opj_j2k_tcp_data_destroy(p_tcp); } -void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp) +static void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp) { if (p_tcp->m_data) { opj_free(p_tcp->m_data); @@ -7427,39 +7680,153 @@ void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp) } } -void opj_j2k_cp_destroy (opj_cp_t *p_cp) +static void opj_j2k_cp_destroy (opj_cp_t *p_cp) { - OPJ_UINT32 l_nb_tiles; - opj_tcp_t * l_current_tile = 00; - OPJ_UINT32 i; + OPJ_UINT32 l_nb_tiles; + opj_tcp_t * l_current_tile = 00; - if (p_cp == 00) - { - return; - } - if (p_cp->tcps != 00) - { - l_current_tile = p_cp->tcps; - l_nb_tiles = p_cp->th * p_cp->tw; + if (p_cp == 00) + { + return; + } + if (p_cp->tcps != 00) + { + OPJ_UINT32 i; + l_current_tile = p_cp->tcps; + l_nb_tiles = p_cp->th * p_cp->tw; + + for (i = 0U; i < l_nb_tiles; ++i) + { + opj_j2k_tcp_destroy(l_current_tile); + ++l_current_tile; + } + opj_free(p_cp->tcps); + p_cp->tcps = 00; + } + if (p_cp->ppm_markers != 00) { + OPJ_UINT32 i; + for (i = 0U; i < p_cp->ppm_markers_count; ++i) { + if (p_cp->ppm_markers[i].m_data != NULL) { + opj_free(p_cp->ppm_markers[i].m_data); + } + } + p_cp->ppm_markers_count = 0U; + opj_free(p_cp->ppm_markers); + p_cp->ppm_markers = NULL; + } + opj_free(p_cp->ppm_buffer); + p_cp->ppm_buffer = 00; + p_cp->ppm_data = NULL; /* ppm_data belongs to the allocated buffer pointed by ppm_buffer */ + opj_free(p_cp->comment); + p_cp->comment = 00; + if (! p_cp->m_is_decoder) + { + opj_free(p_cp->m_specific_param.m_enc.m_matrice); + p_cp->m_specific_param.m_enc.m_matrice = 00; + } +} - for (i = 0; i < l_nb_tiles; ++i) - { - opj_j2k_tcp_destroy(l_current_tile); - ++l_current_tile; - } - opj_free(p_cp->tcps); - p_cp->tcps = 00; - } - opj_free(p_cp->ppm_buffer); - p_cp->ppm_buffer = 00; - p_cp->ppm_data = NULL; /* ppm_data belongs to the allocated buffer pointed by ppm_buffer */ - opj_free(p_cp->comment); - p_cp->comment = 00; - if (! p_cp->m_is_decoder) - { - opj_free(p_cp->m_specific_param.m_enc.m_matrice); - p_cp->m_specific_param.m_enc.m_matrice = 00; - } +static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t *p_stream, OPJ_UINT32 tile_no, OPJ_BOOL* p_correction_needed, opj_event_mgr_t * p_manager ) +{ + OPJ_BYTE l_header_data[10]; + OPJ_OFF_T l_stream_pos_backup; + OPJ_UINT32 l_current_marker; + OPJ_UINT32 l_marker_size; + OPJ_UINT32 l_tile_no, l_tot_len, l_current_part, l_num_parts; + + /* initialize to no correction needed */ + *p_correction_needed = OPJ_FALSE; + + if (!opj_stream_has_seek(p_stream)) { + /* We can't do much in this case, seek is needed */ + return OPJ_TRUE; + } + + l_stream_pos_backup = opj_stream_tell(p_stream); + if (l_stream_pos_backup == -1) { + /* let's do nothing */ + return OPJ_TRUE; + } + + for (;;) { + /* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */ + if (opj_stream_read_data(p_stream,l_header_data, 2, p_manager) != 2) { + /* assume all is OK */ + if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; + } + + /* Read 2 bytes from buffer as the new marker ID */ + opj_read_bytes(l_header_data, &l_current_marker, 2); + + if (l_current_marker != J2K_MS_SOT) { + /* assume all is OK */ + if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; + } + + /* Try to read 2 bytes (the marker size) from stream and copy them into the buffer */ + if (opj_stream_read_data(p_stream, l_header_data, 2, p_manager) != 2) { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + /* Read 2 bytes from the buffer as the marker size */ + opj_read_bytes(l_header_data, &l_marker_size, 2); + + /* Check marker size for SOT Marker */ + if (l_marker_size != 10) { + opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n"); + return OPJ_FALSE; + } + l_marker_size -= 2; + + if (opj_stream_read_data(p_stream, l_header_data, l_marker_size, p_manager) != l_marker_size) { + opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n"); + return OPJ_FALSE; + } + + if (! opj_j2k_get_sot_values(l_header_data, l_marker_size, &l_tile_no, &l_tot_len, &l_current_part, &l_num_parts, p_manager)) { + return OPJ_FALSE; + } + + if (l_tile_no == tile_no) { + /* we found what we were looking for */ + break; + } + + if ((l_tot_len == 0U) || (l_tot_len < 14U)) { + /* last SOT until EOC or invalid Psot value */ + /* assume all is OK */ + if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; + } + l_tot_len -= 12U; + /* look for next SOT marker */ + if (opj_stream_skip(p_stream, (OPJ_OFF_T)(l_tot_len), p_manager) != (OPJ_OFF_T)(l_tot_len)) { + /* assume all is OK */ + if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; + } + } + + /* check for correction */ + if (l_current_part == l_num_parts) { + *p_correction_needed = OPJ_TRUE; + } + + if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; } OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, @@ -7476,7 +7843,6 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, OPJ_UINT32 l_marker_size; const opj_dec_memory_marker_handler_t * l_marker_handler = 00; opj_tcp_t * l_tcp = NULL; - OPJ_UINT32 l_nb_tiles; /* preconditions */ assert(p_stream != 00); @@ -7513,6 +7879,12 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, /* Read 2 bytes from the buffer as the marker size */ opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2); + /* Check marker size (does not include marker ID but includes marker size) */ + if (l_marker_size < 2) { + opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n"); + return OPJ_FALSE; + } + /* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */ if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) { p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC; @@ -7537,7 +7909,14 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, /* Check if the marker size is compatible with the header data size */ if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) { - OPJ_BYTE *new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size); + OPJ_BYTE *new_header_data = NULL; + /* If we are here, this means we consider this marker as known & we will read it */ + /* Check enough bytes left in stream before allocation */ + if ((OPJ_OFF_T)l_marker_size > opj_stream_get_number_byte_left(p_stream)) { + opj_event_msg(p_manager, EVT_ERROR, "Marker size inconsistent with stream length\n"); + return OPJ_FALSE; + } + new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size); if (! new_header_data) { opj_free(p_j2k->m_specific_param.m_decoder.m_header_data); p_j2k->m_specific_param.m_decoder.m_header_data = NULL; @@ -7613,7 +7992,30 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, if (! opj_j2k_read_sod(p_j2k, p_stream, p_manager)) { return OPJ_FALSE; } + if (p_j2k->m_specific_param.m_decoder.m_can_decode && !p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked) { + /* Issue 254 */ + OPJ_BOOL l_correction_needed; + + p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1; + if(!opj_j2k_need_nb_tile_parts_correction(p_stream, p_j2k->m_current_tile_number, &l_correction_needed, p_manager)) { + opj_event_msg(p_manager, EVT_ERROR, "opj_j2k_apply_nb_tile_parts_correction error\n"); + return OPJ_FALSE; + } + if (l_correction_needed) { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th; + OPJ_UINT32 l_tile_no; + p_j2k->m_specific_param.m_decoder.m_can_decode = 0; + p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction = 1; + /* correct tiles */ + for (l_tile_no = 0U; l_tile_no < l_nb_tiles; ++l_tile_no) { + if (p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts != 0U) { + p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts+=1; + } + } + opj_event_msg(p_manager, EVT_WARNING, "Non conformant codestream TPsot==TNsot.\n"); + } + } if (! p_j2k->m_specific_param.m_decoder.m_can_decode){ /* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */ if (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) { @@ -7652,8 +8054,8 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, /* FIXME DOC ???*/ if ( ! p_j2k->m_specific_param.m_decoder.m_can_decode) { + OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number; - l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) { ++p_j2k->m_current_tile_number; @@ -7666,14 +8068,18 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k, } } + if (! opj_j2k_merge_ppt(p_j2k->m_cp.tcps + p_j2k->m_current_tile_number, p_manager)) { + opj_event_msg(p_manager, EVT_ERROR, "Failed to merge PPT data\n"); + return OPJ_FALSE; + } /*FIXME ???*/ - if (! opj_tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) { + if (! opj_tcd_init_decode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number, p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Cannot decode tile, memory error\n"); return OPJ_FALSE; } opj_event_msg(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n", - p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); + p_j2k->m_current_tile_number+1, (p_j2k->m_cp.th * p_j2k->m_cp.tw)); *p_tile_index = p_j2k->m_current_tile_number; *p_go_on = OPJ_TRUE; @@ -7720,7 +8126,7 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, l_tcp->m_data, l_tcp->m_data_size, p_tile_index, - p_j2k->cstr_index) ) { + p_j2k->cstr_index, p_manager) ) { opj_j2k_tcp_destroy(l_tcp); p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/ opj_event_msg(p_manager, EVT_ERROR, "Failed to decode.\n"); @@ -7758,13 +8164,13 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, p_j2k->m_specific_param.m_decoder.m_state = 0x0100;/*FIXME J2K_DEC_STATE_EOC;*/ } else if (l_current_marker != J2K_MS_SOT) - { - opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); - + { if(opj_stream_get_number_byte_left(p_stream) == 0) { p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC; + opj_event_msg(p_manager, EVT_WARNING, "Stream does not end with EOC\n"); return OPJ_TRUE; } + opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n"); return OPJ_FALSE; } } @@ -7772,16 +8178,16 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image) +static OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_image_t* p_output_image) { OPJ_UINT32 i,j,k = 0; OPJ_UINT32 l_width_src,l_height_src; OPJ_UINT32 l_width_dest,l_height_dest; OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src; - OPJ_INT32 l_start_offset_src, l_line_offset_src, l_end_offset_src ; + OPJ_SIZE_T l_start_offset_src, l_line_offset_src, l_end_offset_src ; OPJ_UINT32 l_start_x_dest , l_start_y_dest; OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest; - OPJ_INT32 l_start_offset_dest, l_line_offset_dest; + OPJ_SIZE_T l_start_offset_dest, l_line_offset_dest; opj_image_comp_t * l_img_comp_src = 00; opj_image_comp_t * l_img_comp_dest = 00; @@ -7803,7 +8209,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im /* Allocate output component buffer if necessary */ if (!l_img_comp_dest->data) { - l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_img_comp_dest->w * l_img_comp_dest->h, sizeof(OPJ_INT32)); + l_img_comp_dest->data = (OPJ_INT32*) opj_calloc((OPJ_SIZE_T)l_img_comp_dest->w * (OPJ_SIZE_T)l_img_comp_dest->h, sizeof(OPJ_INT32)); if (! l_img_comp_dest->data) { return OPJ_FALSE; } @@ -7837,9 +8243,9 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im l_height_src = (OPJ_UINT32)(l_res->y1 - l_res->y0); /* Border of the current output component*/ - l_x0_dest = (OPJ_UINT32)opj_int_ceildivpow2((OPJ_INT32)l_img_comp_dest->x0, (OPJ_INT32)l_img_comp_dest->factor); - l_y0_dest = (OPJ_UINT32)opj_int_ceildivpow2((OPJ_INT32)l_img_comp_dest->y0, (OPJ_INT32)l_img_comp_dest->factor); - l_x1_dest = l_x0_dest + l_img_comp_dest->w; + l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); + l_y0_dest = opj_uint_ceildivpow2(l_img_comp_dest->y0, l_img_comp_dest->factor); + l_x1_dest = l_x0_dest + l_img_comp_dest->w; /* can't overflow given that image->x1 is uint32 */ l_y1_dest = l_y0_dest + l_img_comp_dest->h; /*if (i == 0) { @@ -7870,7 +8276,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im } } else { - l_start_x_dest = 0 ; + l_start_x_dest = 0U; l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0; if ( l_x1_dest >= (OPJ_UINT32)l_res->x1 ) { @@ -7897,7 +8303,7 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im } } else { - l_start_y_dest = 0 ; + l_start_y_dest = 0U; l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0; if ( l_y1_dest >= (OPJ_UINT32)l_res->y1 ) { @@ -7920,13 +8326,13 @@ OPJ_BOOL opj_j2k_update_image_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data, opj_im /*-----*/ /* Compute the input buffer offset */ - l_start_offset_src = l_offset_x0_src + l_offset_y0_src * (OPJ_INT32)l_width_src; - l_line_offset_src = l_offset_x1_src + l_offset_x0_src; - l_end_offset_src = l_offset_y1_src * (OPJ_INT32)l_width_src - l_offset_x0_src; + l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src * (OPJ_SIZE_T)l_width_src; + l_line_offset_src = (OPJ_SIZE_T)l_offset_x1_src + (OPJ_SIZE_T)l_offset_x0_src; + l_end_offset_src = (OPJ_SIZE_T)l_offset_y1_src * (OPJ_SIZE_T)l_width_src - (OPJ_SIZE_T)l_offset_x0_src; /* Compute the output buffer offset */ - l_start_offset_dest = (OPJ_INT32)(l_start_x_dest + l_start_y_dest * l_img_comp_dest->w); - l_line_offset_dest = (OPJ_INT32)(l_img_comp_dest->w - l_width_dest); + l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest * (OPJ_SIZE_T)l_img_comp_dest->w; + l_line_offset_dest = (OPJ_SIZE_T)l_img_comp_dest->w - (OPJ_SIZE_T)l_width_dest; /* Move the output buffer to the first place where we will write*/ l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; @@ -8192,23 +8598,25 @@ OPJ_BOOL opj_j2k_set_decode_area( opj_j2k_t *p_j2k, opj_j2k_t* opj_j2k_create_decompress(void) { - opj_j2k_t *l_j2k = (opj_j2k_t*) opj_malloc(sizeof(opj_j2k_t)); + opj_j2k_t *l_j2k = (opj_j2k_t*) opj_calloc(1,sizeof(opj_j2k_t)); if (!l_j2k) { return 00; } - memset(l_j2k,0,sizeof(opj_j2k_t)); l_j2k->m_is_decoder = 1; l_j2k->m_cp.m_is_decoder = 1; - l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_malloc(sizeof(opj_tcp_t)); +#ifdef OPJ_DISABLE_TPSOT_FIX + l_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1; +#endif + + l_j2k->m_specific_param.m_decoder.m_default_tcp = (opj_tcp_t*) opj_calloc(1,sizeof(opj_tcp_t)); if (!l_j2k->m_specific_param.m_decoder.m_default_tcp) { opj_j2k_destroy(l_j2k); return 00; } - memset(l_j2k->m_specific_param.m_decoder.m_default_tcp,0,sizeof(opj_tcp_t)); - l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_malloc(OPJ_J2K_DEFAULT_HEADER_SIZE); + l_j2k->m_specific_param.m_decoder.m_header_data = (OPJ_BYTE *) opj_calloc(1,OPJ_J2K_DEFAULT_HEADER_SIZE); if (! l_j2k->m_specific_param.m_decoder.m_header_data) { opj_j2k_destroy(l_j2k); return 00; @@ -8222,16 +8630,11 @@ opj_j2k_t* opj_j2k_create_decompress(void) /* codestream index creation */ l_j2k->cstr_index = opj_j2k_create_cstr_index(); - - /*(opj_codestream_index_t*) opj_malloc(sizeof(opj_codestream_index_t)); if (!l_j2k->cstr_index){ opj_j2k_destroy(l_j2k); - return NULL; + return 00; } - l_j2k->cstr_index->marker = (opj_marker_info_t*) opj_malloc(100 * sizeof(opj_marker_info_t)); -*/ - /* validation list creation */ l_j2k->m_validation_list = opj_procedure_list_create(); if (! l_j2k->m_validation_list) { @@ -8249,7 +8652,7 @@ opj_j2k_t* opj_j2k_create_decompress(void) return l_j2k; } -opj_codestream_index_t* opj_j2k_create_cstr_index(void) +static opj_codestream_index_t* opj_j2k_create_cstr_index(void) { opj_codestream_index_t* cstr_index = (opj_codestream_index_t*) opj_calloc(1,sizeof(opj_codestream_index_t)); @@ -8260,15 +8663,17 @@ opj_codestream_index_t* opj_j2k_create_cstr_index(void) cstr_index->marknum = 0; cstr_index->marker = (opj_marker_info_t*) opj_calloc(cstr_index->maxmarknum, sizeof(opj_marker_info_t)); - if (!cstr_index-> marker) + if (!cstr_index-> marker) { + opj_free(cstr_index); return NULL; + } cstr_index->tile_index = NULL; return cstr_index; } -OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size ( opj_j2k_t *p_j2k, +static OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size ( opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no ) { @@ -8295,7 +8700,53 @@ OPJ_UINT32 opj_j2k_get_SPCod_SPCoc_size ( opj_j2k_t *p_j2k, } } -OPJ_BOOL opj_j2k_write_SPCod_SPCoc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_compare_SPCod_SPCoc(opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no) +{ + OPJ_UINT32 i; + opj_cp_t *l_cp = NULL; + opj_tcp_t *l_tcp = NULL; + opj_tccp_t *l_tccp0 = NULL; + opj_tccp_t *l_tccp1 = NULL; + + /* preconditions */ + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp0 = &l_tcp->tccps[p_first_comp_no]; + l_tccp1 = &l_tcp->tccps[p_second_comp_no]; + + if (l_tccp0->numresolutions != l_tccp1->numresolutions) { + return OPJ_FALSE; + } + if (l_tccp0->cblkw != l_tccp1->cblkw) { + return OPJ_FALSE; + } + if (l_tccp0->cblkh != l_tccp1->cblkh) { + return OPJ_FALSE; + } + if (l_tccp0->cblksty != l_tccp1->cblksty) { + return OPJ_FALSE; + } + if (l_tccp0->qmfbid != l_tccp1->qmfbid) { + return OPJ_FALSE; + } + if ((l_tccp0->csty & J2K_CCP_CSTY_PRT) != (l_tccp1->csty & J2K_CCP_CSTY_PRT)) { + return OPJ_FALSE; + } + + for (i = 0U; i < l_tccp0->numresolutions; ++i) { + if (l_tccp0->prcw[i] != l_tccp1->prcw[i]) { + return OPJ_FALSE; + } + if (l_tccp0->prch[i] != l_tccp1->prch[i]) { + return OPJ_FALSE; + } + } + return OPJ_TRUE; +} + +static OPJ_BOOL opj_j2k_write_SPCod_SPCoc( opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no, OPJ_BYTE * p_data, @@ -8361,7 +8812,7 @@ OPJ_BOOL opj_j2k_write_SPCod_SPCoc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, OPJ_UINT32 compno, OPJ_BYTE * p_header_data, OPJ_UINT32 * p_header_size, @@ -8421,6 +8872,12 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, ++l_current_ptr; l_tccp->cblkh += 2; + if ((l_tccp->cblkw > 10) || (l_tccp->cblkh > 10) || ((l_tccp->cblkw + l_tccp->cblkh) > 12)) { + opj_event_msg(p_manager, EVT_ERROR, "Error reading SPCod SPCoc element, Invalid cblkw/cblkh combination\n"); + return OPJ_FALSE; + } + + opj_read_bytes(l_current_ptr,&l_tccp->cblksty ,1); /* SPcoc (G) */ ++l_current_ptr; @@ -8439,6 +8896,11 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, for (i = 0; i < l_tccp->numresolutions; ++i) { opj_read_bytes(l_current_ptr,&l_tmp ,1); /* SPcoc (I_i) */ ++l_current_ptr; + /* Precinct exponent 0 is only allowed for lowest resolution level (Table A.21) */ + if ((i != 0) && (((l_tmp & 0xf) == 0) || ((l_tmp >> 4) == 0))) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid precinct size\n"); + return OPJ_FALSE; + } l_tccp->prcw[i] = l_tmp & 0xf; l_tccp->prch[i] = l_tmp >> 4; } @@ -8473,7 +8935,7 @@ OPJ_BOOL opj_j2k_read_SPCod_SPCoc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k ) +static void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k ) { /* loop */ OPJ_UINT32 i; @@ -8506,7 +8968,7 @@ void opj_j2k_copy_tile_component_parameters( opj_j2k_t *p_j2k ) } } -OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k, +static OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no ) { @@ -8537,7 +8999,55 @@ OPJ_UINT32 opj_j2k_get_SQcd_SQcc_size ( opj_j2k_t *p_j2k, } } -OPJ_BOOL opj_j2k_write_SQcd_SQcc( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_compare_SQcd_SQcc(opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_first_comp_no, OPJ_UINT32 p_second_comp_no) +{ + opj_cp_t *l_cp = NULL; + opj_tcp_t *l_tcp = NULL; + opj_tccp_t *l_tccp0 = NULL; + opj_tccp_t *l_tccp1 = NULL; + OPJ_UINT32 l_band_no, l_num_bands; + + /* preconditions */ + assert(p_j2k != 00); + + l_cp = &(p_j2k->m_cp); + l_tcp = &l_cp->tcps[p_tile_no]; + l_tccp0 = &l_tcp->tccps[p_first_comp_no]; + l_tccp1 = &l_tcp->tccps[p_second_comp_no]; + + if (l_tccp0->qntsty != l_tccp1->qntsty ) { + return OPJ_FALSE; + } + if (l_tccp0->numgbits != l_tccp1->numgbits ) { + return OPJ_FALSE; + } + if (l_tccp0->qntsty == J2K_CCP_QNTSTY_SIQNT) { + l_num_bands = 1U; + } else { + l_num_bands = l_tccp0->numresolutions * 3U - 2U; + if (l_num_bands != (l_tccp1->numresolutions * 3U - 2U)) { + return OPJ_FALSE; + } + } + + for (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) { + if (l_tccp0->stepsizes[l_band_no].expn != l_tccp1->stepsizes[l_band_no].expn ) { + return OPJ_FALSE; + } + } + if (l_tccp0->qntsty != J2K_CCP_QNTSTY_NOQNT) + { + for (l_band_no = 0; l_band_no < l_num_bands; ++l_band_no) { + if (l_tccp0->stepsizes[l_band_no].mant != l_tccp1->stepsizes[l_band_no].mant ) { + return OPJ_FALSE; + } + } + } + return OPJ_TRUE; +} + + +static OPJ_BOOL opj_j2k_write_SQcd_SQcc( opj_j2k_t *p_j2k, OPJ_UINT32 p_tile_no, OPJ_UINT32 p_comp_no, OPJ_BYTE * p_data, @@ -8610,7 +9120,7 @@ OPJ_BOOL opj_j2k_write_SQcd_SQcc( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k, OPJ_UINT32 p_comp_no, OPJ_BYTE* p_header_data, OPJ_UINT32 * p_header_size, @@ -8727,7 +9237,7 @@ OPJ_BOOL opj_j2k_read_SQcd_SQcc(opj_j2k_t *p_j2k, return OPJ_TRUE; } -void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k ) +static void opj_j2k_copy_tile_quantization_parameters( opj_j2k_t *p_j2k ) { OPJ_UINT32 i; opj_cp_t *l_cp = NULL; @@ -8854,7 +9364,7 @@ void j2k_dump (opj_j2k_t* p_j2k, OPJ_INT32 flag, FILE* out_stream) } -void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream) +static void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream) { opj_codestream_index_t* cstr_index = p_j2k->cstr_index; OPJ_UINT32 it_marker, it_tile, it_tile_part; @@ -8923,7 +9433,7 @@ void opj_j2k_dump_MH_index(opj_j2k_t* p_j2k, FILE* out_stream) } -void opj_j2k_dump_MH_info(opj_j2k_t* p_j2k, FILE* out_stream) +static void opj_j2k_dump_MH_info(opj_j2k_t* p_j2k, FILE* out_stream) { fprintf(out_stream, "Codestream info from main header: {\n"); @@ -9163,7 +9673,7 @@ opj_codestream_index_t* j2k_get_cstr_index(opj_j2k_t* p_j2k) return l_cstr_index; } -OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k) { OPJ_UINT32 it_tile=0; @@ -9184,7 +9694,7 @@ OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k) return OPJ_TRUE; } -OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager) { @@ -9203,7 +9713,7 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, } l_max_data_size = 1000; - while (OPJ_TRUE) { + for (;;) { if (! opj_j2k_read_tile_header( p_j2k, &l_current_tile_no, &l_data_size, @@ -9260,14 +9770,18 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k, /** * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures. */ -static void opj_j2k_setup_decoding (opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_setup_decoding (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* preconditions*/ assert(p_j2k != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_tiles); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_tiles, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ + return OPJ_TRUE; } /* @@ -9310,14 +9824,14 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, * so move to the last SOT read */ if ( !(opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos+2, p_manager)) ){ opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); + opj_free(l_current_data); return OPJ_FALSE; } } else{ if ( !(opj_stream_read_seek(p_stream, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos+2, p_manager)) ) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); + opj_free(l_current_data); return OPJ_FALSE; } } @@ -9326,7 +9840,7 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; } - while (OPJ_TRUE) { + for (;;) { if (! opj_j2k_read_tile_header( p_j2k, &l_current_tile_no, &l_data_size, @@ -9372,9 +9886,10 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, if(l_current_tile_no == l_tile_no_to_dec) { - /* move into the codestream to the the first SOT (FIXME or not move?)*/ + /* move into the codestream to the first SOT (FIXME or not move?)*/ if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager) ) ) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); + opj_free(l_current_data); return OPJ_FALSE; } break; @@ -9393,14 +9908,18 @@ static OPJ_BOOL opj_j2k_decode_one_tile ( opj_j2k_t *p_j2k, /** * Sets up the procedures to do on decoding one tile. Developpers wanting to extend the library can add their own reading procedures. */ -static void opj_j2k_setup_decoding_tile (opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_setup_decoding_tile (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* preconditions*/ assert(p_j2k != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_one_tile); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_decode_one_tile, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ + return OPJ_TRUE; } OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, @@ -9412,7 +9931,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, if (!p_image) return OPJ_FALSE; - + p_j2k->m_output_image = opj_image_create0(); if (! (p_j2k->m_output_image)) { return OPJ_FALSE; @@ -9420,7 +9939,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, opj_copy_image_header(p_image, p_j2k->m_output_image); /* customization of the decoding */ - opj_j2k_setup_decoding(p_j2k); + opj_j2k_setup_decoding(p_j2k, p_manager); /* Decode the codestream */ if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { @@ -9516,7 +10035,7 @@ OPJ_BOOL opj_j2k_get_tile( opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = (OPJ_INT32)tile_index; /* customization of the decoding */ - opj_j2k_setup_decoding_tile(p_j2k); + opj_j2k_setup_decoding_tile(p_j2k, p_manager); /* Decode the codestream */ if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { @@ -9573,50 +10092,97 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { - OPJ_UINT32 i; + OPJ_UINT32 i, j; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_max_tile_size, l_current_tile_size; - OPJ_BYTE * l_current_data; + OPJ_UINT32 l_max_tile_size = 0, l_current_tile_size; + OPJ_BYTE * l_current_data = 00; + OPJ_BOOL l_reuse_data = OPJ_FALSE; + opj_tcd_t* p_tcd = 00; /* preconditions */ assert(p_j2k != 00); assert(p_stream != 00); assert(p_manager != 00); - - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); - return OPJ_FALSE; - } - l_max_tile_size = 1000; + + p_tcd = p_j2k->m_tcd; l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw; + if (l_nb_tiles == 1) { + l_reuse_data = OPJ_TRUE; +#ifdef __SSE__ + for (j=0;jm_tcd->image->numcomps;++j) { + opj_image_comp_t * l_img_comp = p_tcd->image->comps + j; + if (((size_t)l_img_comp->data & 0xFU) != 0U) { /* tile data shall be aligned on 16 bytes */ + l_reuse_data = OPJ_FALSE; + } + } +#endif + } for (i=0;im_tcd); - if (l_current_tile_size > l_max_tile_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size); - if (! l_new_current_data) { - opj_free(l_current_data); - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); - return OPJ_FALSE; + /* if we only have one tile, then simply set tile component data equal to image component data */ + /* otherwise, allocate the data */ + for (j=0;jm_tcd->image->numcomps;++j) { + opj_tcd_tilecomp_t* l_tilec = p_tcd->tcd_image->tiles->comps + j; + if (l_reuse_data) { + opj_image_comp_t * l_img_comp = p_tcd->image->comps + j; + l_tilec->data = l_img_comp->data; + l_tilec->ownsData = OPJ_FALSE; + } else { + if(! opj_alloc_tile_component_data(l_tilec)) { + opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." ); + if (l_current_data) { + opj_free(l_current_data); + } + return OPJ_FALSE; + } + } + } + l_current_tile_size = opj_tcd_get_encoded_tile_size(p_j2k->m_tcd); + if (!l_reuse_data) { + if (l_current_tile_size > l_max_tile_size) { + OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, l_current_tile_size); + if (! l_new_current_data) { + if (l_current_data) { + opj_free(l_current_data); + } + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to encode all tiles\n"); + return OPJ_FALSE; + } + l_current_data = l_new_current_data; + l_max_tile_size = l_current_tile_size; + } + + /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */ + /* 32 bit components @ 8 bit precision get converted to 8 bit */ + /* 32 bit components @ 16 bit precision get converted to 16 bit */ + opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data); + + /* now copy this data into the tile component */ + if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,l_current_data,l_current_tile_size)) { + opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); + opj_free(l_current_data); + return OPJ_FALSE; } - l_current_data = l_new_current_data; - l_max_tile_size = l_current_tile_size; } - opj_j2k_get_tile_data(p_j2k->m_tcd,l_current_data); - - if (! opj_j2k_post_write_tile (p_j2k,l_current_data,l_current_tile_size,p_stream,p_manager)) { + if (! opj_j2k_post_write_tile (p_j2k,p_stream,p_manager)) { + if (l_current_data) { + opj_free(l_current_data); + } return OPJ_FALSE; } } - opj_free(l_current_data); + if (l_current_data) { + opj_free(l_current_data); + } return OPJ_TRUE; } @@ -9625,7 +10191,9 @@ OPJ_BOOL opj_j2k_end_compress( opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* customization of the encoding */ - opj_j2k_setup_end_compress(p_j2k); + if (! opj_j2k_setup_end_compress(p_j2k, p_manager)) { + return OPJ_FALSE; + } if (! opj_j2k_exec (p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) { @@ -9646,6 +10214,10 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k, assert(p_manager != 00); p_j2k->m_private_image = opj_image_create0(); + if (! p_j2k->m_private_image) { + opj_event_msg(p_manager, EVT_ERROR, "Failed to allocate image header." ); + return OPJ_FALSE; + } opj_copy_image_header(p_image, p_j2k->m_private_image); /* TODO_MSD: Find a better way */ @@ -9661,7 +10233,9 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k, } /* customization of the validation */ - opj_j2k_setup_encoding_validation (p_j2k); + if (! opj_j2k_setup_encoding_validation (p_j2k, p_manager)) { + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_j2k_exec(p_j2k,p_j2k->m_validation_list,p_stream,p_manager)) { @@ -9669,7 +10243,9 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k, } /* customization of the encoding */ - opj_j2k_setup_header_writing(p_j2k); + if (! opj_j2k_setup_header_writing(p_j2k, p_manager)) { + return OPJ_FALSE; + } /* write header */ if (! opj_j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { @@ -9679,7 +10255,7 @@ OPJ_BOOL opj_j2k_start_compress(opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, +static OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_index, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) @@ -9697,44 +10273,68 @@ OPJ_BOOL opj_j2k_pre_write_tile ( opj_j2k_t * p_j2k, p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = 0; /* initialisation before tile encoding */ - if (! opj_tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number)) { + if (! opj_tcd_init_encode_tile(p_j2k->m_tcd, p_j2k->m_current_tile_number, p_manager)) { return OPJ_FALSE; } return OPJ_TRUE; } -void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) +static void opj_get_tile_dimensions(opj_image_t * l_image, + opj_tcd_tilecomp_t * l_tilec, + opj_image_comp_t * l_img_comp, + OPJ_UINT32* l_size_comp, + OPJ_UINT32* l_width, + OPJ_UINT32* l_height, + OPJ_UINT32* l_offset_x, + OPJ_UINT32* l_offset_y, + OPJ_UINT32* l_image_width, + OPJ_UINT32* l_stride, + OPJ_UINT32* l_tile_offset) { + OPJ_UINT32 l_remaining; + *l_size_comp = l_img_comp->prec >> 3; /* (/8) */ + l_remaining = l_img_comp->prec & 7; /* (%8) */ + if (l_remaining) { + *l_size_comp += 1; + } + + if (*l_size_comp == 3) { + *l_size_comp = 4; + } + + *l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); + *l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); + *l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); + *l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy); + *l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); + *l_stride = *l_image_width - *l_width; + *l_tile_offset = ((OPJ_UINT32)l_tilec->x0 - *l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - *l_offset_y) * *l_image_width; +} + +static void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) { OPJ_UINT32 i,j,k = 0; - OPJ_UINT32 l_width,l_height,l_stride, l_offset_x,l_offset_y, l_image_width; - opj_image_comp_t * l_img_comp = 00; - opj_tcd_tilecomp_t * l_tilec = 00; - opj_image_t * l_image = 00; - OPJ_UINT32 l_size_comp, l_remaining; - OPJ_INT32 * l_src_ptr; - l_tilec = p_tcd->tcd_image->tiles->comps; - l_image = p_tcd->image; - l_img_comp = l_image->comps; for (i=0;iimage->numcomps;++i) { - l_size_comp = l_img_comp->prec >> 3; /* (/8) */ - l_remaining = l_img_comp->prec & 7; /* (%8) */ - if (l_remaining) { - ++l_size_comp; - } + opj_image_t * l_image = p_tcd->image; + OPJ_INT32 * l_src_ptr; + opj_tcd_tilecomp_t * l_tilec = p_tcd->tcd_image->tiles->comps + i; + opj_image_comp_t * l_img_comp = l_image->comps + i; + OPJ_UINT32 l_size_comp,l_width,l_height,l_offset_x,l_offset_y, l_image_width,l_stride,l_tile_offset; - if (l_size_comp == 3) { - l_size_comp = 4; - } + opj_get_tile_dimensions(l_image, + l_tilec, + l_img_comp, + &l_size_comp, + &l_width, + &l_height, + &l_offset_x, + &l_offset_y, + &l_image_width, + &l_stride, + &l_tile_offset); - l_width = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); - l_height = (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); - l_offset_x = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); - l_offset_y = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->y0, (OPJ_INT32)l_img_comp->dy); - l_image_width = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)l_image->x1 - (OPJ_INT32)l_image->x0, (OPJ_INT32)l_img_comp->dx); - l_stride = l_image_width - l_width; - l_src_ptr = l_img_comp->data + ((OPJ_UINT32)l_tilec->x0 - l_offset_x) + ((OPJ_UINT32)l_tilec->y0 - l_offset_y) * l_image_width; + l_src_ptr = l_img_comp->data + l_tile_offset; switch (l_size_comp) { case 1: @@ -9801,19 +10401,13 @@ void opj_j2k_get_tile_data (opj_tcd_t * p_tcd, OPJ_BYTE * p_data) } break; } - - ++l_img_comp; - ++l_tilec; } } -OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, - OPJ_BYTE * p_data, - OPJ_UINT32 p_data_size, +static OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager ) { - opj_tcd_t * l_tcd = 00; OPJ_UINT32 l_nb_bytes_written; OPJ_BYTE * l_current_data = 00; OPJ_UINT32 l_tile_size = 0; @@ -9822,17 +10416,10 @@ OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, /* preconditions */ assert(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data); - l_tcd = p_j2k->m_tcd; - l_tile_size = p_j2k->m_specific_param.m_encoder.m_encoded_tile_size; l_available_data = l_tile_size; l_current_data = p_j2k->m_specific_param.m_encoder.m_encoded_tile_data; - if (! opj_tcd_copy_tile_data(l_tcd,p_data,p_data_size)) { - opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); - return OPJ_FALSE; - } - l_nb_bytes_written = 0; if (! opj_j2k_write_first_tile_part(p_j2k,l_current_data,&l_nb_bytes_written,l_available_data,p_stream,p_manager)) { return OPJ_FALSE; @@ -9859,79 +10446,131 @@ OPJ_BOOL opj_j2k_post_write_tile ( opj_j2k_t * p_j2k, return OPJ_TRUE; } -void opj_j2k_setup_end_compress (opj_j2k_t *p_j2k) +static OPJ_BOOL opj_j2k_setup_end_compress (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) { /* preconditions */ assert(p_j2k != 00); + assert(p_manager != 00); /* DEVELOPER CORNER, insert your custom procedures */ - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_eoc ); - - if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) { - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_updated_tlm); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_eoc, p_manager)) { + return OPJ_FALSE; } - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_epc ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_end_encoding ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_destroy_header_memory); -} - -void opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k) -{ - /* preconditions */ - assert(p_j2k != 00); - - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_encoder); - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_encoding_validation); - - /* DEVELOPER CORNER, add your custom validation procedure */ - opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_mct_validation); -} - -void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k) -{ - /* preconditions */ - assert(p_j2k != 00); - - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_init_info ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_soc ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_siz ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_cod ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd ); - if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) { - /* No need for COC or QCC, QCD and COD are used - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc ); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc ); - */ - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm ); - - if (p_j2k->m_cp.rsiz == OPJ_PROFILE_CINEMA_4K) { - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_poc ); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_updated_tlm, p_manager)) { + return OPJ_FALSE; } } - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_regions); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_epc, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_end_encoding, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_destroy_header_memory, p_manager)) { + return OPJ_FALSE; + } + return OPJ_TRUE; +} + +static OPJ_BOOL opj_j2k_setup_encoding_validation (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_build_encoder, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_encoding_validation, p_manager)) { + return OPJ_FALSE; + } + + /* DEVELOPER CORNER, add your custom validation procedure */ + if (! opj_procedure_list_add_procedure(p_j2k->m_validation_list, (opj_procedure)opj_j2k_mct_validation, p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + +static OPJ_BOOL opj_j2k_setup_header_writing (opj_j2k_t *p_j2k, opj_event_mgr_t * p_manager) +{ + /* preconditions */ + assert(p_j2k != 00); + assert(p_manager != 00); + + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_init_info, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_soc, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_siz, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_cod, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc, p_manager)) { + return OPJ_FALSE; + } + + if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) { + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm, p_manager)) { + return OPJ_FALSE; + } + + if (p_j2k->m_cp.rsiz == OPJ_PROFILE_CINEMA_4K) { + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_poc, p_manager)) { + return OPJ_FALSE; + } + } + } + + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_regions, p_manager)) { + return OPJ_FALSE; + } if (p_j2k->m_cp.comment != 00) { - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_com); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_com, p_manager)) { + return OPJ_FALSE; + } } /* DEVELOPER CORNER, insert your custom procedures */ if (p_j2k->m_cp.rsiz & OPJ_EXTENSION_MCT) { - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_mct_data_group ); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_mct_data_group, p_manager)) { + return OPJ_FALSE; + } } /* End of Developer Corner */ if (p_j2k->cstr_index) { - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_get_end_header ); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_get_end_header, p_manager)) { + return OPJ_FALSE; + } } - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_create_tcd); - opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_update_rates); + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_create_tcd, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_update_rates, p_manager)) { + return OPJ_FALSE; + } + + return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_total_data_size, @@ -9983,7 +10622,6 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, p_total_data_size -= l_current_nb_bytes_written; } #endif - if (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) { l_current_nb_bytes_written = 0; opj_j2k_write_poc_in_memory(p_j2k,p_data,&l_current_nb_bytes_written,p_manager); @@ -10011,7 +10649,7 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_all_tile_parts( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_all_tile_parts( opj_j2k_t *p_j2k, OPJ_BYTE * p_data, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_total_data_size, @@ -10122,7 +10760,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -10153,7 +10791,7 @@ OPJ_BOOL opj_j2k_write_updated_tlm( opj_j2k_t *p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_end_encoding( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_end_encoding( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -10204,7 +10842,7 @@ static OPJ_BOOL opj_j2k_destroy_header_memory ( opj_j2k_t * p_j2k, return OPJ_TRUE; } -OPJ_BOOL opj_j2k_init_info( opj_j2k_t *p_j2k, +static OPJ_BOOL opj_j2k_init_info( opj_j2k_t *p_j2k, struct opj_stream_private *p_stream, struct opj_event_mgr * p_manager ) { @@ -10303,7 +10941,23 @@ OPJ_BOOL opj_j2k_write_tile (opj_j2k_t * p_j2k, return OPJ_FALSE; } else { - if (! opj_j2k_post_write_tile(p_j2k,p_data,p_data_size,p_stream,p_manager)) { + OPJ_UINT32 j; + /* Allocate data */ + for (j=0;jm_tcd->image->numcomps;++j) { + opj_tcd_tilecomp_t* l_tilec = p_j2k->m_tcd->tcd_image->tiles->comps + j; + + if(! opj_alloc_tile_component_data(l_tilec)) { + opj_event_msg(p_manager, EVT_ERROR, "Error allocating tile component data." ); + return OPJ_FALSE; + } + } + + /* now copy data into the tile component */ + if (! opj_tcd_copy_tile_data(p_j2k->m_tcd,p_data,p_data_size)) { + opj_event_msg(p_manager, EVT_ERROR, "Size mismatch between tile data and sent data." ); + return OPJ_FALSE; + } + if (! opj_j2k_post_write_tile(p_j2k,p_stream,p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Error while opj_j2k_post_write_tile with tile index = %d\n", p_tile_index); return OPJ_FALSE; } diff --git a/src/lib/openjp2/j2k.h b/src/lib/openjp2/j2k.h index d0f59d72..358e0739 100644 --- a/src/lib/openjp2/j2k.h +++ b/src/lib/openjp2/j2k.h @@ -232,6 +232,12 @@ typedef struct opj_simple_mcc_decorrelation_data } opj_simple_mcc_decorrelation_data_t; +typedef struct opj_ppx_struct +{ + OPJ_BYTE* m_data; /* m_data == NULL => Zppx not read yet */ + OPJ_UINT32 m_data_size; +} opj_ppx; + /** Tile coding parameters : this structure is used to store coding/decoding parameters common to all @@ -254,7 +260,13 @@ typedef struct opj_tcp OPJ_UINT32 numpocs; /** progression order changes */ opj_poc_t pocs[32]; - /** packet header store there for futur use in t2_decode_packet */ + + /** number of ppt markers (reserved size) */ + OPJ_UINT32 ppt_markers_count; + /** ppt markers data (table indexed by Zppt) */ + opj_ppx* ppt_markers; + + /** packet header store there for future use in t2_decode_packet */ OPJ_BYTE *ppt_data; /** used to keep a track of the allocated memory */ OPJ_BYTE *ppt_buffer; @@ -293,6 +305,8 @@ typedef struct opj_tcp /***** FLAGS *******/ + /** If cod == 1 --> there was a COD marker for the present tile */ + OPJ_UINT32 cod : 1; /** If ppt == 1 --> there was a PPT marker for the present tile */ OPJ_UINT32 ppt : 1; /** indicates if a POC marker has been used O:NO, 1:YES */ @@ -357,7 +371,12 @@ typedef struct opj_cp /** number of tiles in heigth */ OPJ_UINT32 th; - /** packet header store there for futur use in t2_decode_packet */ + /** number of ppm markers (reserved size) */ + OPJ_UINT32 ppm_markers_count; + /** ppm markers data (table indexed by Zppm) */ + opj_ppx* ppm_markers; + + /** packet header store there for future use in t2_decode_packet */ OPJ_BYTE *ppm_data; /** size of the ppm_data*/ OPJ_UINT32 ppm_len; @@ -481,6 +500,9 @@ typedef struct opj_j2k_dec OPJ_UINT32 m_can_decode : 1; OPJ_UINT32 m_discard_tiles : 1; OPJ_UINT32 m_skip_data : 1; + /** TNsot correction : see issue 254 **/ + OPJ_UINT32 m_nb_tile_parts_correction_checked : 1; + OPJ_UINT32 m_nb_tile_parts_correction : 1; } opj_j2k_dec_t; @@ -567,7 +589,6 @@ typedef struct opj_j2k /** the current tile coder/decoder **/ struct opj_tcd * m_tcd; - } opj_j2k_t; @@ -594,7 +615,7 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters); opj_j2k_t* opj_j2k_create_compress(void); -void opj_j2k_setup_encoder( opj_j2k_t *p_j2k, +OPJ_BOOL opj_j2k_setup_encoder( opj_j2k_t *p_j2k, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager); diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index 5c88c4d7..6c6f6e83 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -94,7 +94,7 @@ static OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, * @param p_bpc_header_size the size of the bpc header * @param p_manager the user event manager. * - * @return true if the bpc header is valid, fale else. + * @return true if the bpc header is valid, false else. */ static OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, OPJ_BYTE * p_bpc_header_data, @@ -106,7 +106,18 @@ static OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, OPJ_UINT32 p_cdef_header_size, opj_event_mgr_t * p_manager ); -static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color); +static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color, opj_event_mgr_t *); + +/** + * Writes the Channel Definition box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. + */ +static OPJ_BYTE * opj_jp2_write_cdef( opj_jp2_t *jp2, + OPJ_UINT32 * p_nb_bytes_written ); /** * Writes the Colour Specification box. @@ -147,7 +158,7 @@ static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); -OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -159,13 +170,26 @@ OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, * @param p_header_size the size of the data contained in the file header box. * @param p_manager the user event manager. * - * @return true if the JP2 Header box was successfully reconized. + * @return true if the JP2 Header box was successfully recognized. */ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_BYTE *p_header_data, OPJ_UINT32 p_header_size, opj_event_mgr_t * p_manager ); +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param jp2 the jpeg2000 file codec. + * @param stream the stream to write data to. + * @param p_manager user event manager. + * + * @return true if writing was successful. + */ +static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, + opj_stream_private_t *stream, + opj_event_mgr_t * p_manager ); + /** * Writes the Jpeg2000 codestream Header box - JP2C Header box. This function must be called AFTER the coding has been done. * @@ -287,7 +311,7 @@ static OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, * @param p_colr_header_size the size of the color header * @param p_manager the user event manager. * - * @return true if the bpc header is valid, fale else. + * @return true if the bpc header is valid, false else. */ static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, OPJ_BYTE * p_colr_header_data, @@ -302,13 +326,13 @@ static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, * Sets up the procedures to do on writing header after the codestream. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_end_header_writing (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_end_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on reading header after the codestream. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_end_header_reading (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_end_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Reads a jpeg2000 file header structure. @@ -346,7 +370,7 @@ static OPJ_BOOL opj_jp2_exec ( opj_jp2_t * jp2, * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). * @param p_manager user event manager. * - * @return true if the box is reconized, false otherwise + * @return true if the box is recognized, false otherwise */ static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read, @@ -357,14 +381,14 @@ static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_jp2_setup_encoding_validation (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_encoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on writing header. Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_header_writing (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); -OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ); @@ -386,14 +410,14 @@ static const opj_jp2_header_handler_t * opj_jp2_img_find_handler (OPJ_UINT32 p_i */ static const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id ); -const opj_jp2_header_handler_t jp2_header [] = +static const opj_jp2_header_handler_t jp2_header [] = { {JP2_JP,opj_jp2_read_jp}, {JP2_FTYP,opj_jp2_read_ftyp}, {JP2_JP2H,opj_jp2_read_jp2h} }; -const opj_jp2_header_handler_t jp2_img_header [] = +static const opj_jp2_header_handler_t jp2_img_header [] = { {JP2_IHDR,opj_jp2_read_ihdr}, {JP2_COLR,opj_jp2_read_colr}, @@ -413,7 +437,7 @@ const opj_jp2_header_handler_t jp2_img_header [] = * @param p_box_max_size the maximum number of bytes in the box. * @param p_manager FIXME DOC * - * @return true if the box is reconized, false otherwise + * @return true if the box is recognized, false otherwise */ static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, OPJ_BYTE * p_data, @@ -425,16 +449,16 @@ static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters * are valid. Developpers wanting to extend the library can add their own validation procedures. */ -static void opj_jp2_setup_decoding_validation (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_decoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /** * Sets up the procedures to do on reading header. * Developpers wanting to extend the library can add their own writing procedures. */ -static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); +static OPJ_BOOL opj_jp2_setup_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager); /* ----------------------------------------------------------------------- */ - OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, +static OPJ_BOOL opj_jp2_read_boxhdr(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -458,12 +482,16 @@ static void opj_jp2_setup_header_reading (opj_jp2_t *jp2); opj_read_bytes(l_data_header+4,&(box->type), 4); if(box->length == 0)/* last box */ - { + { const OPJ_OFF_T bleft = opj_stream_get_number_byte_left(cio); - box->length = (OPJ_UINT32)bleft; - assert( (OPJ_OFF_T)box->length == bleft ); - return OPJ_TRUE; + if (bleft > (OPJ_OFF_T)(0xFFFFFFFFU - 8U)) { + opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return OPJ_FALSE; } + box->length = (OPJ_UINT32)bleft + 8U; + assert( (OPJ_OFF_T)box->length == bleft + 8 ); + return OPJ_TRUE; + } /* do we have a "special very large box ?" */ /* read then the XLBox */ @@ -514,7 +542,7 @@ static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { } #endif -OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, OPJ_BYTE *p_image_header_data, OPJ_UINT32 p_image_header_size, opj_event_mgr_t * p_manager ) @@ -537,12 +565,11 @@ OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, p_image_header_data += 2; /* allocate memory for components */ - jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + jp2->comps = (opj_jp2_comps_t*) opj_calloc(jp2->numcomps, sizeof(opj_jp2_comps_t)); if (jp2->comps == 0) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle image header (ihdr)\n"); return OPJ_FALSE; } - memset(jp2->comps,0,jp2->numcomps * sizeof(opj_jp2_comps_t)); opj_read_bytes(p_image_header_data,&(jp2->bpc),1); /* BPC */ ++ p_image_header_data; @@ -563,7 +590,7 @@ OPJ_BOOL opj_jp2_read_ihdr( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, +static OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { @@ -574,11 +601,10 @@ OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, assert(p_nb_bytes_written != 00); /* default image header is 22 bytes wide */ - l_ihdr_data = (OPJ_BYTE *) opj_malloc(22); + l_ihdr_data = (OPJ_BYTE *) opj_calloc(1,22); if (l_ihdr_data == 00) { return 00; } - memset(l_ihdr_data,0,22); l_current_ihdr_ptr = l_ihdr_data; @@ -614,7 +640,7 @@ OPJ_BYTE * opj_jp2_write_ihdr(opj_jp2_t *jp2, return l_ihdr_data; } -OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, +static OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { @@ -627,11 +653,10 @@ OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, assert(jp2 != 00); assert(p_nb_bytes_written != 00); - l_bpcc_data = (OPJ_BYTE *) opj_malloc(l_bpcc_size); + l_bpcc_data = (OPJ_BYTE *) opj_calloc(1,l_bpcc_size); if (l_bpcc_data == 00) { return 00; } - memset(l_bpcc_data,0,l_bpcc_size); l_current_bpcc_ptr = l_bpcc_data; @@ -651,7 +676,7 @@ OPJ_BYTE * opj_jp2_write_bpcc( opj_jp2_t *jp2, return l_bpcc_data; } -OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, OPJ_BYTE * p_bpc_header_data, OPJ_UINT32 p_bpc_header_size, opj_event_mgr_t * p_manager @@ -683,15 +708,64 @@ OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, return OPJ_TRUE; } +static OPJ_BYTE * opj_jp2_write_cdef(opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written) +{ + /* room for 8 bytes for box, 2 for n */ + OPJ_UINT32 l_cdef_size = 10; + OPJ_BYTE * l_cdef_data,* l_current_cdef_ptr; + OPJ_UINT32 l_value; + OPJ_UINT16 i; -OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, + /* preconditions */ + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + assert(jp2->color.jp2_cdef != 00); + assert(jp2->color.jp2_cdef->info != 00); + assert(jp2->color.jp2_cdef->n > 0U); + + l_cdef_size += 6U * jp2->color.jp2_cdef->n; + + l_cdef_data = (OPJ_BYTE *) opj_malloc(l_cdef_size); + if (l_cdef_data == 00) { + return 00; + } + + l_current_cdef_ptr = l_cdef_data; + + opj_write_bytes(l_current_cdef_ptr,l_cdef_size,4); /* write box size */ + l_current_cdef_ptr += 4; + + opj_write_bytes(l_current_cdef_ptr,JP2_CDEF,4); /* BPCC */ + l_current_cdef_ptr += 4; + + l_value = jp2->color.jp2_cdef->n; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* N */ + l_current_cdef_ptr += 2; + + for (i = 0U; i < jp2->color.jp2_cdef->n; ++i) { + l_value = jp2->color.jp2_cdef->info[i].cn; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Cni */ + l_current_cdef_ptr += 2; + l_value = jp2->color.jp2_cdef->info[i].typ; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Typi */ + l_current_cdef_ptr += 2; + l_value = jp2->color.jp2_cdef->info[i].asoc; + opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Asoci */ + l_current_cdef_ptr += 2; + } + *p_nb_bytes_written = l_cdef_size; + + return l_cdef_data; +} + +static OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written ) { /* room for 8 bytes for box 3 for common data and variable upon profile*/ OPJ_UINT32 l_colr_size = 11; OPJ_BYTE * l_colr_data,* l_current_colr_ptr; - + /* preconditions */ assert(jp2 != 00); assert(p_nb_bytes_written != 00); @@ -709,11 +783,10 @@ OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, return 00; } - l_colr_data = (OPJ_BYTE *) opj_malloc(l_colr_size); + l_colr_data = (OPJ_BYTE *) opj_calloc(1,l_colr_size); if (l_colr_data == 00) { return 00; } - memset(l_colr_data,0,l_colr_size); l_current_colr_ptr = l_colr_data; @@ -749,7 +822,7 @@ OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, return l_colr_data; } -void opj_jp2_free_pclr(opj_jp2_color_t *color) +static void opj_jp2_free_pclr(opj_jp2_color_t *color) { opj_free(color->jp2_pclr->channel_sign); opj_free(color->jp2_pclr->channel_size); @@ -768,17 +841,41 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, if (color->jp2_cdef) { opj_jp2_cdef_info_t *info = color->jp2_cdef->info; OPJ_UINT16 n = color->jp2_cdef->n; + OPJ_UINT32 nr_channels = image->numcomps; /* FIXME image->numcomps == jp2->numcomps before color is applied ??? */ + + /* cdef applies to cmap channels if any */ + if (color->jp2_pclr && color->jp2_pclr->cmap) { + nr_channels = (OPJ_UINT32)color->jp2_pclr->nr_channels; + } for (i = 0; i < n; i++) { - if (info[i].cn >= image->numcomps) { - opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, image->numcomps); + if (info[i].cn >= nr_channels) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, nr_channels); return OPJ_FALSE; } - if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= image->numcomps) { - opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, image->numcomps); + if (info[i].asoc == 65535U) continue; + + if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= nr_channels) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, nr_channels); return OPJ_FALSE; } } + + /* issue 397 */ + /* ISO 15444-1 states that if cdef is present, it shall contain a complete list of channel definitions. */ + while (nr_channels > 0) + { + for(i = 0; i < n; ++i) { + if ((OPJ_UINT32)info[i].cn == (nr_channels - 1U)) { + break; + } + } + if (i == n) { + opj_event_msg(p_manager, EVT_ERROR, "Incomplete channel definitions.\n"); + return OPJ_FALSE; + } + --nr_channels; + } } /* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and @@ -796,7 +893,7 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, } } - pcol_usage = opj_calloc(nr_channels, sizeof(OPJ_BOOL)); + pcol_usage = (OPJ_BOOL *) opj_calloc(nr_channels, sizeof(OPJ_BOOL)); if (!pcol_usage) { opj_event_msg(p_manager, EVT_ERROR, "Unexpected OOM.\n"); return OPJ_FALSE; @@ -829,6 +926,23 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, is_sane = OPJ_FALSE; } } + /* Issue 235/447 weird cmap */ + if (1 && is_sane && (image->numcomps==1U)) { + for (i = 0; i < nr_channels; i++) { + if (!pcol_usage[i]) { + is_sane = 0U; + opj_event_msg(p_manager, EVT_WARNING, "Component mapping seems wrong. Trying to correct.\n", i); + break; + } + } + if (!is_sane) { + is_sane = OPJ_TRUE; + for (i = 0; i < nr_channels; i++) { + cmap[i].mtyp = 1U; + cmap[i].pcol = (OPJ_BYTE) i; + } + } + } opj_free(pcol_usage); if (!is_sane) { return OPJ_FALSE; @@ -839,7 +953,7 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, } /* file9.jp2 */ -void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) +static void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) { opj_image_comp_t *old_comps, *new_comps; OPJ_BYTE *channel_size, *channel_sign; @@ -859,7 +973,11 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) old_comps = image->comps; new_comps = (opj_image_comp_t*) opj_malloc(nr_channels * sizeof(opj_image_comp_t)); - + if (!new_comps) { + /* FIXME no error code for opj_jp2_apply_pclr */ + /* FIXME event manager error callback */ + return; + } for(i = 0; i < nr_channels; ++i) { pcol = cmap[i].pcol; cmp = cmap[i].cmp; @@ -875,6 +993,13 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) /* Palette mapping: */ new_comps[i].data = (OPJ_INT32*) opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(OPJ_INT32)); + if (!new_comps[i].data) { + opj_free(new_comps); + new_comps = NULL; + /* FIXME no error code for opj_jp2_apply_pclr */ + /* FIXME event manager error callback */ + return; + } new_comps[i].prec = channel_size[i]; new_comps[i].sgnd = channel_sign[i]; } @@ -924,7 +1049,7 @@ void opj_jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) }/* apply_pclr() */ -OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, OPJ_BYTE * p_pclr_header_data, OPJ_UINT32 p_pclr_header_size, opj_event_mgr_t * p_manager @@ -953,12 +1078,20 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, opj_read_bytes(p_pclr_header_data, &l_value , 2); /* NE */ p_pclr_header_data += 2; nr_entries = (OPJ_UINT16) l_value; + if ((nr_entries == 0U) || (nr_entries > 1024U)) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports %d entries\n", (int)nr_entries); + return OPJ_FALSE; + } opj_read_bytes(p_pclr_header_data, &l_value , 1); /* NPC */ ++p_pclr_header_data; nr_channels = (OPJ_UINT16) l_value; + if (nr_channels == 0U) { + opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports 0 palette columns\n"); + return OPJ_FALSE; + } - if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels || nr_channels == 0 || nr_entries >= (OPJ_UINT32)-1 / nr_channels) + if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels) return OPJ_FALSE; entries = (OPJ_UINT32*) opj_malloc((size_t)nr_channels * nr_entries * sizeof(OPJ_UINT32)); @@ -1010,7 +1143,7 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, if (bytes_to_read > sizeof(OPJ_UINT32)) bytes_to_read = sizeof(OPJ_UINT32); - if ((ptrdiff_t)p_pclr_header_size < p_pclr_header_data - orig_header_data + (ptrdiff_t)bytes_to_read) + if ((ptrdiff_t)p_pclr_header_size < (ptrdiff_t)(p_pclr_header_data - orig_header_data) + (ptrdiff_t)bytes_to_read) return OPJ_FALSE; opj_read_bytes(p_pclr_header_data, &l_value , bytes_to_read); /* Cji */ @@ -1023,7 +1156,7 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, OPJ_BYTE * p_cmap_header_data, OPJ_UINT32 p_cmap_header_size, opj_event_mgr_t * p_manager @@ -1083,55 +1216,71 @@ OPJ_BOOL opj_jp2_read_cmap( opj_jp2_t * jp2, return OPJ_TRUE; } -void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) +static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color, opj_event_mgr_t *manager) { opj_jp2_cdef_info_t *info; OPJ_UINT16 i, n, cn, asoc, acn; - + info = color->jp2_cdef->info; n = color->jp2_cdef->n; - - for(i = 0; i < n; ++i) - { - /* WATCH: acn = asoc - 1 ! */ - asoc = info[i].asoc; - if(asoc == 0 || asoc == 65535) - { - if (i < image->numcomps) - image->comps[i].alpha = info[i].typ; - continue; - } - - cn = info[i].cn; - acn = (OPJ_UINT16)(asoc - 1); - if( cn >= image->numcomps || acn >= image->numcomps ) - { - fprintf(stderr, "cn=%d, acn=%d, numcomps=%d\n", cn, acn, image->numcomps); - continue; - } - - if(cn != acn) + + for(i = 0; i < n; ++i) + { + /* WATCH: acn = asoc - 1 ! */ + asoc = info[i].asoc; + cn = info[i].cn; + + if( cn >= image->numcomps) + { + opj_event_msg(manager, EVT_WARNING, "opj_jp2_apply_cdef: cn=%d, numcomps=%d\n", cn, image->numcomps); + continue; + } + if(asoc == 0 || asoc == 65535) + { + image->comps[cn].alpha = info[i].typ; + continue; + } + + acn = (OPJ_UINT16)(asoc - 1); + if( acn >= image->numcomps ) + { + opj_event_msg(manager, EVT_WARNING, "opj_jp2_apply_cdef: acn=%d, numcomps=%d\n", acn, image->numcomps); + continue; + } + + /* Swap only if color channel */ + if((cn != acn) && (info[i].typ == 0)) { opj_image_comp_t saved; - + OPJ_UINT16 j; + memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); - - info[i].asoc = (OPJ_UINT16)(cn + 1); - info[acn].asoc = (OPJ_UINT16)(info[acn].cn + 1); + + /* Swap channels in following channel definitions, don't bother with j <= i that are already processed */ + for (j = (OPJ_UINT16)(i + 1U); j < n ; ++j) + { + if (info[j].cn == cn) { + info[j].cn = acn; + } + else if (info[j].cn == acn) { + info[j].cn = cn; + } + /* asoc is related to color index. Do not update. */ + } } - + image->comps[cn].alpha = info[i].typ; } - + if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); - + opj_free(color->jp2_cdef); color->jp2_cdef = NULL; - + }/* jp2_apply_cdef() */ -OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, OPJ_BYTE * p_cdef_header_data, OPJ_UINT32 p_cdef_header_size, opj_event_mgr_t * p_manager @@ -1170,15 +1319,15 @@ OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, } cdef_info = (opj_jp2_cdef_info_t*) opj_malloc(l_value * sizeof(opj_jp2_cdef_info_t)); - if (!cdef_info) - return OPJ_FALSE; + if (!cdef_info) + return OPJ_FALSE; jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); - if(!jp2->color.jp2_cdef) - { - opj_free(cdef_info); - return OPJ_FALSE; - } + if(!jp2->color.jp2_cdef) + { + opj_free(cdef_info); + return OPJ_FALSE; + } jp2->color.jp2_cdef->info = cdef_info; jp2->color.jp2_cdef->n = (OPJ_UINT16) l_value; @@ -1199,7 +1348,7 @@ OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, OPJ_BYTE * p_colr_header_data, OPJ_UINT32 p_colr_header_size, opj_event_mgr_t * p_manager @@ -1240,14 +1389,59 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, opj_event_msg(p_manager, EVT_ERROR, "Bad COLR header box (bad size: %d)\n", p_colr_header_size); return OPJ_FALSE; } - if (p_colr_header_size > 7) { + if ((p_colr_header_size > 7) && (jp2->enumcs != 14)) { /* handled below for CIELab) */ /* testcase Altona_Technical_v20_x4.pdf */ opj_event_msg(p_manager, EVT_WARNING, "Bad COLR header box (bad size: %d)\n", p_colr_header_size); } opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4); /* EnumCS */ - - jp2->color.jp2_has_colr = 1; + + p_colr_header_data += 4; + + if(jp2->enumcs == 14)/* CIELab */ + { + OPJ_UINT32 *cielab; + OPJ_UINT32 rl, ol, ra, oa, rb, ob, il; + + cielab = (OPJ_UINT32*)opj_malloc(9 * sizeof(OPJ_UINT32)); + cielab[0] = 14; /* enumcs */ + + /* default values */ + rl = ra = rb = ol = oa = ob = 0; + il = 0x00443530; /* D50 */ + cielab[1] = 0x44454600;/* DEF */ + + if(p_colr_header_size == 35) + { + opj_read_bytes(p_colr_header_data, &rl, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ol, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ra, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &oa, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &rb, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &ob, 4); + p_colr_header_data += 4; + opj_read_bytes(p_colr_header_data, &il, 4); + p_colr_header_data += 4; + + cielab[1] = 0; + } + else if(p_colr_header_size != 7) + { + opj_event_msg(p_manager, EVT_WARNING, "Bad COLR header box (CIELab, bad size: %d)\n", p_colr_header_size); + } + cielab[2] = rl; cielab[4] = ra; cielab[6] = rb; + cielab[3] = ol; cielab[5] = oa; cielab[7] = ob; + cielab[8] = il; + + jp2->color.icc_profile_buf = (OPJ_BYTE*)cielab; + jp2->color.icc_profile_len = 0; + } + jp2->color.jp2_has_colr = 1; } else if (jp2->meth == 2) { /* ICC profile */ @@ -1255,13 +1449,12 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, OPJ_INT32 icc_len = (OPJ_INT32)p_colr_header_size - 3; jp2->color.icc_profile_len = (OPJ_UINT32)icc_len; - jp2->color.icc_profile_buf = (OPJ_BYTE*) opj_malloc((size_t)icc_len); - if (!jp2->color.icc_profile_buf) - { - jp2->color.icc_profile_len = 0; - return OPJ_FALSE; - } - memset(jp2->color.icc_profile_buf, 0, (size_t)icc_len * sizeof(OPJ_BYTE)); + jp2->color.icc_profile_buf = (OPJ_BYTE*) opj_calloc(1,(size_t)icc_len); + if (!jp2->color.icc_profile_buf) + { + jp2->color.icc_profile_len = 0; + return OPJ_FALSE; + } for (it_icc_value = 0; it_icc_value < icc_len; ++it_icc_value) { @@ -1270,16 +1463,16 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2, jp2->color.icc_profile_buf[it_icc_value] = (OPJ_BYTE) l_value; } - jp2->color.jp2_has_colr = 1; + jp2->color.jp2_has_colr = 1; } else if (jp2->meth > 2) - { - /* ISO/IEC 15444-1:2004 (E), Table I.9 ­ Legal METH values: - conforming JP2 reader shall ignore the entire Colour Specification box.*/ - opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), " - "so we will ignore the entire Colour Specification box. \n", jp2->meth); - } - return OPJ_TRUE; + { + /* ISO/IEC 15444-1:2004 (E), Table I.9 Legal METH values: + conforming JP2 reader shall ignore the entire Colour Specification box.*/ + opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), " + "so we will ignore the entire Colour Specification box. \n", jp2->meth); + } + return OPJ_TRUE; } OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, @@ -1296,52 +1489,54 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, return OPJ_FALSE; } - if (!jp2->ignore_pclr_cmap_cdef){ - if (!opj_jp2_check_color(p_image, &(jp2->color), p_manager)) { - return OPJ_FALSE; - } + if (!jp2->ignore_pclr_cmap_cdef){ + if (!opj_jp2_check_color(p_image, &(jp2->color), p_manager)) { + return OPJ_FALSE; + } - /* Set Image Color Space */ - if (jp2->enumcs == 16) - p_image->color_space = OPJ_CLRSPC_SRGB; - else if (jp2->enumcs == 17) - p_image->color_space = OPJ_CLRSPC_GRAY; - else if (jp2->enumcs == 18) - p_image->color_space = OPJ_CLRSPC_SYCC; - else if (jp2->enumcs == 24) - p_image->color_space = OPJ_CLRSPC_EYCC; - else - p_image->color_space = OPJ_CLRSPC_UNKNOWN; + /* Set Image Color Space */ + if (jp2->enumcs == 16) + p_image->color_space = OPJ_CLRSPC_SRGB; + else if (jp2->enumcs == 17) + p_image->color_space = OPJ_CLRSPC_GRAY; + else if (jp2->enumcs == 18) + p_image->color_space = OPJ_CLRSPC_SYCC; + else if (jp2->enumcs == 24) + p_image->color_space = OPJ_CLRSPC_EYCC; + else if (jp2->enumcs == 12) + p_image->color_space = OPJ_CLRSPC_CMYK; + else + p_image->color_space = OPJ_CLRSPC_UNKNOWN; - /* Apply the color space if needed */ - if(jp2->color.jp2_cdef) { - opj_jp2_apply_cdef(p_image, &(jp2->color)); - } + if(jp2->color.jp2_pclr) { + /* Part 1, I.5.3.4: Either both or none : */ + if( !jp2->color.jp2_pclr->cmap) + opj_jp2_free_pclr(&(jp2->color)); + else + opj_jp2_apply_pclr(p_image, &(jp2->color)); + } - if(jp2->color.jp2_pclr) { - /* Part 1, I.5.3.4: Either both or none : */ - if( !jp2->color.jp2_pclr->cmap) - opj_jp2_free_pclr(&(jp2->color)); - else - opj_jp2_apply_pclr(p_image, &(jp2->color)); - } + /* Apply the color space if needed */ + if(jp2->color.jp2_cdef) { + opj_jp2_apply_cdef(p_image, &(jp2->color), p_manager); + } - if(jp2->color.icc_profile_buf) { - p_image->icc_profile_buf = jp2->color.icc_profile_buf; - p_image->icc_profile_len = jp2->color.icc_profile_len; - jp2->color.icc_profile_buf = NULL; - } - } + if(jp2->color.icc_profile_buf) { + p_image->icc_profile_buf = jp2->color.icc_profile_buf; + p_image->icc_profile_len = jp2->color.icc_profile_len; + jp2->color.icc_profile_buf = NULL; + } + } return OPJ_TRUE; } -OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { - opj_jp2_img_header_writer_handler_t l_writers [3]; + opj_jp2_img_header_writer_handler_t l_writers [4]; opj_jp2_img_header_writer_handler_t * l_current_writer; OPJ_INT32 i, l_nb_pass; @@ -1371,6 +1566,11 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, l_writers[1].handler = opj_jp2_write_colr; } + if (jp2->color.jp2_cdef != NULL) { + l_writers[l_nb_pass].handler = opj_jp2_write_cdef; + l_nb_pass++; + } + /* write box header */ /* write JP2H type */ opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); @@ -1434,7 +1634,7 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, return l_result; } -OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -1448,15 +1648,13 @@ OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, assert(jp2 != 00); assert(p_manager != 00); - l_ftyp_data = (OPJ_BYTE *) opj_malloc(l_ftyp_size); + l_ftyp_data = (OPJ_BYTE *) opj_calloc(1,l_ftyp_size); if (l_ftyp_data == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle ftyp data\n"); return OPJ_FALSE; } - memset(l_ftyp_data,0,l_ftyp_size); - l_current_data_ptr = l_ftyp_data; opj_write_bytes(l_current_data_ptr, l_ftyp_size,4); /* box size */ @@ -1486,7 +1684,7 @@ OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2, return l_result; } -OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -1523,7 +1721,7 @@ OPJ_BOOL opj_jp2_write_jp2c(opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_write_jp( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_write_jp( opj_jp2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) { @@ -1567,17 +1765,21 @@ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) /* JP2 encoder interface */ /* ----------------------------------------------------------------------- */ -void opj_jp2_setup_encoder( opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_setup_encoder( opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager) { - OPJ_UINT32 i; + OPJ_UINT32 i; OPJ_UINT32 depth_0; OPJ_UINT32 sign; + OPJ_UINT32 alpha_count; + OPJ_UINT32 color_channels = 0U; + OPJ_UINT32 alpha_channel = 0U; + if(!jp2 || !parameters || !image) - return; + return OPJ_FALSE; /* setup the J2K codec */ /* ------------------- */ @@ -1585,10 +1787,12 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, /* Check if number of components respects standard */ if (image->numcomps < 1 || image->numcomps > 16384) { opj_event_msg(p_manager, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); - return; + return OPJ_FALSE; } - opj_j2k_setup_encoder(jp2->j2k, parameters, image, p_manager ); + if (opj_j2k_setup_encoder(jp2->j2k, parameters, image, p_manager ) == OPJ_FALSE) { + return OPJ_FALSE; + } /* setup the JP2 codec */ /* ------------------- */ @@ -1599,22 +1803,23 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, jp2->minversion = 0; /* MinV */ jp2->numcl = 1; jp2->cl = (OPJ_UINT32*) opj_malloc(jp2->numcl * sizeof(OPJ_UINT32)); - if (!jp2->cl){ - jp2->cl = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); - return; - } + if (!jp2->cl){ + jp2->cl = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); + return OPJ_FALSE; + } jp2->cl[0] = JP2_JP2; /* CL0 : JP2 */ /* Image Header box */ jp2->numcomps = image->numcomps; /* NC */ jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); - if (!jp2->comps) { - jp2->comps = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); - return; - } + if (!jp2->comps) { + jp2->comps = NULL; + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory when setup the JP2 encoder\n"); + /* Memory of jp2->cl will be freed by opj_jp2_destroy */ + return OPJ_FALSE; + } jp2->h = image->y1 - image->y0; /* HEIGHT */ jp2->w = image->x1 - image->x0; /* WIDTH */ @@ -1652,11 +1857,81 @@ void opj_jp2_setup_encoder( opj_jp2_t *jp2, jp2->enumcs = 18; /* YUV */ } + /* Channel Definition box */ + /* FIXME not provided by parameters */ + /* We try to do what we can... */ + alpha_count = 0U; + for (i = 0; i < image->numcomps; i++) { + if (image->comps[i].alpha != 0) { + alpha_count++; + alpha_channel = i; + } + } + if (alpha_count == 1U) { /* no way to deal with more than 1 alpha channel */ + switch (jp2->enumcs) { + case 16: + case 18: + color_channels = 3; + break; + case 17: + color_channels = 1; + break; + default: + alpha_count = 0U; + break; + } + if (alpha_count == 0U) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but unknown enumcs. No cdef box will be created.\n"); + } else if (image->numcomps < (color_channels+1)) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but not enough image components for an automatic cdef box creation.\n"); + alpha_count = 0U; + } else if ((OPJ_UINT32)alpha_channel < color_channels) { + opj_event_msg(p_manager, EVT_WARNING, "Alpha channel position conflicts with color channel. No cdef box will be created.\n"); + alpha_count = 0U; + } + } else if (alpha_count > 1) { + opj_event_msg(p_manager, EVT_WARNING, "Multiple alpha channels specified. No cdef box will be created.\n"); + } + if (alpha_count == 1U) { /* if here, we know what we can do */ + jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); + if(!jp2->color.jp2_cdef) { + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); + return OPJ_FALSE; + } + /* no memset needed, all values will be overwritten except if jp2->color.jp2_cdef->info allocation fails, */ + /* in which case jp2->color.jp2_cdef->info will be NULL => valid for destruction */ + jp2->color.jp2_cdef->info = (opj_jp2_cdef_info_t*) opj_malloc(image->numcomps * sizeof(opj_jp2_cdef_info_t)); + if (!jp2->color.jp2_cdef->info) { + /* memory will be freed by opj_jp2_destroy */ + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); + return OPJ_FALSE; + } + jp2->color.jp2_cdef->n = (OPJ_UINT16) image->numcomps; /* cast is valid : image->numcomps [1,16384] */ + for (i = 0U; i < color_channels; i++) { + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 0U; + jp2->color.jp2_cdef->info[i].asoc = (OPJ_UINT16)(i+1U); /* No overflow + cast is valid : image->numcomps [1,16384] */ + } + for (; i < image->numcomps; i++) { + if (image->comps[i].alpha != 0) { /* we'll be here exactly once */ + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 1U; /* Opacity channel */ + jp2->color.jp2_cdef->info[i].asoc = 0U; /* Apply alpha channel to the whole image */ + } else { + /* Unknown channel */ + jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ + jp2->color.jp2_cdef->info[i].typ = 65535U; + jp2->color.jp2_cdef->info[i].asoc = 65535U; + } + } + } jp2->precedence = 0; /* PRECEDENCE */ jp2->approx = 0; /* APPROX */ jp2->jpip_on = parameters->jpip_on; + + return OPJ_TRUE; } OPJ_BOOL opj_jp2_encode(opj_jp2_t *jp2, @@ -1677,7 +1952,9 @@ OPJ_BOOL opj_jp2_end_decompress(opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the end encoding */ - opj_jp2_setup_end_header_reading(jp2); + if (! opj_jp2_setup_end_header_reading(jp2, p_manager)) { + return OPJ_FALSE; + } /* write header */ if (! opj_jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) { @@ -1698,7 +1975,9 @@ OPJ_BOOL opj_jp2_end_compress( opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the end encoding */ - opj_jp2_setup_end_header_writing(jp2); + if (! opj_jp2_setup_end_header_writing(jp2, p_manager)) { + return OPJ_FALSE; + } if (! opj_j2k_end_compress(jp2->j2k,cio,p_manager)) { return OPJ_FALSE; @@ -1708,35 +1987,52 @@ OPJ_BOOL opj_jp2_end_compress( opj_jp2_t *jp2, return opj_jp2_exec(jp2,jp2->m_procedure_list,cio,p_manager); } -void opj_jp2_setup_end_header_writing (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_end_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); #ifdef USE_JPIP - if( jp2->jpip_on ) - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_iptr ); + if( jp2->jpip_on ) { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_iptr, p_manager)) { + return OPJ_FALSE; + } + } #endif - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2c ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2c, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ #ifdef USE_JPIP if( jp2->jpip_on ) - { - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_cidx ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_fidx ); - } + { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_cidx, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_write_fidx, p_manager)) { + return OPJ_FALSE; + } + } #endif + return OPJ_TRUE; } -void opj_jp2_setup_end_header_reading (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_end_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure ); + assert(p_manager != 00); + + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom procedures */ + + return OPJ_TRUE; } -OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, +static OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager ) @@ -1777,7 +2073,7 @@ OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, l_is_valid &= (jp2->w > 0); /* precision */ for (i = 0; i < jp2->numcomps; ++i) { - l_is_valid &= (jp2->comps[i].bpcc > 0); + l_is_valid &= ((jp2->comps[i].bpcc & 0x7FU) < 38U); /* 0 is valid, ignore sign for check */ } /* METH */ @@ -1790,7 +2086,7 @@ OPJ_BOOL opj_jp2_default_validation ( opj_jp2_t * jp2, return l_is_valid; } -OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) @@ -1798,6 +2094,7 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, opj_jp2_box_t box; OPJ_UINT32 l_nb_bytes_read; const opj_jp2_header_handler_t * l_current_handler; + const opj_jp2_header_handler_t * l_current_handler_misplaced; OPJ_UINT32 l_last_data_size = OPJ_BOX_SIZE; OPJ_UINT32 l_current_data_size; OPJ_BYTE * l_current_data = 00; @@ -1807,20 +2104,19 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, assert(jp2 != 00); assert(p_manager != 00); - l_current_data = (OPJ_BYTE*)opj_malloc(l_last_data_size); + l_current_data = (OPJ_BYTE*)opj_calloc(1,l_last_data_size); if (l_current_data == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle jpeg2000 file header\n"); return OPJ_FALSE; } - memset(l_current_data, 0 , l_last_data_size); while (opj_jp2_read_boxhdr(&box,&l_nb_bytes_read,stream,p_manager)) { /* is it the codestream box ? */ if (box.type == JP2_JP2C) { if (jp2->jp2_state & JP2_STATE_HEADER) { jp2->jp2_state |= JP2_STATE_CODESTREAM; - opj_free(l_current_data); + opj_free(l_current_data); return OPJ_TRUE; } else { @@ -1835,16 +2131,39 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, return OPJ_FALSE; } /* testcase 1851.pdf.SIGSEGV.ce9.948 */ - else if (box.length < l_nb_bytes_read) { + else if (box.length < l_nb_bytes_read) { opj_event_msg(p_manager, EVT_ERROR, "invalid box size %d (%x)\n", box.length, box.type); opj_free(l_current_data); return OPJ_FALSE; } l_current_handler = opj_jp2_find_handler(box.type); + l_current_handler_misplaced = opj_jp2_img_find_handler(box.type); l_current_data_size = box.length - l_nb_bytes_read; - if (l_current_handler != 00) { + if ((l_current_handler != 00) || (l_current_handler_misplaced != 00)) { + if (l_current_handler == 00) { + opj_event_msg(p_manager, EVT_WARNING, "Found a misplaced '%c%c%c%c' box outside jp2h box\n", (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0)); + if (jp2->jp2_state & JP2_STATE_HEADER) { + /* read anyway, we already have jp2h */ + l_current_handler = l_current_handler_misplaced; + } else { + opj_event_msg(p_manager, EVT_WARNING, "JPEG2000 Header box not read yet, '%c%c%c%c' box will be ignored\n", (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0)); + jp2->jp2_state |= JP2_STATE_UNKNOWN; + if (opj_stream_skip(stream,l_current_data_size,p_manager) != l_current_data_size) { + opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + continue; + } + } + if ((OPJ_OFF_T)l_current_data_size > opj_stream_get_number_byte_left(stream)) { + /* do not even try to malloc if we can't read */ + opj_event_msg(p_manager, EVT_ERROR, "Invalid box size %d for box '%c%c%c%c'. Need %d bytes, %d bytes remaining \n", box.length, (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0), l_current_data_size, (OPJ_UINT32)opj_stream_get_number_byte_left(stream)); + opj_free(l_current_data); + return OPJ_FALSE; + } if (l_current_data_size > l_last_data_size) { OPJ_BYTE* new_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_data_size); if (!new_current_data) { @@ -1869,6 +2188,16 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2, } } else { + if (!(jp2->jp2_state & JP2_STATE_SIGNATURE)) { + opj_event_msg(p_manager, EVT_ERROR, "Malformed JP2 file format: first box must be JPEG 2000 signature box\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + if (!(jp2->jp2_state & JP2_STATE_FILE_TYPE)) { + opj_event_msg(p_manager, EVT_ERROR, "Malformed JP2 file format: second box must be file type box\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } jp2->jp2_state |= JP2_STATE_UNKNOWN; if (opj_stream_skip(stream,l_current_data_size,p_manager) != l_current_data_size) { opj_event_msg(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); @@ -1935,7 +2264,9 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, assert(p_manager != 00); /* customization of the validation */ - opj_jp2_setup_encoding_validation (jp2); + if (! opj_jp2_setup_encoding_validation (jp2, p_manager)) { + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_jp2_exec(jp2,jp2->m_validation_list,stream,p_manager)) { @@ -1943,7 +2274,9 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, } /* customization of the encoding */ - opj_jp2_setup_header_writing(jp2); + if (! opj_jp2_setup_header_writing(jp2, p_manager)) { + return OPJ_FALSE; + } /* write header */ if (! opj_jp2_exec (jp2,jp2->m_procedure_list,stream,p_manager)) { @@ -1953,7 +2286,7 @@ OPJ_BOOL opj_jp2_start_compress(opj_jp2_t *jp2, return opj_j2k_start_compress(jp2->j2k,stream,p_image,p_manager); } -const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id) +static const opj_jp2_header_handler_t * opj_jp2_find_handler (OPJ_UINT32 p_id) { OPJ_UINT32 i, l_handler_size = sizeof(jp2_header) / sizeof(opj_jp2_header_handler_t); @@ -2083,12 +2416,11 @@ static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, /* div by 4 */ jp2->numcl = l_remaining_bytes >> 2; if (jp2->numcl) { - jp2->cl = (OPJ_UINT32 *) opj_malloc(jp2->numcl * sizeof(OPJ_UINT32)); + jp2->cl = (OPJ_UINT32 *) opj_calloc(jp2->numcl, sizeof(OPJ_UINT32)); if (jp2->cl == 00) { opj_event_msg(p_manager, EVT_ERROR, "Not enough memory with FTYP Box\n"); return OPJ_FALSE; } - memset(jp2->cl,0,jp2->numcl * sizeof(OPJ_UINT32)); } for (i = 0; i < jp2->numcl; ++i) @@ -2102,7 +2434,7 @@ static OPJ_BOOL opj_jp2_read_ftyp( opj_jp2_t *jp2, return OPJ_TRUE; } -OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, +static OPJ_BOOL opj_jp2_skip_jp2c( opj_jp2_t *jp2, opj_stream_private_t *stream, opj_event_mgr_t * p_manager ) { @@ -2146,7 +2478,7 @@ static OPJ_BOOL opj_jpip_skip_iptr( opj_jp2_t *jp2, * @param p_header_size the size of the data contained in the file header box. * @param p_manager the user event manager. * - * @return true if the JP2 Header box was successfully reconized. + * @return true if the JP2 Header box was successfully recognized. */ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_BYTE *p_header_data, @@ -2157,6 +2489,7 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, OPJ_UINT32 l_box_size=0, l_current_data_size = 0; opj_jp2_box_t box; const opj_jp2_header_handler_t * l_current_handler; + OPJ_BOOL l_has_ihdr = 0; /* preconditions */ assert(p_header_data != 00); @@ -2197,16 +2530,25 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2, jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN; } + if (box.type == JP2_IHDR) { + l_has_ihdr = 1; + } + p_header_data += l_current_data_size; p_header_size -= box.length; } + if (l_has_ihdr == 0) { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box: no 'ihdr' box.\n"); + return OPJ_FALSE; + } + jp2->jp2_state |= JP2_STATE_HEADER; return OPJ_TRUE; } -OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, +static OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, OPJ_BYTE * p_data, OPJ_UINT32 * p_number_bytes_read, OPJ_UINT32 p_box_max_size, @@ -2269,7 +2611,10 @@ OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box, opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); return OPJ_FALSE; } - + if (box->length < *p_number_bytes_read) { + opj_event_msg(p_manager, EVT_ERROR, "Box length is inconsistent.\n"); + return OPJ_FALSE; + } return OPJ_TRUE; } @@ -2285,10 +2630,14 @@ OPJ_BOOL opj_jp2_read_header( opj_stream_private_t *p_stream, assert(p_manager != 00); /* customization of the validation */ - opj_jp2_setup_decoding_validation (jp2); + if (! opj_jp2_setup_decoding_validation (jp2, p_manager)) { + return OPJ_FALSE; + } /* customization of the encoding */ - opj_jp2_setup_header_reading(jp2); + if (! opj_jp2_setup_header_reading(jp2, p_manager)) { + return OPJ_FALSE; + } /* validation of the parameters codec */ if (! opj_jp2_exec(jp2,jp2->m_validation_list,p_stream,p_manager)) { @@ -2306,45 +2655,73 @@ OPJ_BOOL opj_jp2_read_header( opj_stream_private_t *p_stream, p_manager); } -void opj_jp2_setup_encoding_validation (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_encoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_validation_list, (opj_procedure)opj_jp2_default_validation); + if (! opj_procedure_list_add_procedure(jp2->m_validation_list, (opj_procedure)opj_jp2_default_validation, p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, add your custom validation procedure */ + + return OPJ_TRUE; } -void opj_jp2_setup_decoding_validation (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_decoding_validation (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); + /* DEVELOPER CORNER, add your custom validation procedure */ + + return OPJ_TRUE; } -void opj_jp2_setup_header_writing (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_header_writing (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_ftyp ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2h ); - if( jp2->jpip_on ) - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_skip_iptr ); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_skip_jp2c ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_ftyp, p_manager)) { + return OPJ_FALSE; + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_write_jp2h, p_manager)) { + return OPJ_FALSE; + } + if( jp2->jpip_on ) { + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jpip_skip_iptr, p_manager)) { + return OPJ_FALSE; + } + } + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_skip_jp2c,p_manager)) { + return OPJ_FALSE; + } /* DEVELOPER CORNER, insert your custom procedures */ + return OPJ_TRUE; } -void opj_jp2_setup_header_reading (opj_jp2_t *jp2) +static OPJ_BOOL opj_jp2_setup_header_reading (opj_jp2_t *jp2, opj_event_mgr_t * p_manager) { /* preconditions */ assert(jp2 != 00); + assert(p_manager != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure ); + if (! opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)opj_jp2_read_header_procedure, p_manager)) { + return OPJ_FALSE; + } + /* DEVELOPER CORNER, add your custom procedures */ + + return OPJ_TRUE; } OPJ_BOOL opj_jp2_read_tile_header ( opj_jp2_t * p_jp2, @@ -2500,14 +2877,13 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, p_image->color_space = OPJ_CLRSPC_GRAY; else if (p_jp2->enumcs == 18) p_image->color_space = OPJ_CLRSPC_SYCC; + else if (p_jp2->enumcs == 24) + p_image->color_space = OPJ_CLRSPC_EYCC; + else if (p_jp2->enumcs == 12) + p_image->color_space = OPJ_CLRSPC_CMYK; else p_image->color_space = OPJ_CLRSPC_UNKNOWN; - /* Apply the color space if needed */ - if(p_jp2->color.jp2_cdef) { - opj_jp2_apply_cdef(p_image, &(p_jp2->color)); - } - if(p_jp2->color.jp2_pclr) { /* Part 1, I.5.3.4: Either both or none : */ if( !p_jp2->color.jp2_pclr->cmap) @@ -2515,6 +2891,11 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, else opj_jp2_apply_pclr(p_image, &(p_jp2->color)); } + + /* Apply the color space if needed */ + if(p_jp2->color.jp2_cdef) { + opj_jp2_apply_cdef(p_image, &(p_jp2->color), p_manager); + } if(p_jp2->color.icc_profile_buf) { p_image->icc_profile_buf = p_jp2->color.icc_profile_buf; @@ -2531,9 +2912,8 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, opj_jp2_t* opj_jp2_create(OPJ_BOOL p_is_decoder) { - opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t)); + opj_jp2_t *jp2 = (opj_jp2_t*)opj_calloc(1,sizeof(opj_jp2_t)); if (jp2) { - memset(jp2,0,sizeof(opj_jp2_t)); /* create the J2K codec */ if (! p_is_decoder) { diff --git a/src/lib/openjp2/jp2.h b/src/lib/openjp2/jp2.h index c11d2f31..94138832 100644 --- a/src/lib/openjp2/jp2.h +++ b/src/lib/openjp2/jp2.h @@ -90,7 +90,7 @@ typedef enum JP2_IMG_STATE; /** -Channel description: channel index, type, assocation +Channel description: channel index, type, association */ typedef struct opj_jp2_cdef_info { @@ -235,19 +235,6 @@ opj_jp2_img_header_writer_handler_t; /*@{*/ /* ----------------------------------------------------------------------- */ -/** - * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). - * - * @param jp2 the jpeg2000 file codec. - * @param stream the stream to write data to. - * @param p_manager user event manager. - * - * @return true if writing was successful. -*/ -OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, - opj_stream_private_t *stream, - opj_event_mgr_t * p_manager ); - /** Setup the decoder decoding parameters using user parameters. Decoding parameters are returned in jp2->j2k->cp. @@ -278,8 +265,9 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, * @param parameters compression parameters * @param image input filled image * @param p_manager FIXME DOC + * @return OPJ_TRUE if successful, OPJ_FALSE otherwise */ -void opj_jp2_setup_encoder( opj_jp2_t *jp2, +OPJ_BOOL opj_jp2_setup_encoder( opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t * p_manager); diff --git a/src/lib/openjp2/mct.c b/src/lib/openjp2/mct.c index 60ee0969..02259679 100644 --- a/src/lib/openjp2/mct.c +++ b/src/lib/openjp2/mct.c @@ -40,6 +40,12 @@ #ifdef __SSE__ #include #endif +#ifdef __SSE2__ +#include +#endif +#ifdef __SSE4_1__ +#include +#endif #include "opj_includes.h" @@ -64,16 +70,39 @@ const OPJ_FLOAT64 * opj_mct_get_mct_norms_real () } /* */ -/* Foward reversible MCT. */ +/* Forward reversible MCT. */ /* */ +#ifdef __SSE2__ void opj_mct_encode( OPJ_INT32* restrict c0, OPJ_INT32* restrict c1, OPJ_INT32* restrict c2, OPJ_UINT32 n) { - OPJ_UINT32 i; - for(i = 0; i < n; ++i) { + OPJ_SIZE_T i; + const OPJ_SIZE_T len = n; + /* buffer are aligned on 16 bytes */ + assert( ((size_t)c0 & 0xf) == 0 ); + assert( ((size_t)c1 & 0xf) == 0 ); + assert( ((size_t)c2 & 0xf) == 0 ); + + for(i = 0; i < (len & ~3U); i += 4) { + __m128i y, u, v; + __m128i r = _mm_load_si128((const __m128i *)&(c0[i])); + __m128i g = _mm_load_si128((const __m128i *)&(c1[i])); + __m128i b = _mm_load_si128((const __m128i *)&(c2[i])); + y = _mm_add_epi32(g, g); + y = _mm_add_epi32(y, b); + y = _mm_add_epi32(y, r); + y = _mm_srai_epi32(y, 2); + u = _mm_sub_epi32(b, g); + v = _mm_sub_epi32(r, g); + _mm_store_si128((__m128i *)&(c0[i]), y); + _mm_store_si128((__m128i *)&(c1[i]), u); + _mm_store_si128((__m128i *)&(c2[i]), v); + } + + for(; i < len; ++i) { OPJ_INT32 r = c0[i]; OPJ_INT32 g = c1[i]; OPJ_INT32 b = c2[i]; @@ -85,10 +114,69 @@ void opj_mct_encode( c2[i] = v; } } +#else +void opj_mct_encode( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_SIZE_T i; + const OPJ_SIZE_T len = n; + + for(i = 0; i < len; ++i) { + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = (r + (g * 2) + b) >> 2; + OPJ_INT32 u = b - g; + OPJ_INT32 v = r - g; + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} +#endif /* */ /* Inverse reversible MCT. */ /* */ +#ifdef __SSE2__ +void opj_mct_decode( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_SIZE_T i; + const OPJ_SIZE_T len = n; + + for(i = 0; i < (len & ~3U); i += 4) { + __m128i r, g, b; + __m128i y = _mm_load_si128((const __m128i *)&(c0[i])); + __m128i u = _mm_load_si128((const __m128i *)&(c1[i])); + __m128i v = _mm_load_si128((const __m128i *)&(c2[i])); + g = y; + g = _mm_sub_epi32(g, _mm_srai_epi32(_mm_add_epi32(u, v), 2)); + r = _mm_add_epi32(v, g); + b = _mm_add_epi32(u, g); + _mm_store_si128((__m128i *)&(c0[i]), r); + _mm_store_si128((__m128i *)&(c1[i]), g); + _mm_store_si128((__m128i *)&(c2[i]), b); + } + for (; i < len; ++i) { + OPJ_INT32 y = c0[i]; + OPJ_INT32 u = c1[i]; + OPJ_INT32 v = c2[i]; + OPJ_INT32 g = y - ((u + v) >> 2); + OPJ_INT32 r = v + g; + OPJ_INT32 b = u + g; + c0[i] = r; + c1[i] = g; + c2[i] = b; + } +} +#else void opj_mct_decode( OPJ_INT32* restrict c0, OPJ_INT32* restrict c1, @@ -108,6 +196,7 @@ void opj_mct_decode( c2[i] = b; } } +#endif /* */ /* Get norm of basis function of reversible MCT. */ @@ -117,8 +206,150 @@ OPJ_FLOAT64 opj_mct_getnorm(OPJ_UINT32 compno) { } /* */ -/* Foward irreversible MCT. */ +/* Forward irreversible MCT. */ /* */ +#ifdef __SSE4_1__ +void opj_mct_encode_real( + OPJ_INT32* restrict c0, + OPJ_INT32* restrict c1, + OPJ_INT32* restrict c2, + OPJ_UINT32 n) +{ + OPJ_SIZE_T i; + const OPJ_SIZE_T len = n; + + const __m128i ry = _mm_set1_epi32(2449); + const __m128i gy = _mm_set1_epi32(4809); + const __m128i by = _mm_set1_epi32(934); + const __m128i ru = _mm_set1_epi32(1382); + const __m128i gu = _mm_set1_epi32(2714); + /* const __m128i bu = _mm_set1_epi32(4096); */ + /* const __m128i rv = _mm_set1_epi32(4096); */ + const __m128i gv = _mm_set1_epi32(3430); + const __m128i bv = _mm_set1_epi32(666); + const __m128i mulround = _mm_shuffle_epi32(_mm_cvtsi32_si128(4096), _MM_SHUFFLE(1, 0, 1, 0)); + + for(i = 0; i < (len & ~3U); i += 4) { + __m128i lo, hi; + __m128i y, u, v; + __m128i r = _mm_load_si128((const __m128i *)&(c0[i])); + __m128i g = _mm_load_si128((const __m128i *)&(c1[i])); + __m128i b = _mm_load_si128((const __m128i *)&(c2[i])); + + lo = r; + hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, ry); + hi = _mm_mul_epi32(hi, ry); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + y = _mm_blend_epi16(lo, hi, 0xCC); + + lo = g; + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, gy); + hi = _mm_mul_epi32(hi, gy); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC)); + + lo = b; + hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, by); + hi = _mm_mul_epi32(hi, by); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i *)&(c0[i]), y); + + /*lo = b; + hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, mulround); + hi = _mm_mul_epi32(hi, mulround);*/ + lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 2, 0))); + hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 3, 1))); + lo = _mm_slli_epi64(lo, 12); + hi = _mm_slli_epi64(hi, 12); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + u = _mm_blend_epi16(lo, hi, 0xCC); + + lo = r; + hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, ru); + hi = _mm_mul_epi32(hi, ru); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC)); + + lo = g; + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, gu); + hi = _mm_mul_epi32(hi, gu); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i *)&(c1[i]), u); + + /*lo = r; + hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, mulround); + hi = _mm_mul_epi32(hi, mulround);*/ + lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 2, 0))); + hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 3, 1))); + lo = _mm_slli_epi64(lo, 12); + hi = _mm_slli_epi64(hi, 12); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + v = _mm_blend_epi16(lo, hi, 0xCC); + + lo = g; + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, gv); + hi = _mm_mul_epi32(hi, gv); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC)); + + lo = b; + hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(lo, bv); + hi = _mm_mul_epi32(hi, bv); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32-13); + v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i *)&(c2[i]), v); + } + for(; i < len; ++i) { + OPJ_INT32 r = c0[i]; + OPJ_INT32 g = c1[i]; + OPJ_INT32 b = c2[i]; + OPJ_INT32 y = opj_int_fix_mul(r, 2449) + opj_int_fix_mul(g, 4809) + opj_int_fix_mul(b, 934); + OPJ_INT32 u = -opj_int_fix_mul(r, 1382) - opj_int_fix_mul(g, 2714) + opj_int_fix_mul(b, 4096); + OPJ_INT32 v = opj_int_fix_mul(r, 4096) - opj_int_fix_mul(g, 3430) - opj_int_fix_mul(b, 666); + c0[i] = y; + c1[i] = u; + c2[i] = v; + } +} +#else void opj_mct_encode_real( OPJ_INT32* restrict c0, OPJ_INT32* restrict c1, @@ -138,6 +369,7 @@ void opj_mct_encode_real( c2[i] = v; } } +#endif /* */ /* Inverse irreversible MCT. */ diff --git a/src/lib/openjp2/mqc.c b/src/lib/openjp2/mqc.c index 18fcc476..7e0f5637 100644 --- a/src/lib/openjp2/mqc.c +++ b/src/lib/openjp2/mqc.c @@ -202,7 +202,7 @@ static opj_mqc_state_t mqc_states[47 * 2] = { ========================================================== */ -void opj_mqc_byteout(opj_mqc_t *mqc) { +static void opj_mqc_byteout(opj_mqc_t *mqc) { if (*mqc->bp == 0xff) { mqc->bp++; *mqc->bp = (OPJ_BYTE)(mqc->c >> 20); @@ -232,7 +232,7 @@ void opj_mqc_byteout(opj_mqc_t *mqc) { } } -void opj_mqc_renorme(opj_mqc_t *mqc) { +static void opj_mqc_renorme(opj_mqc_t *mqc) { do { mqc->a <<= 1; mqc->c <<= 1; @@ -243,7 +243,7 @@ void opj_mqc_renorme(opj_mqc_t *mqc) { } while ((mqc->a & 0x8000) == 0); } -void opj_mqc_codemps(opj_mqc_t *mqc) { +static void opj_mqc_codemps(opj_mqc_t *mqc) { mqc->a -= (*mqc->curctx)->qeval; if ((mqc->a & 0x8000) == 0) { if (mqc->a < (*mqc->curctx)->qeval) { @@ -258,7 +258,7 @@ void opj_mqc_codemps(opj_mqc_t *mqc) { } } -void opj_mqc_codelps(opj_mqc_t *mqc) { +static void opj_mqc_codelps(opj_mqc_t *mqc) { mqc->a -= (*mqc->curctx)->qeval; if (mqc->a < (*mqc->curctx)->qeval) { mqc->c += (*mqc->curctx)->qeval; @@ -269,7 +269,7 @@ void opj_mqc_codelps(opj_mqc_t *mqc) { opj_mqc_renorme(mqc); } -void opj_mqc_setbits(opj_mqc_t *mqc) { +static void opj_mqc_setbits(opj_mqc_t *mqc) { OPJ_UINT32 tempc = mqc->c + mqc->a; mqc->c |= 0xffff; if (mqc->c >= tempc) { @@ -362,7 +362,9 @@ static INLINE void opj_mqc_renormd(opj_mqc_t *const mqc) { opj_mqc_t* opj_mqc_create(void) { opj_mqc_t *mqc = (opj_mqc_t*)opj_malloc(sizeof(opj_mqc_t)); #ifdef MQC_PERF_OPT - mqc->buffer = NULL; + if (mqc) { + mqc->buffer = NULL; + } #endif return mqc; } @@ -370,7 +372,9 @@ opj_mqc_t* opj_mqc_create(void) { void opj_mqc_destroy(opj_mqc_t *mqc) { if(mqc) { #ifdef MQC_PERF_OPT - opj_free(mqc->buffer); + if (mqc->buffer) { + opj_free(mqc->buffer); + } #endif opj_free(mqc); } diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index 4665d906..5114cc10 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -132,7 +132,7 @@ static OPJ_BOOL opj_seek_from_file (OPJ_OFF_T p_nb_bytes, FILE * p_user_data) #ifdef _WIN32 #ifndef OPJ_STATIC BOOL APIENTRY -DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { +DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { OPJ_ARG_NOT_USED(lpReserved); OPJ_ARG_NOT_USED(hModule); @@ -169,7 +169,6 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) if (!l_codec){ return 00; } - memset(l_codec, 0, sizeof(opj_codec_private_t)); l_codec->is_decompressor = 1; @@ -525,14 +524,12 @@ OPJ_BOOL OPJ_CALLCONV opj_set_decoded_resolution_factor(opj_codec_t *p_codec, opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; if ( !l_codec ){ - fprintf(stderr, "[ERROR] Input parameters of the setup_decoder function are incorrect.\n"); return OPJ_FALSE; } - l_codec->m_codec_data.m_decompression.opj_set_decoded_resolution_factor(l_codec->m_codec, + return l_codec->m_codec_data.m_decompression.opj_set_decoded_resolution_factor(l_codec->m_codec, res_factor, &(l_codec->m_event_mgr) ); - return OPJ_TRUE; } /* ---------------------------------------------------------------------- */ @@ -546,7 +543,6 @@ opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) if (!l_codec) { return 00; } - memset(l_codec, 0, sizeof(opj_codec_private_t)); l_codec->is_decompressor = 0; @@ -574,7 +570,7 @@ opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) l_codec->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) opj_j2k_destroy; - l_codec->m_codec_data.m_compression.opj_setup_encoder = (void (*) ( void *, + l_codec->m_codec_data.m_compression.opj_setup_encoder = (OPJ_BOOL (*) ( void *, opj_cparameters_t *, struct opj_image *, struct opj_event_mgr * )) opj_j2k_setup_encoder; @@ -611,7 +607,7 @@ opj_codec_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT p_format) l_codec->m_codec_data.m_compression.opj_destroy = (void (*) (void *)) opj_jp2_destroy; - l_codec->m_codec_data.m_compression.opj_setup_encoder = (void (*) ( void *, + l_codec->m_codec_data.m_compression.opj_setup_encoder = (OPJ_BOOL (*) ( void *, opj_cparameters_t *, struct opj_image *, struct opj_event_mgr * )) opj_jp2_setup_encoder; @@ -702,11 +698,10 @@ OPJ_BOOL OPJ_CALLCONV opj_setup_encoder(opj_codec_t *p_codec, opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; if (! l_codec->is_decompressor) { - l_codec->m_codec_data.m_compression.opj_setup_encoder( l_codec->m_codec, + return l_codec->m_codec_data.m_compression.opj_setup_encoder( l_codec->m_codec, parameters, p_image, &(l_codec->m_event_mgr) ); - return OPJ_TRUE; } } @@ -871,7 +866,8 @@ void OPJ_CALLCONV opj_dump_codec( opj_codec_t *p_codec, return; } - fprintf(stderr, "[ERROR] Input parameter of the dump_codec function are incorrect.\n"); + /* TODO return error */ + /* fprintf(stderr, "[ERROR] Input parameter of the dump_codec function are incorrect.\n"); */ return; } diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index 988db720..c07e9c84 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -78,29 +78,33 @@ Most compilers implement their own version of this keyword ... #if defined(OPJ_STATIC) || !defined(_WIN32) /* http://gcc.gnu.org/wiki/Visibility */ -#if __GNUC__ >= 4 -#define OPJ_API __attribute__ ((visibility ("default"))) -#define OPJ_LOCAL __attribute__ ((visibility ("hidden"))) +# if __GNUC__ >= 4 +# if defined(OPJ_STATIC) /* static library uses "hidden" */ +# define OPJ_API __attribute__ ((visibility ("hidden"))) +# else +# define OPJ_API __attribute__ ((visibility ("default"))) +# endif +# define OPJ_LOCAL __attribute__ ((visibility ("hidden"))) +# else +# define OPJ_API +# define OPJ_LOCAL +# endif +# define OPJ_CALLCONV #else -#define OPJ_API -#define OPJ_LOCAL -#endif -#define OPJ_CALLCONV -#else -#define OPJ_CALLCONV __stdcall +# define OPJ_CALLCONV __stdcall /* The following ifdef block is the standard way of creating macros which make exporting from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS symbol defined on the command line. this symbol should not be defined on any project that uses this DLL. This way any other project whose source files include this file see -OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +OPJ_API functions as being imported from a DLL, whereas this DLL sees symbols defined with this macro as being exported. */ -#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) -#define OPJ_API __declspec(dllexport) -#else -#define OPJ_API __declspec(dllimport) -#endif /* OPJ_EXPORTS */ +# if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) +# define OPJ_API __declspec(dllexport) +# else +# define OPJ_API __declspec(dllimport) +# endif /* OPJ_EXPORTS */ #endif /* !OPJ_STATIC || !_WIN32 */ typedef int OPJ_BOOL; @@ -846,7 +850,7 @@ typedef struct opj_codestream_info { } opj_codestream_info_t; /* <----------------------------------------------------------- */ -/* new output managment of the codestream information and index */ +/* new output management of the codestream information and index */ /** * Tile-component coding parameters information @@ -1343,7 +1347,7 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_write_tile ( opj_codec_t *p_codec, opj_stream_t *p_stream ); /** - * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. + * Reads a tile header. This function is compulsory and allows one to know the size of the tile that will be decoded. * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. * * @param p_codec the jpeg2000 codec. diff --git a/src/lib/openjp2/opj_clock.c b/src/lib/openjp2/opj_clock.c index 0df99ef0..bb4cae73 100644 --- a/src/lib/openjp2/opj_clock.c +++ b/src/lib/openjp2/opj_clock.c @@ -29,6 +29,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "opj_includes.h" + #ifdef _WIN32 #include #else @@ -36,7 +38,6 @@ #include #include #endif /* _WIN32 */ -#include "opj_includes.h" OPJ_FLOAT64 opj_clock(void) { #ifdef _WIN32 diff --git a/src/lib/openjp2/opj_codec.h b/src/lib/openjp2/opj_codec.h index 4fdfa7d8..6bd791fa 100644 --- a/src/lib/openjp2/opj_codec.h +++ b/src/lib/openjp2/opj_codec.h @@ -142,10 +142,10 @@ typedef struct opj_codec_private void (* opj_destroy) (void * p_codec); - void (* opj_setup_encoder) ( void * p_codec, - opj_cparameters_t * p_param, - struct opj_image * p_image, - struct opj_event_mgr * p_manager); + OPJ_BOOL (* opj_setup_encoder) ( void * p_codec, + opj_cparameters_t * p_param, + struct opj_image * p_image, + struct opj_event_mgr * p_manager); } m_compression; } m_codec_data; /** FIXME DOC*/ diff --git a/src/lib/openjp2/opj_config_private.h.cmake.in b/src/lib/openjp2/opj_config_private.h.cmake.in index 8a02c79d..c41f9066 100644 --- a/src/lib/openjp2/opj_config_private.h.cmake.in +++ b/src/lib/openjp2/opj_config_private.h.cmake.in @@ -17,6 +17,24 @@ #cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@ #cmakedefine OPJ_HAVE_FSEEKO @OPJ_HAVE_FSEEKO@ +/* find whether or not have */ +#cmakedefine OPJ_HAVE_MALLOC_H +/* check if function `aligned_alloc` exists */ +#cmakedefine OPJ_HAVE_ALIGNED_ALLOC +/* check if function `_aligned_malloc` exists */ +#cmakedefine OPJ_HAVE__ALIGNED_MALLOC +/* check if function `memalign` exists */ +#cmakedefine OPJ_HAVE_MEMALIGN +/* check if function `posix_memalign` exists */ +#cmakedefine OPJ_HAVE_POSIX_MEMALIGN + +#if !defined(_POSIX_C_SOURCE) +#if defined(OPJ_HAVE_FSEEKO) || defined(OPJ_HAVE_POSIX_MEMALIGN) +/* Get declarations of fseeko, ftello, posix_memalign. */ +#define _POSIX_C_SOURCE 200112L +#endif +#endif + /* Byte order. */ /* All compilers that support Mac OS X define either __BIG_ENDIAN__ or __LITTLE_ENDIAN__ to match the endianness of the architecture being @@ -28,4 +46,4 @@ On other platforms we use the result of the TRY_RUN. */ #cmakedefine OPJ_BIG_ENDIAN #elif defined(__BIG_ENDIAN__) # define OPJ_BIG_ENDIAN -#endif \ No newline at end of file +#endif diff --git a/src/lib/openjp2/opj_includes.h b/src/lib/openjp2/opj_includes.h index d9238b1b..f855b7c6 100644 --- a/src/lib/openjp2/opj_includes.h +++ b/src/lib/openjp2/opj_includes.h @@ -118,29 +118,65 @@ #endif #endif + + /* MSVC before 2013 and Borland C do not have lrintf */ -#if defined(_MSC_VER) && (_MSC_VER < 1800) || defined(__BORLANDC__) -static INLINE long lrintf(float f){ +#if defined(_MSC_VER) +#include +static INLINE long opj_lrintf(float f){ #ifdef _M_X64 - return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); -#else + return _mm_cvt_ss2si(_mm_load_ss(&f)); + + /* commented out line breaks many tests */ + /* return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); */ +#elif defined(_M_IX86) int i; - - _asm{ + _asm{ fld f fistp i }; return i; +#else + return (long)((f>0.0f) ? (f + 0.5f) : (f - 0.5f)); #endif } +#elif defined(__BORLANDC__) +static INLINE long opj_lrintf(float f) { +#ifdef _M_X64 + return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); +#else + int i; + + _asm { + fld f + fistp i + }; + + return i; +#endif +} +#else +static INLINE long opj_lrintf(float f) { + return lrintf(f); +} +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1400) + #define vsnprintf _vsnprintf +#endif + +/* MSVC x86 is really bad at doing int64 = int32 * int32 on its own. Use intrinsic. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) && defined(_M_IX86) +# include +# pragma intrinsic(__emul) #endif #include "opj_inttypes.h" #include "opj_clock.h" #include "opj_malloc.h" -#include "function_list.h" #include "event.h" +#include "function_list.h" #include "bio.h" #include "cio.h" diff --git a/src/lib/openjp2/opj_intmath.h b/src/lib/openjp2/opj_intmath.h index dc898953..3f7934c4 100644 --- a/src/lib/openjp2/opj_intmath.h +++ b/src/lib/openjp2/opj_intmath.h @@ -81,6 +81,15 @@ static INLINE OPJ_UINT32 opj_uint_max(OPJ_UINT32 a, OPJ_UINT32 b) { return (a > b) ? a : b; } +/** + Get the saturated sum of two unsigned integers + @return Returns saturated sum of a+b + */ +static INLINE OPJ_UINT32 opj_uint_adds(OPJ_UINT32 a, OPJ_UINT32 b) { + OPJ_UINT64 sum = (OPJ_UINT64)a + (OPJ_UINT64)b; + return (OPJ_UINT32)(-(OPJ_INT32)(sum >> 32)) | (OPJ_UINT32)sum; +} + /** Clamp an integer inside an interval @return @@ -108,7 +117,7 @@ Divide an integer and round upwards @return Returns a divided by b */ static INLINE OPJ_INT32 opj_int_ceildiv(OPJ_INT32 a, OPJ_INT32 b) { - assert(b); + assert(b); return (a + b - 1) / b; } @@ -117,6 +126,7 @@ Divide an integer and round upwards @return Returns a divided by b */ static INLINE OPJ_UINT32 opj_uint_ceildiv(OPJ_UINT32 a, OPJ_UINT32 b) { + assert(b); return (a + b - 1) / b; } @@ -125,8 +135,25 @@ Divide an integer by a power of 2 and round upwards @return Returns a divided by 2^b */ static INLINE OPJ_INT32 opj_int_ceildivpow2(OPJ_INT32 a, OPJ_INT32 b) { - return (OPJ_INT32)((a + (OPJ_INT64)(1 << b) - 1) >> b); + return (OPJ_INT32)((a + ((OPJ_INT64)1 << b) - 1) >> b); } + +/** + Divide a 64bits integer by a power of 2 and round upwards + @return Returns a divided by 2^b + */ +static INLINE OPJ_INT32 opj_int64_ceildivpow2(OPJ_INT64 a, OPJ_INT32 b) { + return (OPJ_INT32)((a + ((OPJ_INT64)1 << b) - 1) >> b); +} + +/** + Divide an integer by a power of 2 and round upwards + @return Returns a divided by 2^b + */ +static INLINE OPJ_UINT32 opj_uint_ceildivpow2(OPJ_UINT32 a, OPJ_UINT32 b) { + return (OPJ_UINT32)((a + ((OPJ_UINT64)1U << b) - 1U) >> b); +} + /** Divide an integer by a power of 2 and round downwards @return Returns a divided by 2^b @@ -165,9 +192,27 @@ Multiply two fixed-precision rational numbers. @return Returns a * b */ static INLINE OPJ_INT32 opj_int_fix_mul(OPJ_INT32 a, OPJ_INT32 b) { - OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ; - temp += temp & 4096; - return (OPJ_INT32) (temp >> 13) ; +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) && defined(_M_IX86) + OPJ_INT64 temp = __emul(a, b); +#else + OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ; +#endif + temp += 4096; + assert((temp >> 13) <= (OPJ_INT64)0x7FFFFFFF); + assert((temp >> 13) >= (-(OPJ_INT64)0x7FFFFFFF - (OPJ_INT64)1)); + return (OPJ_INT32) (temp >> 13); +} + +static INLINE OPJ_INT32 opj_int_fix_mul_t1(OPJ_INT32 a, OPJ_INT32 b) { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) && defined(_M_IX86) + OPJ_INT64 temp = __emul(a, b); +#else + OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ; +#endif + temp += 4096; + assert((temp >> (13 + 11 - T1_NMSEDEC_FRACBITS)) <= (OPJ_INT64)0x7FFFFFFF); + assert((temp >> (13 + 11 - T1_NMSEDEC_FRACBITS)) >= (-(OPJ_INT64)0x7FFFFFFF - (OPJ_INT64)1)); + return (OPJ_INT32) (temp >> (13 + 11 - T1_NMSEDEC_FRACBITS)) ; } /* ----------------------------------------------------------------------- */ diff --git a/src/lib/openjp2/opj_malloc.c b/src/lib/openjp2/opj_malloc.c new file mode 100644 index 00000000..e04db912 --- /dev/null +++ b/src/lib/openjp2/opj_malloc.c @@ -0,0 +1,239 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2015, Mathieu Malaterre + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 COPYRIGHT OWNER 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. + */ +#define OPJ_SKIP_POISON +#include "opj_includes.h" + +#if defined(OPJ_HAVE_MALLOC_H) && defined(OPJ_HAVE_MEMALIGN) +# include +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +static INLINE void *opj_aligned_alloc_n(size_t alignment, size_t size) +{ + void* ptr; + + /* alignment shall be power of 2 */ + assert( (alignment != 0U) && ((alignment & (alignment - 1U)) == 0U)); + /* alignment shall be at least sizeof(void*) */ + assert( alignment >= sizeof(void*)); + + if (size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + +#if defined(OPJ_HAVE_POSIX_MEMALIGN) + /* aligned_alloc requires c11, restrict to posix_memalign for now. Quote: + * This function was introduced in POSIX 1003.1d. Although this function is + * superseded by aligned_alloc, it is more portable to older POSIX systems + * that do not support ISO C11. */ + if (posix_memalign (&ptr, alignment, size)) + { + ptr = NULL; + } + /* older linux */ +#elif defined(OPJ_HAVE_MEMALIGN) + ptr = memalign( alignment, size ); +/* _MSC_VER */ +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + ptr = _aligned_malloc(size, alignment); +#else + /* + * Generic aligned malloc implementation. + * Uses size_t offset for the integer manipulation of the pointer, + * as uintptr_t is not available in C89 to do + * bitwise operations on the pointer itself. + */ + alignment--; + { + size_t offset; + OPJ_UINT8 *mem; + + /* Room for padding and extra pointer stored in front of allocated area */ + size_t overhead = alignment + sizeof(void *); + + /* let's be extra careful */ + assert(alignment <= (SIZE_MAX - sizeof(void *))); + + /* Avoid integer overflow */ + if (size > (SIZE_MAX - overhead)) { + return NULL; + } + + mem = (OPJ_UINT8*)malloc(size + overhead); + if (mem == NULL) { + return mem; + } + /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */ + /* Use the fact that alignment + 1U is a power of 2 */ + offset = ((alignment ^ ((size_t)(mem + sizeof(void*)) & alignment)) + 1U) & alignment; + ptr = (void *)(mem + sizeof(void*) + offset); + ((void**) ptr)[-1] = mem; + } +#endif + return ptr; +} +static INLINE void *opj_aligned_realloc_n(void *ptr, size_t alignment, size_t new_size) +{ + void *r_ptr; + + /* alignment shall be power of 2 */ + assert( (alignment != 0U) && ((alignment & (alignment - 1U)) == 0U)); + /* alignment shall be at least sizeof(void*) */ + assert( alignment >= sizeof(void*)); + + if (new_size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + +/* no portable aligned realloc */ +#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN) + /* glibc doc states one can mix aligned malloc with realloc */ + r_ptr = realloc( ptr, new_size ); /* fast path */ + /* we simply use `size_t` to cast, since we are only interest in binary AND + * operator */ + if( ((size_t)r_ptr & (alignment - 1U)) != 0U ) { + /* this is non-trivial to implement a portable aligned realloc, so use a + * simple approach where we do not need a function that return the size of an + * allocated array (eg. _msize on Windows, malloc_size on MacOS, + * malloc_usable_size on systems with glibc) */ + void *a_ptr = opj_aligned_alloc_n(alignment, new_size); + if (a_ptr != NULL) { + memcpy(a_ptr, r_ptr, new_size); + } + free( r_ptr ); + r_ptr = a_ptr; + } +/* _MSC_VER */ +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + r_ptr = _aligned_realloc( ptr, new_size, alignment ); +#else + if (ptr == NULL) { + return opj_aligned_alloc_n(alignment, new_size); + } + alignment--; + { + void *oldmem; + OPJ_UINT8 *newmem; + size_t overhead = alignment + sizeof(void *); + + /* let's be extra careful */ + assert(alignment <= (SIZE_MAX - sizeof(void *))); + + /* Avoid integer overflow */ + if (new_size > SIZE_MAX - overhead) { + return NULL; + } + + oldmem = ((void**) ptr)[-1]; + newmem = (OPJ_UINT8*)realloc(oldmem, new_size + overhead); + if (newmem == NULL) { + return newmem; + } + + if (newmem == oldmem) { + r_ptr = ptr; + } + else { + size_t old_offset; + size_t new_offset; + + /* realloc created a new copy, realign the copied memory block */ + old_offset = (size_t)((OPJ_UINT8*)ptr - (OPJ_UINT8*)oldmem); + + /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */ + /* Use the fact that alignment + 1U is a power of 2 */ + new_offset = ((alignment ^ ((size_t)(newmem + sizeof(void*)) & alignment)) + 1U) & alignment; + new_offset += sizeof(void*); + r_ptr = (void *)(newmem + new_offset); + + if (new_offset != old_offset) { + memmove(newmem + new_offset, newmem + old_offset, new_size); + } + ((void**) r_ptr)[-1] = newmem; + } + } +#endif + return r_ptr; +} +void * opj_malloc(size_t size) +{ + if (size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + return malloc(size); +} +void * opj_calloc(size_t num, size_t size) +{ + if (size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + /* according to C89 standard, num == 0 shall return a valid pointer */ + return calloc(num, size); +} + +void *opj_aligned_malloc(size_t size) +{ + return opj_aligned_alloc_n(16U, size); +} +void * opj_aligned_realloc(void *ptr, size_t size) +{ + return opj_aligned_realloc_n(ptr, 16U, size); +} + +void opj_aligned_free(void* ptr) +{ +#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN) + free( ptr ); +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + _aligned_free( ptr ); +#else + /* Generic implementation has malloced pointer stored in front of used area */ + if (ptr != NULL) { + free(((void**) ptr)[-1]); + } +#endif +} + +void * opj_realloc(void *ptr, size_t new_size) +{ + if (new_size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + return realloc(ptr, new_size); +} +void opj_free(void *ptr) +{ + free(ptr); +} diff --git a/src/lib/openjp2/opj_malloc.h b/src/lib/openjp2/opj_malloc.h index 5007b0c9..1b3fced9 100644 --- a/src/lib/openjp2/opj_malloc.h +++ b/src/lib/openjp2/opj_malloc.h @@ -31,6 +31,8 @@ */ #ifndef __OPJ_MALLOC_H #define __OPJ_MALLOC_H + +#include /** @file opj_malloc.h @brief Internal functions @@ -50,16 +52,7 @@ Allocate an uninitialized memory block @param size Bytes to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_malloc(size_t size); -#else -/* prevent assertion on overflow for MSVC */ -#ifdef _MSC_VER -#define opj_malloc(size) ((size_t)(size) >= (size_t)-0x100 ? NULL : malloc(size)) -#else -#define opj_malloc(size) malloc(size) -#endif -#endif +void * opj_malloc(size_t size); /** Allocate a memory block with elements initialized to 0 @@ -67,83 +60,16 @@ Allocate a memory block with elements initialized to 0 @param size Bytes per block to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements); -#else -/* prevent assertion on overflow for MSVC */ -#ifdef _MSC_VER -#define opj_calloc(num, size) ((size_t)(num) != 0 && (size_t)(num) >= (size_t)-0x100 / (size_t)(size) ? NULL : calloc(num, size)) -#else -#define opj_calloc(num, size) calloc(num, size) -#endif -#endif +void * opj_calloc(size_t numOfElements, size_t sizeOfElements); /** -Allocate memory aligned to a 16 byte boundry +Allocate memory aligned to a 16 byte boundary @param size Bytes to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ -#ifdef _WIN32 - /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ - #ifdef __GNUC__ - #include - #define HAVE_MM_MALLOC - #else /* MSVC, Intel C++ */ - #include - #ifdef _mm_malloc - #define HAVE_MM_MALLOC - #endif - #endif -#else /* Not _WIN32 */ - #if defined(__sun) - #define HAVE_MEMALIGN - #elif defined(__FreeBSD__) - #define HAVE_POSIX_MEMALIGN - /* Linux x86_64 and OSX always align allocations to 16 bytes */ - #elif !defined(__amd64__) && !defined(__APPLE__) && !defined(_AIX) - #define HAVE_MEMALIGN - #include - #endif -#endif - -#define opj_aligned_malloc(size) malloc(size) -#define opj_aligned_free(m) free(m) - -#ifdef HAVE_MM_MALLOC - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) _mm_malloc(size, 16) - #undef opj_aligned_free - #define opj_aligned_free(m) _mm_free(m) -#endif - -#ifdef HAVE_MEMALIGN - extern void* memalign(size_t, size_t); - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) memalign(16, (size)) - #undef opj_aligned_free - #define opj_aligned_free(m) free(m) -#endif - -#ifdef HAVE_POSIX_MEMALIGN - #undef opj_aligned_malloc - extern int posix_memalign(void**, size_t, size_t); - - static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ - void* mem = NULL; - posix_memalign(&mem, 16, size); - return mem; - } - #undef opj_aligned_free - #define opj_aligned_free(m) free(m) -#endif - -#ifdef ALLOC_PERF_OPT - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) opj_malloc(size) - #undef opj_aligned_free - #define opj_aligned_free(m) opj_free(m) -#endif +void * opj_aligned_malloc(size_t size); +void * opj_aligned_realloc(void *ptr, size_t size); +void opj_aligned_free(void* ptr); /** Reallocate memory blocks. @@ -151,28 +77,15 @@ Reallocate memory blocks. @param s New size in bytes @return Returns a void pointer to the reallocated (and possibly moved) memory block */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_realloc(void * m, size_t s); -#else -/* prevent assertion on overflow for MSVC */ -#ifdef _MSC_VER -#define opj_realloc(m, s) ((size_t)(s) >= (size_t)-0x100 ? NULL : realloc(m, s)) -#else -#define opj_realloc(m, s) realloc(m, s) -#endif -#endif +void * opj_realloc(void * m, size_t s); /** Deallocates or frees a memory block. @param m Previously allocated memory block to be freed */ -#ifdef ALLOC_PERF_OPT -void OPJ_CALLCONV opj_free(void * m); -#else -#define opj_free(m) free(m) -#endif +void opj_free(void * m); -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(OPJ_SKIP_POISON) #pragma GCC poison malloc calloc realloc free #endif diff --git a/src/lib/openjp2/pi.c b/src/lib/openjp2/pi.c index 1d8db41b..bfee10a2 100644 --- a/src/lib/openjp2/pi.c +++ b/src/lib/openjp2/pi.c @@ -136,10 +136,10 @@ static void opj_pi_update_encode_not_poc ( opj_cp_t *p_cp, * @param p_tx1 pointer that will hold the X1 parameter for the tile * @param p_ty0 pointer that will hold the Y0 parameter for the tile * @param p_ty1 pointer that will hold the Y1 parameter for the tile - * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile - * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. - * @param p_dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. - * @param p_dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + * @param p_max_prec pointer that will hold the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the maximum number of resolutions for all the poc inside the tile. + * @param p_dx_min pointer that will hold the minimum dx of all the components of all the resolutions for the tile. + * @param p_dy_min pointer that will hold the minimum dy of all the components of all the resolutions for the tile. */ static void opj_get_encoding_parameters(const opj_image_t *p_image, const opj_cp_t *p_cp, @@ -167,10 +167,10 @@ static void opj_get_encoding_parameters(const opj_image_t *p_image, * @param p_tx1 pointer that will hold the X1 parameter for the tile * @param p_ty0 pointer that will hold the Y0 parameter for the tile * @param p_ty1 pointer that will hold the Y1 parameter for the tile - * @param p_max_prec pointer that will hold the the maximum precision for all the bands of the tile - * @param p_max_res pointer that will hold the the maximum number of resolutions for all the poc inside the tile. - * @param p_dx_min pointer that will hold the the minimum dx of all the components of all the resolutions for the tile. - * @param p_dy_min pointer that will hold the the minimum dy of all the components of all the resolutions for the tile. + * @param p_max_prec pointer that will hold the maximum precision for all the bands of the tile + * @param p_max_res pointer that will hold the maximum number of resolutions for all the poc inside the tile. + * @param p_dx_min pointer that will hold the minimum dx of all the components of all the resolutions for the tile. + * @param p_dy_min pointer that will hold the minimum dy of all the components of all the resolutions for the tile. * @param p_resolutions pointer to an area corresponding to the one described above. */ static void opj_get_all_encoding_parameters(const opj_image_t *p_image, @@ -214,7 +214,7 @@ static void opj_pi_update_decode_poc ( opj_pi_iterator_t * p_pi, /** * FIXME DOC */ -OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, +static OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, opj_cp_t *cp, OPJ_UINT32 tileno, OPJ_UINT32 pino, @@ -230,7 +230,7 @@ OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, ========================================================== */ -OPJ_BOOL opj_pi_next_lrcp(opj_pi_iterator_t * pi) { +static OPJ_BOOL opj_pi_next_lrcp(opj_pi_iterator_t * pi) { opj_pi_comp_t *comp = NULL; opj_pi_resolution_t *res = NULL; OPJ_UINT32 index = 0; @@ -270,7 +270,7 @@ LABEL_SKIP:; return OPJ_FALSE; } -OPJ_BOOL opj_pi_next_rlcp(opj_pi_iterator_t * pi) { +static OPJ_BOOL opj_pi_next_rlcp(opj_pi_iterator_t * pi) { opj_pi_comp_t *comp = NULL; opj_pi_resolution_t *res = NULL; OPJ_UINT32 index = 0; @@ -309,7 +309,7 @@ LABEL_SKIP:; return OPJ_FALSE; } -OPJ_BOOL opj_pi_next_rpcl(opj_pi_iterator_t * pi) { +static OPJ_BOOL opj_pi_next_rpcl(opj_pi_iterator_t * pi) { opj_pi_comp_t *comp = NULL; opj_pi_resolution_t *res = NULL; OPJ_UINT32 index = 0; @@ -392,7 +392,7 @@ LABEL_SKIP:; return OPJ_FALSE; } -OPJ_BOOL opj_pi_next_pcrl(opj_pi_iterator_t * pi) { +static OPJ_BOOL opj_pi_next_pcrl(opj_pi_iterator_t * pi) { opj_pi_comp_t *comp = NULL; opj_pi_resolution_t *res = NULL; OPJ_UINT32 index = 0; @@ -473,7 +473,7 @@ LABEL_SKIP:; return OPJ_FALSE; } -OPJ_BOOL opj_pi_next_cprl(opj_pi_iterator_t * pi) { +static OPJ_BOOL opj_pi_next_cprl(opj_pi_iterator_t * pi) { opj_pi_comp_t *comp = NULL; opj_pi_resolution_t *res = NULL; OPJ_UINT32 index = 0; @@ -552,7 +552,7 @@ LABEL_SKIP:; return OPJ_FALSE; } -void opj_get_encoding_parameters( const opj_image_t *p_image, +static void opj_get_encoding_parameters( const opj_image_t *p_image, const opj_cp_t *p_cp, OPJ_UINT32 p_tileno, OPJ_INT32 * p_tx0, @@ -666,7 +666,7 @@ void opj_get_encoding_parameters( const opj_image_t *p_image, } -void opj_get_all_encoding_parameters( const opj_image_t *p_image, +static void opj_get_all_encoding_parameters( const opj_image_t *p_image, const opj_cp_t *p_cp, OPJ_UINT32 tileno, OPJ_INT32 * p_tx0, @@ -693,6 +693,9 @@ void opj_get_all_encoding_parameters( const opj_image_t *p_image, /* position in x and y of tile*/ OPJ_UINT32 p, q; + /* non-corrected (in regard to image offset) tile offset */ + OPJ_UINT32 l_tx0, l_ty0; + /* preconditions in debug*/ assert(p_cp != 00); assert(p_image != 00); @@ -708,10 +711,12 @@ void opj_get_all_encoding_parameters( const opj_image_t *p_image, q = tileno / p_cp->tw; /* here calculation of tx0, tx1, ty0, ty1, maxprec, l_dx and l_dy */ - *p_tx0 = opj_int_max((OPJ_INT32)(p_cp->tx0 + p * p_cp->tdx), (OPJ_INT32)p_image->x0); - *p_tx1 = opj_int_min((OPJ_INT32)(p_cp->tx0 + (p + 1) * p_cp->tdx), (OPJ_INT32)p_image->x1); - *p_ty0 = opj_int_max((OPJ_INT32)(p_cp->ty0 + q * p_cp->tdy), (OPJ_INT32)p_image->y0); - *p_ty1 = opj_int_min((OPJ_INT32)(p_cp->ty0 + (q + 1) * p_cp->tdy), (OPJ_INT32)p_image->y1); + l_tx0 = p_cp->tx0 + p * p_cp->tdx; /* can't be greater than p_image->x1 so won't overflow */ + *p_tx0 = (OPJ_INT32)opj_uint_max(l_tx0, p_image->x0); + *p_tx1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_tx0, p_cp->tdx), p_image->x1); + l_ty0 = p_cp->ty0 + q * p_cp->tdy; /* can't be greater than p_image->y1 so won't overflow */ + *p_ty0 = (OPJ_INT32)opj_uint_max(l_ty0, p_image->y0); + *p_ty1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_ty0, p_cp->tdy), p_image->y1); /* max precision and resolution is 0 (can only grow)*/ *p_max_prec = 0; @@ -784,7 +789,7 @@ void opj_get_all_encoding_parameters( const opj_image_t *p_image, } } -opj_pi_iterator_t * opj_pi_create( const opj_image_t *image, +static opj_pi_iterator_t * opj_pi_create( const opj_image_t *image, const opj_cp_t *cp, OPJ_UINT32 tileno ) { @@ -815,7 +820,6 @@ opj_pi_iterator_t * opj_pi_create( const opj_image_t *image, if (!l_pi) { return NULL; } - memset(l_pi,0,l_poc_bound * sizeof(opj_pi_iterator_t)); l_current_pi = l_pi; for (pino = 0; pino < l_poc_bound ; ++pino) { @@ -827,28 +831,26 @@ opj_pi_iterator_t * opj_pi_create( const opj_image_t *image, } l_current_pi->numcomps = image->numcomps; - memset(l_current_pi->comps,0,image->numcomps * sizeof(opj_pi_comp_t)); for (compno = 0; compno < image->numcomps; ++compno) { opj_pi_comp_t *comp = &l_current_pi->comps[compno]; tccp = &tcp->tccps[compno]; - comp->resolutions = (opj_pi_resolution_t*) opj_malloc(tccp->numresolutions * sizeof(opj_pi_resolution_t)); + comp->resolutions = (opj_pi_resolution_t*) opj_calloc(tccp->numresolutions, sizeof(opj_pi_resolution_t)); if (!comp->resolutions) { opj_pi_destroy(l_pi, l_poc_bound); return 00; } comp->numresolutions = tccp->numresolutions; - memset(comp->resolutions,0,tccp->numresolutions * sizeof(opj_pi_resolution_t)); } ++l_current_pi; } return l_pi; } -void opj_pi_update_encode_poc_and_final ( opj_cp_t *p_cp, +static void opj_pi_update_encode_poc_and_final ( opj_cp_t *p_cp, OPJ_UINT32 p_tileno, OPJ_INT32 p_tx0, OPJ_INT32 p_tx1, @@ -926,7 +928,7 @@ void opj_pi_update_encode_poc_and_final ( opj_cp_t *p_cp, } } -void opj_pi_update_encode_not_poc ( opj_cp_t *p_cp, +static void opj_pi_update_encode_not_poc ( opj_cp_t *p_cp, OPJ_UINT32 p_num_comps, OPJ_UINT32 p_tileno, OPJ_INT32 p_tx0, @@ -981,7 +983,7 @@ void opj_pi_update_encode_not_poc ( opj_cp_t *p_cp, } } -void opj_pi_update_decode_poc (opj_pi_iterator_t * p_pi, +static void opj_pi_update_decode_poc (opj_pi_iterator_t * p_pi, opj_tcp_t * p_tcp, OPJ_UINT32 p_max_precision, OPJ_UINT32 p_max_res) @@ -1023,7 +1025,7 @@ void opj_pi_update_decode_poc (opj_pi_iterator_t * p_pi, } } -void opj_pi_update_decode_not_poc (opj_pi_iterator_t * p_pi, +static void opj_pi_update_decode_not_poc (opj_pi_iterator_t * p_pi, opj_tcp_t * p_tcp, OPJ_UINT32 p_max_precision, OPJ_UINT32 p_max_res) @@ -1060,7 +1062,7 @@ void opj_pi_update_decode_not_poc (opj_pi_iterator_t * p_pi, -OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, +static OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, opj_cp_t *cp, OPJ_UINT32 tileno, OPJ_UINT32 pino, @@ -1108,7 +1110,8 @@ OPJ_BOOL opj_pi_check_next_level( OPJ_INT32 pos, break; case 'P': switch(tcp->prg){ - case OPJ_LRCP||OPJ_RLCP: + case OPJ_LRCP: /* fall through */ + case OPJ_RLCP: if(tcp->prc_t == tcp->prcE){ if(opj_pi_check_next_level(i-1,cp,tileno,pino,prog)){ return OPJ_TRUE; @@ -1242,7 +1245,6 @@ opj_pi_iterator_t *opj_pi_create_decode(opj_image_t *p_image, opj_pi_destroy(l_pi, l_bound); return 00; } - memset(l_current_pi->include,0, (l_tcp->numlayers + 1) * l_step_l* sizeof(OPJ_INT16)); /* special treatment for the first packet iterator */ l_current_comp = l_current_pi->comps; @@ -1428,7 +1430,7 @@ opj_pi_iterator_t *opj_pi_initialise_encode(const opj_image_t *p_image, l_step_l = l_max_res * l_step_r; /* set values for first packet iterator*/ - l_pi->tp_on = p_cp->m_specific_param.m_enc.m_tp_on; + l_pi->tp_on = (OPJ_BYTE)p_cp->m_specific_param.m_enc.m_tp_on; l_current_pi = l_pi; /* memory allocation for include*/ @@ -1439,7 +1441,6 @@ opj_pi_iterator_t *opj_pi_initialise_encode(const opj_image_t *p_image, opj_pi_destroy(l_pi, l_bound); return 00; } - memset(l_current_pi->include,0,l_tcp->numlayers * l_step_l* sizeof(OPJ_INT16)); /* special treatment for the first packet iterator*/ l_current_comp = l_current_pi->comps; diff --git a/src/lib/openjp2/pi.h b/src/lib/openjp2/pi.h index f239679f..265d5b1e 100644 --- a/src/lib/openjp2/pi.h +++ b/src/lib/openjp2/pi.h @@ -73,7 +73,7 @@ Packet iterator typedef struct opj_pi_iterator { /** Enabling Tile part generation*/ OPJ_BYTE tp_on; - /** precise if the packet has been already used (usefull for progression order change) */ + /** precise if the packet has been already used (useful for progression order change) */ OPJ_INT16 *include; /** layer step used to localize the packet in the include vector */ OPJ_UINT32 step_l; diff --git a/src/lib/openjp2/t1.c b/src/lib/openjp2/t1.c index 0d6c2f60..108ce78b 100644 --- a/src/lib/openjp2/t1.c +++ b/src/lib/openjp2/t1.c @@ -265,7 +265,8 @@ static OPJ_FLOAT64 opj_t1_getwmsedec( OPJ_UINT32 qmfbid, OPJ_FLOAT64 stepsize, OPJ_UINT32 numcomps, - const OPJ_FLOAT64 * mct_norms); + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps); static void opj_t1_encode_cblk( opj_t1_t *t1, opj_tcd_cblk_enc_t* cblk, @@ -277,7 +278,8 @@ static void opj_t1_encode_cblk( opj_t1_t *t1, OPJ_UINT32 cblksty, OPJ_UINT32 numcomps, opj_tcd_tile_t * tile, - const OPJ_FLOAT64 * mct_norms); + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps); /** Decode 1 code-block @@ -293,7 +295,7 @@ static OPJ_BOOL opj_t1_decode_cblk( opj_t1_t *t1, OPJ_UINT32 roishift, OPJ_UINT32 cblksty); -OPJ_BOOL opj_t1_allocate_buffers( opj_t1_t *t1, +static OPJ_BOOL opj_t1_allocate_buffers( opj_t1_t *t1, OPJ_UINT32 w, OPJ_UINT32 h); @@ -303,41 +305,41 @@ OPJ_BOOL opj_t1_allocate_buffers( opj_t1_t *t1, /* ----------------------------------------------------------------------- */ -OPJ_BYTE opj_t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient) { +static OPJ_BYTE opj_t1_getctxno_zc(OPJ_UINT32 f, OPJ_UINT32 orient) { return lut_ctxno_zc[(orient << 8) | (f & T1_SIG_OTH)]; } -OPJ_BYTE opj_t1_getctxno_sc(OPJ_UINT32 f) { +static OPJ_BYTE opj_t1_getctxno_sc(OPJ_UINT32 f) { return lut_ctxno_sc[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; } -OPJ_UINT32 opj_t1_getctxno_mag(OPJ_UINT32 f) { +static OPJ_UINT32 opj_t1_getctxno_mag(OPJ_UINT32 f) { OPJ_UINT32 tmp1 = (f & T1_SIG_OTH) ? T1_CTXNO_MAG + 1 : T1_CTXNO_MAG; OPJ_UINT32 tmp2 = (f & T1_REFINE) ? T1_CTXNO_MAG + 2 : tmp1; return (tmp2); } -OPJ_BYTE opj_t1_getspb(OPJ_UINT32 f) { +static OPJ_BYTE opj_t1_getspb(OPJ_UINT32 f) { return lut_spb[(f & (T1_SIG_PRIM | T1_SGN)) >> 4]; } -OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) { - if (bitpos > T1_NMSEDEC_FRACBITS) { - return lut_nmsedec_sig[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; +static OPJ_INT16 opj_t1_getnmsedec_sig(OPJ_UINT32 x, OPJ_UINT32 bitpos) { + if (bitpos > 0) { + return lut_nmsedec_sig[(x >> (bitpos)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } return lut_nmsedec_sig0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; } -OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { - if (bitpos > T1_NMSEDEC_FRACBITS) { - return lut_nmsedec_ref[(x >> (bitpos - T1_NMSEDEC_FRACBITS)) & ((1 << T1_NMSEDEC_BITS) - 1)]; +static OPJ_INT16 opj_t1_getnmsedec_ref(OPJ_UINT32 x, OPJ_UINT32 bitpos) { + if (bitpos > 0) { + return lut_nmsedec_ref[(x >> (bitpos)) & ((1 << T1_NMSEDEC_BITS) - 1)]; } return lut_nmsedec_ref0[x & ((1 << T1_NMSEDEC_BITS) - 1)]; } -void opj_t1_updateflags(opj_flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride) { +static void opj_t1_updateflags(opj_flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride) { opj_flag_t *np = flagsp - stride; opj_flag_t *sp = flagsp + stride; @@ -361,7 +363,7 @@ void opj_t1_updateflags(opj_flag_t *flagsp, OPJ_UINT32 s, OPJ_UINT32 stride) { sp[1] |= T1_SIG_NW; } -void opj_t1_enc_sigpass_step( opj_t1_t *t1, +static void opj_t1_enc_sigpass_step( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, OPJ_UINT32 orient, @@ -388,7 +390,7 @@ void opj_t1_enc_sigpass_step( opj_t1_t *t1, } if (v) { v = *datap < 0 ? 1 : 0; - *nmsedec += opj_t1_getnmsedec_sig((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno + T1_NMSEDEC_FRACBITS)); + *nmsedec += opj_t1_getnmsedec_sig((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno)); opj_mqc_setcurctx(mqc, opj_t1_getctxno_sc(flag)); /* ESSAI */ if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ opj_mqc_bypass_enc(mqc, (OPJ_UINT32)v); @@ -425,7 +427,7 @@ static INLINE void opj_t1_dec_sigpass_step_raw( } } -INLINE void opj_t1_dec_sigpass_step_mqc( +static INLINE void opj_t1_dec_sigpass_step_mqc( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -449,7 +451,7 @@ INLINE void opj_t1_dec_sigpass_step_mqc( } } /* VSC and BYPASS by Antonin */ -INLINE void opj_t1_dec_sigpass_step_mqc_vsc( +static INLINE void opj_t1_dec_sigpass_step_mqc_vsc( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -476,7 +478,7 @@ INLINE void opj_t1_dec_sigpass_step_mqc_vsc( -void opj_t1_enc_sigpass(opj_t1_t *t1, +static void opj_t1_enc_sigpass(opj_t1_t *t1, OPJ_INT32 bpno, OPJ_UINT32 orient, OPJ_INT32 *nmsedec, @@ -496,7 +498,7 @@ void opj_t1_enc_sigpass(opj_t1_t *t1, opj_t1_enc_sigpass_step( t1, &t1->flags[((j+1) * t1->flags_stride) + i + 1], - &t1->data[(j * t1->w) + i], + &t1->data[(j * t1->data_stride) + i], orient, bpno, one, @@ -508,7 +510,7 @@ void opj_t1_enc_sigpass(opj_t1_t *t1, } } -void opj_t1_dec_sigpass_raw( +static void opj_t1_dec_sigpass_raw( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_INT32 orient, @@ -535,7 +537,7 @@ void opj_t1_dec_sigpass_raw( } } /* VSC and BYPASS by Antonin */ -void opj_t1_dec_sigpass_mqc( +static void opj_t1_dec_sigpass_mqc( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_INT32 orient) @@ -578,7 +580,7 @@ void opj_t1_dec_sigpass_mqc( } } /* VSC and BYPASS by Antonin */ -void opj_t1_dec_sigpass_mqc_vsc( +static void opj_t1_dec_sigpass_mqc_vsc( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_INT32 orient) @@ -606,7 +608,7 @@ void opj_t1_dec_sigpass_mqc_vsc( -void opj_t1_enc_refpass_step( opj_t1_t *t1, +static void opj_t1_enc_refpass_step( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, OPJ_INT32 bpno, @@ -622,7 +624,7 @@ void opj_t1_enc_refpass_step( opj_t1_t *t1, flag = vsc ? (OPJ_UINT32)((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (OPJ_UINT32)(*flagsp); if ((flag & (T1_SIG | T1_VISIT)) == T1_SIG) { - *nmsedec += opj_t1_getnmsedec_ref((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno + T1_NMSEDEC_FRACBITS)); + *nmsedec += opj_t1_getnmsedec_ref((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno)); v = opj_int_abs(*datap) & one ? 1 : 0; opj_mqc_setcurctx(mqc, opj_t1_getctxno_mag(flag)); /* ESSAI */ if (type == T1_TYPE_RAW) { /* BYPASS/LAZY MODE */ @@ -634,7 +636,7 @@ void opj_t1_enc_refpass_step( opj_t1_t *t1, } } -INLINE void opj_t1_dec_refpass_step_raw( +static INLINE void opj_t1_dec_refpass_step_raw( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -655,7 +657,7 @@ INLINE void opj_t1_dec_refpass_step_raw( } } /* VSC and BYPASS by Antonin */ -INLINE void opj_t1_dec_refpass_step_mqc( +static INLINE void opj_t1_dec_refpass_step_mqc( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -676,7 +678,7 @@ INLINE void opj_t1_dec_refpass_step_mqc( } } /* VSC and BYPASS by Antonin */ -INLINE void opj_t1_dec_refpass_step_mqc_vsc( +static INLINE void opj_t1_dec_refpass_step_mqc_vsc( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -699,7 +701,7 @@ INLINE void opj_t1_dec_refpass_step_mqc_vsc( } /* VSC and BYPASS by Antonin */ -void opj_t1_enc_refpass( +static void opj_t1_enc_refpass( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_INT32 *nmsedec, @@ -718,7 +720,7 @@ void opj_t1_enc_refpass( opj_t1_enc_refpass_step( t1, &t1->flags[((j+1) * t1->flags_stride) + i + 1], - &t1->data[(j * t1->w) + i], + &t1->data[(j * t1->data_stride) + i], bpno, one, nmsedec, @@ -729,7 +731,7 @@ void opj_t1_enc_refpass( } } -void opj_t1_dec_refpass_raw( +static void opj_t1_dec_refpass_raw( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_INT32 cblksty) @@ -756,7 +758,7 @@ void opj_t1_dec_refpass_raw( } } /* VSC and BYPASS by Antonin */ -void opj_t1_dec_refpass_mqc( +static void opj_t1_dec_refpass_mqc( opj_t1_t *t1, OPJ_INT32 bpno) { @@ -798,7 +800,7 @@ void opj_t1_dec_refpass_mqc( } } /* VSC and BYPASS by Antonin */ -void opj_t1_dec_refpass_mqc_vsc( +static void opj_t1_dec_refpass_mqc_vsc( opj_t1_t *t1, OPJ_INT32 bpno) { @@ -825,7 +827,7 @@ void opj_t1_dec_refpass_mqc_vsc( } /* VSC and BYPASS by Antonin */ -void opj_t1_enc_clnpass_step( +static void opj_t1_enc_clnpass_step( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, @@ -851,7 +853,7 @@ void opj_t1_enc_clnpass_step( opj_mqc_encode(mqc, (OPJ_UINT32)v); if (v) { LABEL_PARTIAL: - *nmsedec += opj_t1_getnmsedec_sig((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno + T1_NMSEDEC_FRACBITS)); + *nmsedec += opj_t1_getnmsedec_sig((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)(bpno)); opj_mqc_setcurctx(mqc, opj_t1_getctxno_sc(flag)); v = *datap < 0 ? 1 : 0; opj_mqc_encode(mqc, (OPJ_UINT32)(v ^ opj_t1_getspb((OPJ_UINT32)flag))); @@ -935,7 +937,7 @@ LABEL_PARTIAL: *flagsp &= ~T1_VISIT; } -void opj_t1_enc_clnpass( +static void opj_t1_enc_clnpass( opj_t1_t *t1, OPJ_INT32 bpno, OPJ_UINT32 orient, @@ -960,17 +962,17 @@ void opj_t1_enc_clnpass( || (MACRO_t1_flags(1 + k + 3,1 + i) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); } else { - agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + agg = !((MACRO_t1_flags(1 + k,1 + i) | + MACRO_t1_flags(1 + k + 1,1 + i) | + MACRO_t1_flags(1 + k + 2,1 + i) | + MACRO_t1_flags(1 + k + 3,1 + i)) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); } } else { agg = 0; } if (agg) { for (runlen = 0; runlen < 4; ++runlen) { - if (opj_int_abs(t1->data[((k + runlen)*t1->w) + i]) & one) + if (opj_int_abs(t1->data[((k + runlen)*t1->data_stride) + i]) & one) break; } opj_mqc_setcurctx(mqc, T1_CTXNO_AGG); @@ -989,7 +991,7 @@ void opj_t1_enc_clnpass( opj_t1_enc_clnpass_step( t1, &t1->flags[((j+1) * t1->flags_stride) + i + 1], - &t1->data[(j * t1->w) + i], + &t1->data[(j * t1->data_stride) + i], orient, bpno, one, @@ -1059,10 +1061,10 @@ static void opj_t1_dec_clnpass( for (i = 0; i < t1->w; ++i) { OPJ_INT32 *data2 = data1 + i; opj_flag_t *flags2 = flags1 + i; - agg = !(MACRO_t1_flags(1 + k,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 1,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 2,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH) - || MACRO_t1_flags(1 + k + 3,1 + i) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); + agg = !((MACRO_t1_flags(1 + k, 1 + i) | + MACRO_t1_flags(1 + k + 1, 1 + i) | + MACRO_t1_flags(1 + k + 2, 1 + i) | + MACRO_t1_flags(1 + k + 3, 1 + i)) & (T1_SIG | T1_VISIT | T1_SIG_OTH)); if (agg) { opj_mqc_setcurctx(mqc, T1_CTXNO_AGG); if (!opj_mqc_decode(mqc)) { @@ -1073,9 +1075,9 @@ static void opj_t1_dec_clnpass( runlen = (runlen << 1) | opj_mqc_decode(mqc); flags2 += (OPJ_UINT32)runlen * t1->flags_stride; data2 += (OPJ_UINT32)runlen * t1->w; - for (j = k + (OPJ_UINT32)runlen; j < k + 4 && j < t1->h; ++j) { + for (j = (OPJ_UINT32)runlen; j < 4 && j < t1->h; ++j) { flags2 += t1->flags_stride; - if (agg && (j == k + (OPJ_UINT32)runlen)) { + if (agg && (j == (OPJ_UINT32)runlen)) { opj_t1_dec_clnpass_step_partial(t1, flags2, data2, orient, oneplushalf); } else { opj_t1_dec_clnpass_step(t1, flags2, data2, orient, oneplushalf); @@ -1137,12 +1139,13 @@ static OPJ_FLOAT64 opj_t1_getwmsedec( OPJ_UINT32 qmfbid, OPJ_FLOAT64 stepsize, OPJ_UINT32 numcomps, - const OPJ_FLOAT64 * mct_norms) + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps) { OPJ_FLOAT64 w1 = 1, w2, wmsedec; - OPJ_ARG_NOT_USED(numcomps); + OPJ_ARG_NOT_USED(numcomps); - if (mct_norms) { + if (mct_norms && (compno < mct_numcomps)) { w1 = mct_norms[compno]; } @@ -1158,7 +1161,7 @@ static OPJ_FLOAT64 opj_t1_getwmsedec( return wmsedec; } -OPJ_BOOL opj_t1_allocate_buffers( +static OPJ_BOOL opj_t1_allocate_buffers( opj_t1_t *t1, OPJ_UINT32 w, OPJ_UINT32 h) @@ -1166,16 +1169,19 @@ OPJ_BOOL opj_t1_allocate_buffers( OPJ_UINT32 datasize=w * h; OPJ_UINT32 flagssize; - if(datasize > t1->datasize){ - opj_aligned_free(t1->data); - t1->data = (OPJ_INT32*) opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); - if(!t1->data){ - return OPJ_FALSE; + /* encoder uses tile buffer, so no need to allocate */ + if (!t1->encoder) { + if(datasize > t1->datasize){ + opj_aligned_free(t1->data); + t1->data = (OPJ_INT32*) opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); + if(!t1->data){ + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + t1->datasize=datasize; } - t1->datasize=datasize; + memset(t1->data,0,datasize * sizeof(OPJ_INT32)); } - memset(t1->data,0,datasize * sizeof(OPJ_INT32)); - t1->flags_stride=w+2; flagssize=t1->flags_stride * (h+2); @@ -1183,6 +1189,7 @@ OPJ_BOOL opj_t1_allocate_buffers( opj_aligned_free(t1->flags); t1->flags = (opj_flag_t*) opj_aligned_malloc(flagssize * sizeof(opj_flag_t)); if(!t1->flags){ + /* FIXME event manager error callback */ return OPJ_FALSE; } t1->flagssize=flagssize; @@ -1203,15 +1210,14 @@ OPJ_BOOL opj_t1_allocate_buffers( * and initializes the look-up tables of the Tier-1 coder/decoder * @return a new T1 handle if successful, returns NULL otherwise */ -opj_t1_t* opj_t1_create() +opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder) { opj_t1_t *l_t1 = 00; - l_t1 = (opj_t1_t*) opj_malloc(sizeof(opj_t1_t)); + l_t1 = (opj_t1_t*) opj_calloc(1,sizeof(opj_t1_t)); if (!l_t1) { return 00; } - memset(l_t1,0,sizeof(opj_t1_t)); /* create MQC and RAW handles */ l_t1->mqc = opj_mqc_create(); @@ -1225,6 +1231,7 @@ opj_t1_t* opj_t1_create() opj_t1_destroy(l_t1); return 00; } + l_t1->encoder = isEncoder; return l_t1; } @@ -1247,7 +1254,8 @@ void opj_t1_destroy(opj_t1_t *p_t1) opj_raw_destroy(p_t1->raw); p_t1->raw = 00; - if (p_t1->data) { + /* encoder uses tile buffer, so no need to free */ + if (!p_t1->encoder && p_t1->data) { opj_aligned_free(p_t1->data); p_t1->data = 00; } @@ -1280,7 +1288,6 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; OPJ_INT32* restrict datap; - /*void* restrict tiledp;*/ OPJ_UINT32 cblk_w, cblk_h; OPJ_INT32 x, y; OPJ_UINT32 i, j; @@ -1322,14 +1329,12 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, } } } - - /*tiledp=(void*)&tilec->data[(y * tile_w) + x];*/ if (tccp->qmfbid == 1) { OPJ_INT32* restrict tiledp = &tilec->data[(OPJ_UINT32)y * tile_w + (OPJ_UINT32)x]; for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { OPJ_INT32 tmp = datap[(j * cblk_w) + i]; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i] = tmp / 2; + ((OPJ_INT32*)tiledp)[(j * tile_w) + i] = tmp/2; } } } else { /* if (tccp->qmfbid == 0) */ @@ -1341,18 +1346,11 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, *tiledp2 = tmp; datap++; tiledp2++; - /*float tmp = datap[(j * cblk_w) + i] * band->stepsize; - ((float*)tiledp)[(j * tile_w) + i] = tmp;*/ - } tiledp += tile_w; } } - /*opj_free(cblk->data); - opj_free(cblk->segs);*/ - /*cblk->segs = 00;*/ } /* cblkno */ - /*opj_free(precinct->cblks.dec);*/ } /* precno */ } /* bandno */ } /* resno */ @@ -1360,7 +1358,7 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, } -OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, +static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 orient, OPJ_UINT32 roishift, @@ -1369,7 +1367,7 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opj_raw_t *raw = t1->raw; /* RAW component */ opj_mqc_t *mqc = t1->mqc; /* MQC component */ - OPJ_INT32 bpno; + OPJ_INT32 bpno_plus_one; OPJ_UINT32 passtype; OPJ_UINT32 segno, passno; OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ @@ -1382,7 +1380,7 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, return OPJ_FALSE; } - bpno = (OPJ_INT32)(roishift + cblk->numbps - 1); + bpno_plus_one = (OPJ_INT32)(roishift + cblk->numbps); passtype = 2; opj_mqc_resetstates(mqc); @@ -1394,7 +1392,7 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, opj_tcd_seg_t *seg = &cblk->segs[segno]; /* BYPASS mode */ - type = ((bpno <= ((OPJ_INT32) (cblk->numbps) - 1) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; + type = ((bpno_plus_one <= ((OPJ_INT32) (cblk->numbps)) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ; /* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */ if(seg->data == 00){ continue; @@ -1411,28 +1409,28 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, switch (passtype) { case 0: if (type == T1_TYPE_RAW) { - opj_t1_dec_sigpass_raw(t1, bpno+1, (OPJ_INT32)orient, (OPJ_INT32)cblksty); + opj_t1_dec_sigpass_raw(t1, bpno_plus_one, (OPJ_INT32)orient, (OPJ_INT32)cblksty); } else { if (cblksty & J2K_CCP_CBLKSTY_VSC) { - opj_t1_dec_sigpass_mqc_vsc(t1, bpno+1, (OPJ_INT32)orient); + opj_t1_dec_sigpass_mqc_vsc(t1, bpno_plus_one, (OPJ_INT32)orient); } else { - opj_t1_dec_sigpass_mqc(t1, bpno+1, (OPJ_INT32)orient); + opj_t1_dec_sigpass_mqc(t1, bpno_plus_one, (OPJ_INT32)orient); } } break; case 1: if (type == T1_TYPE_RAW) { - opj_t1_dec_refpass_raw(t1, bpno+1, (OPJ_INT32)cblksty); + opj_t1_dec_refpass_raw(t1, bpno_plus_one, (OPJ_INT32)cblksty); } else { if (cblksty & J2K_CCP_CBLKSTY_VSC) { - opj_t1_dec_refpass_mqc_vsc(t1, bpno+1); + opj_t1_dec_refpass_mqc_vsc(t1, bpno_plus_one); } else { - opj_t1_dec_refpass_mqc(t1, bpno+1); + opj_t1_dec_refpass_mqc(t1, bpno_plus_one); } } break; case 2: - opj_t1_dec_clnpass(t1, bpno+1, (OPJ_INT32)orient, (OPJ_INT32)cblksty); + opj_t1_dec_clnpass(t1, bpno_plus_one, (OPJ_INT32)orient, (OPJ_INT32)cblksty); break; } @@ -1444,11 +1442,11 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, } if (++passtype == 3) { passtype = 0; - bpno--; + bpno_plus_one--; } } } - return OPJ_TRUE; + return OPJ_TRUE; } @@ -1457,7 +1455,8 @@ OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp, - const OPJ_FLOAT64 * mct_norms + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps ) { OPJ_UINT32 compno, resno, bandno, precno, cblkno; @@ -1481,11 +1480,10 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; - OPJ_INT32 * restrict datap; OPJ_INT32* restrict tiledp; OPJ_UINT32 cblk_w; OPJ_UINT32 cblk_h; - OPJ_UINT32 i, j; + OPJ_UINT32 i, j, tileIndex=0, tileLineAdvance; OPJ_INT32 x = cblk->x0 - band->x0; OPJ_INT32 y = cblk->y0 - band->y0; @@ -1506,27 +1504,32 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, return OPJ_FALSE; } - datap=t1->data; cblk_w = t1->w; cblk_h = t1->h; + tileLineAdvance = tile_w - cblk_w; tiledp=&tilec->data[(OPJ_UINT32)y * tile_w + (OPJ_UINT32)x]; + t1->data = tiledp; + t1->data_stride = tile_w; if (tccp->qmfbid == 1) { for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; - datap[(j * cblk_w) + i] = tmp << T1_NMSEDEC_FRACBITS; + tiledp[tileIndex] <<= T1_NMSEDEC_FRACBITS; + tileIndex++; } + tileIndex += tileLineAdvance; } } else { /* if (tccp->qmfbid == 0) */ for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { - OPJ_INT32 tmp = tiledp[(j * tile_w) + i]; - datap[(j * cblk_w) + i] = - opj_int_fix_mul( + OPJ_INT32 tmp = tiledp[tileIndex]; + tiledp[tileIndex] = + opj_int_fix_mul_t1( tmp, - bandconst) >> (11 - T1_NMSEDEC_FRACBITS); + bandconst); + tileIndex++; } + tileIndex += tileLineAdvance; } } @@ -1541,7 +1544,8 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, tccp->cblksty, tile->numcomps, tile, - mct_norms); + mct_norms, + mct_numcomps); } /* cblkno */ } /* precno */ @@ -1552,7 +1556,7 @@ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, } /** mod fixed_quality */ -void opj_t1_encode_cblk(opj_t1_t *t1, +static void opj_t1_encode_cblk(opj_t1_t *t1, opj_tcd_cblk_enc_t* cblk, OPJ_UINT32 orient, OPJ_UINT32 compno, @@ -1562,7 +1566,8 @@ void opj_t1_encode_cblk(opj_t1_t *t1, OPJ_UINT32 cblksty, OPJ_UINT32 numcomps, opj_tcd_tile_t * tile, - const OPJ_FLOAT64 * mct_norms) + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps) { OPJ_FLOAT64 cumwmsedec = 0.0; @@ -1573,14 +1578,16 @@ void opj_t1_encode_cblk(opj_t1_t *t1, OPJ_UINT32 passtype; OPJ_INT32 nmsedec = 0; OPJ_INT32 max; - OPJ_UINT32 i; + OPJ_UINT32 i, j; OPJ_BYTE type = T1_TYPE_MQ; OPJ_FLOAT64 tempwmsedec; max = 0; - for (i = 0; i < t1->w * t1->h; ++i) { - OPJ_INT32 tmp = abs(t1->data[i]); - max = opj_int_max(max, tmp); + for (i = 0; i < t1->w; ++i) { + for (j = 0; j < t1->h; ++j) { + OPJ_INT32 tmp = abs(t1->data[i + j*t1->data_stride]); + max = opj_int_max(max, tmp); + } } cblk->numbps = max ? (OPJ_UINT32)((opj_int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS) : 0; @@ -1615,7 +1622,7 @@ void opj_t1_encode_cblk(opj_t1_t *t1, } /* fixed_quality */ - tempwmsedec = opj_t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms) ; + tempwmsedec = opj_t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid, stepsize, numcomps,mct_norms, mct_numcomps) ; cumwmsedec += tempwmsedec; tile->distotile += tempwmsedec; @@ -1689,7 +1696,7 @@ void opj_t1_encode_cblk(opj_t1_t *t1, } #if 0 -void opj_t1_dec_refpass_step( opj_t1_t *t1, +static void opj_t1_dec_refpass_step( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, OPJ_INT32 poshalf, @@ -1721,7 +1728,7 @@ void opj_t1_dec_refpass_step( opj_t1_t *t1, #if 0 -void opj_t1_dec_sigpass_step( opj_t1_t *t1, +static void opj_t1_dec_sigpass_step( opj_t1_t *t1, opj_flag_t *flagsp, OPJ_INT32 *datap, OPJ_UINT32 orient, diff --git a/src/lib/openjp2/t1.h b/src/lib/openjp2/t1.h index e5be70ed..3bc0ad9e 100644 --- a/src/lib/openjp2/t1.h +++ b/src/lib/openjp2/t1.h @@ -103,13 +103,15 @@ typedef struct opj_t1 { /** RAW component */ opj_raw_t *raw; - OPJ_INT32 *data; + OPJ_INT32 *data; opj_flag_t *flags; OPJ_UINT32 w; OPJ_UINT32 h; OPJ_UINT32 datasize; OPJ_UINT32 flagssize; OPJ_UINT32 flags_stride; + OPJ_UINT32 data_stride; + OPJ_BOOL encoder; } opj_t1_t; #define MACRO_t1_flags(x,y) t1->flags[((x)*(t1->flags_stride))+(y)] @@ -124,11 +126,13 @@ Encode the code-blocks of a tile @param tile The tile to encode @param tcp Tile coding parameters @param mct_norms FIXME DOC +@param mct_numcomps Number of components used for MCT */ OPJ_BOOL opj_t1_encode_cblks( opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp, - const OPJ_FLOAT64 * mct_norms); + const OPJ_FLOAT64 * mct_norms, + OPJ_UINT32 mct_numcomps); /** Decode the code-blocks of a tile @@ -147,7 +151,7 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1, * and initializes the look-up tables of the Tier-1 coder/decoder * @return a new T1 handle if successful, returns NULL otherwise */ -opj_t1_t* opj_t1_create(void); +opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder); /** * Destroys a previously created T1 handle diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 37f98149..ebc26b2d 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -97,7 +97,8 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* t2, OPJ_BYTE *src, OPJ_UINT32 * data_read, OPJ_UINT32 max_length, - opj_packet_info_t *pack_info); + opj_packet_info_t *pack_info, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, @@ -106,7 +107,8 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, OPJ_BYTE *p_src, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *p_pack_info); + opj_packet_info_t *p_pack_info, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, @@ -116,7 +118,8 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, OPJ_BYTE *p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *p_pack_info); + opj_packet_info_t *p_pack_info, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, @@ -124,14 +127,16 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, OPJ_BYTE *p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *pack_info); + opj_packet_info_t *pack_info, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_pi_iterator_t *p_pi, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *pack_info); + opj_packet_info_t *pack_info, + opj_event_mgr_t *p_manager); /** @param cblk @@ -158,7 +163,7 @@ static void opj_t2_putcommacode(opj_bio_t *bio, OPJ_INT32 n) { opj_bio_write(bio, 0, 1); } -OPJ_UINT32 opj_t2_getcommacode(opj_bio_t *bio) +static OPJ_UINT32 opj_t2_getcommacode(opj_bio_t *bio) { OPJ_UINT32 n = 0; while (opj_bio_read(bio, 1)) { @@ -167,7 +172,7 @@ OPJ_UINT32 opj_t2_getcommacode(opj_bio_t *bio) return n; } -void opj_t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n) { +static void opj_t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n) { if (n == 1) { opj_bio_write(bio, 0, 1); } else if (n == 2) { @@ -181,7 +186,7 @@ void opj_t2_putnumpasses(opj_bio_t *bio, OPJ_UINT32 n) { } } -OPJ_UINT32 opj_t2_getnumpasses(opj_bio_t *bio) { +static OPJ_UINT32 opj_t2_getnumpasses(opj_bio_t *bio) { OPJ_UINT32 n; if (!opj_bio_read(bio, 1)) return 1; @@ -242,6 +247,11 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* p_t2, /* TODO MSD : check why this function cannot fail (cf. v1) */ opj_pi_create_encode(l_pi, l_cp,p_tile_no,poc,l_tp_num,p_tp_pos,p_t2_mode); + if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { + /* TODO ADE : add an error */ + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } while (opj_pi_next(l_current_pi)) { if (l_current_pi->layno < p_maxlayers) { l_nb_bytes = 0; @@ -274,7 +284,11 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* p_t2, opj_pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos,p_t2_mode); l_current_pi = &l_pi[p_pino]; - + if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { + /* TODO ADE : add an error */ + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } while (opj_pi_next(l_current_pi)) { if (l_current_pi->layno < p_maxlayers) { l_nb_bytes=0; @@ -336,7 +350,8 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, OPJ_BYTE *p_src, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_len, - opj_codestream_index_t *p_cstr_index) + opj_codestream_index_t *p_cstr_index, + opj_event_mgr_t *p_manager) { OPJ_BYTE *l_current_data = p_src; opj_pi_iterator_t *l_pi = 00; @@ -378,7 +393,15 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, * l_current_pi->resno is always >= p_tile->comps[l_current_pi->compno].minimum_num_resolutions * and no l_img_comp->resno_decoded are computed */ - OPJ_BOOL* first_pass_failed = (OPJ_BOOL*)opj_malloc(l_image->numcomps * sizeof(OPJ_BOOL)); + OPJ_BOOL* first_pass_failed = NULL; + + if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) { + /* TODO ADE : add an error */ + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + + first_pass_failed = (OPJ_BOOL*)opj_malloc(l_image->numcomps * sizeof(OPJ_BOOL)); if (!first_pass_failed) { opj_pi_destroy(l_pi,l_nb_pocs); @@ -396,7 +419,7 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, first_pass_failed[l_current_pi->compno] = OPJ_FALSE; - if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) { + if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) { opj_pi_destroy(l_pi,l_nb_pocs); opj_free(first_pass_failed); return OPJ_FALSE; @@ -407,7 +430,7 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, } else { l_nb_bytes_read = 0; - if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info)) { + if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) { opj_pi_destroy(l_pi,l_nb_pocs); opj_free(first_pass_failed); return OPJ_FALSE; @@ -477,11 +500,10 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2, opj_t2_t* opj_t2_create(opj_image_t *p_image, opj_cp_t *p_cp) { /* create the t2 structure */ - opj_t2_t *l_t2 = (opj_t2_t*)opj_malloc(sizeof(opj_t2_t)); + opj_t2_t *l_t2 = (opj_t2_t*)opj_calloc(1,sizeof(opj_t2_t)); if (!l_t2) { return NULL; } - memset(l_t2,0,sizeof(opj_t2_t)); l_t2->image = p_image; l_t2->cp = p_cp; @@ -495,14 +517,15 @@ void opj_t2_destroy(opj_t2_t *t2) { } } -OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, +static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, OPJ_BYTE *p_src, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *p_pack_info) + opj_packet_info_t *p_pack_info, + opj_event_mgr_t *p_manager) { OPJ_BOOL l_read_data; OPJ_UINT32 l_nb_bytes_read = 0; @@ -510,7 +533,7 @@ OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, *p_data_read = 0; - if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) { + if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { return OPJ_FALSE; } @@ -522,7 +545,7 @@ OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, if (l_read_data) { l_nb_bytes_read = 0; - if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) { + if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { return OPJ_FALSE; } @@ -534,7 +557,7 @@ OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2, return OPJ_TRUE; } -OPJ_BOOL opj_t2_encode_packet( OPJ_UINT32 tileno, +static OPJ_BOOL opj_t2_encode_packet( OPJ_UINT32 tileno, opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_iterator_t *pi, @@ -599,6 +622,10 @@ OPJ_BOOL opj_t2_encode_packet( OPJ_UINT32 tileno, } bio = opj_bio_create(); + if (!bio) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } opj_bio_init_enc(bio, c, length); opj_bio_write(bio, 1, 1); /* Empty header bit */ @@ -773,7 +800,8 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, OPJ_BYTE *p_src, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *p_pack_info) + opj_packet_info_t *p_pack_info, + opj_event_mgr_t *p_manager) { OPJ_BOOL l_read_data; OPJ_UINT32 l_nb_bytes_read = 0; @@ -781,7 +809,7 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, *p_data_read = 0; - if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info)) { + if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { return OPJ_FALSE; } @@ -793,7 +821,7 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, if (l_read_data) { l_nb_bytes_read = 0; - if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info)) { + if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) { return OPJ_FALSE; } @@ -805,7 +833,7 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2, } -OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, +static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_tcp_t *p_tcp, opj_pi_iterator_t *p_pi, @@ -813,7 +841,8 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, OPJ_BYTE *p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *p_pack_info) + opj_packet_info_t *p_pack_info, + opj_event_mgr_t *p_manager) { /* loop */ @@ -862,12 +891,9 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, if (p_tcp->csty & J2K_CP_CSTY_SOP) { if (p_max_length < 6) { - /* TODO opj_event_msg(p_t2->cinfo->event_mgr, EVT_WARNING, "Not enough space for expected SOP marker\n"); */ - printf("Not enough space for expected SOP marker\n"); + opj_event_msg(p_manager, EVT_WARNING, "Not enough space for expected SOP marker\n"); } else if ((*l_current_data) != 0xff || (*(l_current_data + 1) != 0x91)) { - /* TODO opj_event_msg(p_t2->cinfo->event_mgr, EVT_WARNING, "Expected SOP marker\n"); */ - printf("Expected SOP marker\n"); - fprintf(stderr, "Error : expected SOP marker\n"); + opj_event_msg(p_manager, EVT_WARNING, "Expected SOP marker\n"); } else { l_current_data += 6; } @@ -917,10 +943,10 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, /* EPH markers */ if (p_tcp->csty & J2K_CP_CSTY_EPH) { - if (p_max_length < 2) { - fprintf(stderr, "Not enough space for expected EPH marker\n"); + if ((*l_modified_length_ptr - (OPJ_UINT32)(l_header_data - *l_header_data_start)) < 2U) { + opj_event_msg(p_manager, EVT_WARNING, "Not enough space for expected EPH marker\n"); } else if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { - fprintf(stderr, "Error : expected EPH marker\n"); + opj_event_msg(p_manager, EVT_WARNING, "Expected EPH marker\n"); } else { l_header_data += 2; } @@ -971,7 +997,7 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, if (!l_included) { l_cblk->numnewpasses = 0; ++l_cblk; - JAS_FPRINTF(stderr, "included=%d \n", l_included); + JAS_FPRINTF(stderr, "included=%d \n", l_included); continue; } @@ -1045,11 +1071,10 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, /* EPH markers */ if (p_tcp->csty & J2K_CP_CSTY_EPH) { - if (p_max_length < 2) { - fprintf(stderr, "Not enough space for expected EPH marker\n"); + if ((*l_modified_length_ptr - (OPJ_UINT32)(l_header_data - *l_header_data_start)) < 2U) { + opj_event_msg(p_manager, EVT_WARNING, "Not enough space for expected EPH marker\n"); } else if ((*l_header_data) != 0xff || (*(l_header_data + 1) != 0x92)) { - /* TODO opj_event_msg(t2->cinfo->event_mgr, EVT_ERROR, "Expected EPH marker\n"); */ - fprintf(stderr, "Error : expected EPH marker\n"); + opj_event_msg(p_manager, EVT_WARNING, "Expected EPH marker\n"); } else { l_header_data += 2; } @@ -1075,13 +1100,14 @@ OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2, return OPJ_TRUE; } -OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, +static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_pi_iterator_t *p_pi, OPJ_BYTE *p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *pack_info) + opj_packet_info_t *pack_info, + opj_event_mgr_t* p_manager) { OPJ_UINT32 bandno, cblkno; OPJ_UINT32 l_nb_code_blocks; @@ -1129,9 +1155,10 @@ OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, } do { - if (l_current_data + l_seg->newlen > p_src_data + p_max_length) { - fprintf(stderr, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); + /* Check possible overflow (on l_current_data only, assumes input args already checked) then size */ + if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || (l_current_data + l_seg->newlen > p_src_data + p_max_length)) { + opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); return OPJ_FALSE; } @@ -1141,24 +1168,31 @@ OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, /* let's check that we are not exceeding */ if ((l_cblk->len + l_seg->newlen) > 8192) { - opj_event_msg(p_t2->cinfo, EVT_WARNING, + opj_event_msg(p_manager, EVT_WARNING, "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); if (!JPWL_ASSUME) { - opj_event_msg(p_t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_manager, EVT_ERROR, "JPWL: giving up\n"); return OPJ_FALSE; } l_seg->newlen = 8192 - l_cblk->len; - opj_event_msg(p_t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", l_seg->newlen); + opj_event_msg(p_manager, EVT_WARNING, " - truncating segment to %d\n", l_seg->newlen); break; }; #endif /* USE_JPWL */ + /* Check possible overflow on size */ + if ((l_cblk->data_current_size + l_seg->newlen) < l_cblk->data_current_size) { + opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with current size (%d > %d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, l_cblk->data_current_size, 0xFFFFFFFF - l_seg->newlen, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); + return OPJ_FALSE; + } /* Check if the cblk->data have allocated enough memory */ if ((l_cblk->data_current_size + l_seg->newlen) > l_cblk->data_max_size) { OPJ_BYTE* new_cblk_data = (OPJ_BYTE*) opj_realloc(l_cblk->data, l_cblk->data_current_size + l_seg->newlen); if(! new_cblk_data) { opj_free(l_cblk->data); + l_cblk->data = NULL; l_cblk->data_max_size = 0; /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to realloc code block cata!\n"); */ return OPJ_FALSE; @@ -1197,15 +1231,17 @@ OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2, *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); + return OPJ_TRUE; } -OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2, +static OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2, opj_tcd_tile_t *p_tile, opj_pi_iterator_t *p_pi, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_length, - opj_packet_info_t *pack_info) + opj_packet_info_t *pack_info, + opj_event_mgr_t *p_manager) { OPJ_UINT32 bandno, cblkno; OPJ_UINT32 l_nb_code_blocks; @@ -1254,8 +1290,9 @@ OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2, } do { - if (* p_data_read + l_seg->newlen > p_max_length) { - fprintf(stderr, "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + /* Check possible overflow then size */ + if (((*p_data_read + l_seg->newlen) < (*p_data_read)) || ((*p_data_read + l_seg->newlen) > p_max_length)) { + opj_event_msg(p_manager, EVT_ERROR, "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); return OPJ_FALSE; } @@ -1266,15 +1303,15 @@ OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2, /* let's check that we are not exceeding */ if ((l_cblk->len + l_seg->newlen) > 8192) { - opj_event_msg(p_t2->cinfo, EVT_WARNING, + opj_event_msg(p_manager, EVT_WARNING, "JPWL: segment too long (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", l_seg->newlen, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno); if (!JPWL_ASSUME) { - opj_event_msg(p_t2->cinfo, EVT_ERROR, "JPWL: giving up\n"); + opj_event_msg(p_manager, EVT_ERROR, "JPWL: giving up\n"); return -999; } l_seg->newlen = 8192 - l_cblk->len; - opj_event_msg(p_t2->cinfo, EVT_WARNING, " - truncating segment to %d\n", l_seg->newlen); + opj_event_msg(p_manager, EVT_WARNING, " - truncating segment to %d\n", l_seg->newlen); break; }; @@ -1301,7 +1338,7 @@ OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2, } -OPJ_BOOL opj_t2_init_seg( opj_tcd_cblk_dec_t* cblk, +static OPJ_BOOL opj_t2_init_seg( opj_tcd_cblk_dec_t* cblk, OPJ_UINT32 index, OPJ_UINT32 cblksty, OPJ_UINT32 first) diff --git a/src/lib/openjp2/t2.h b/src/lib/openjp2/t2.h index 931141e0..3b652eea 100644 --- a/src/lib/openjp2/t2.h +++ b/src/lib/openjp2/t2.h @@ -108,7 +108,8 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *t2, OPJ_BYTE *src, OPJ_UINT32 * p_data_read, OPJ_UINT32 len, - opj_codestream_index_t *cstr_info); + opj_codestream_index_t *cstr_info, + opj_event_mgr_t *p_manager); /** * Creates a Tier 2 handle diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c index 79262fcd..6eeb211e 100644 --- a/src/lib/openjp2/tcd.c +++ b/src/lib/openjp2/tcd.c @@ -103,6 +103,12 @@ void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) { fprintf(fd, "}\n"); } #endif + +/** + * Initializes tile coding/decoding + */ +static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BOOL isEncoder, OPJ_FLOAT32 fraction, OPJ_SIZE_T sizeof_block, opj_event_mgr_t* manager); + /** * Allocates memory for a decoding code block. */ @@ -114,10 +120,15 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_blo static void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct); /** - * Allocates memory for an encoding code block. + * Allocates memory for an encoding code block (but not data). */ static OPJ_BOOL opj_tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block); +/** + * Allocates data for an encoding code block + */ +static OPJ_BOOL opj_tcd_code_block_enc_allocate_data (opj_tcd_cblk_enc_t * p_code_block); + /** * Deallocates the encoding data of the given precinct. */ @@ -135,13 +146,14 @@ static OPJ_BOOL opj_tcd_t2_decode ( opj_tcd_t *p_tcd, OPJ_BYTE * p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_src_size, - opj_codestream_index_t *p_cstr_index ); + opj_codestream_index_t *p_cstr_index, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_tcd_t1_decode (opj_tcd_t *p_tcd); static OPJ_BOOL opj_tcd_dwt_decode (opj_tcd_t *p_tcd); -static OPJ_BOOL opj_tcd_mct_decode (opj_tcd_t *p_tcd); +static OPJ_BOOL opj_tcd_mct_decode (opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager); static OPJ_BOOL opj_tcd_dc_level_shift_decode (opj_tcd_t *p_tcd); @@ -175,20 +187,18 @@ opj_tcd_t* opj_tcd_create(OPJ_BOOL p_is_decoder) opj_tcd_t *l_tcd = 00; /* create the tcd structure */ - l_tcd = (opj_tcd_t*) opj_malloc(sizeof(opj_tcd_t)); + l_tcd = (opj_tcd_t*) opj_calloc(1,sizeof(opj_tcd_t)); if (!l_tcd) { return 00; } - memset(l_tcd,0,sizeof(opj_tcd_t)); l_tcd->m_is_decoder = p_is_decoder ? 1 : 0; - l_tcd->tcd_image = (opj_tcd_image_t*)opj_malloc(sizeof(opj_tcd_image_t)); + l_tcd->tcd_image = (opj_tcd_image_t*)opj_calloc(1,sizeof(opj_tcd_image_t)); if (!l_tcd->tcd_image) { opj_free(l_tcd); return 00; } - memset(l_tcd->tcd_image,0,sizeof(opj_tcd_image_t)); return l_tcd; } @@ -258,7 +268,7 @@ void opj_tcd_makelayer( opj_tcd_t *tcd, n = passno + 1; continue; } - if (dd / dr >= thresh) + if (thresh - (dd / dr) < DBL_EPSILON) /* do not rely on float equality, check with DBL_EPSILON margin */ n = passno + 1; } @@ -467,6 +477,10 @@ OPJ_BOOL opj_tcd_rateallocate( opj_tcd_t *tcd, tile_info->numpix = tcd_tile->numpix; tile_info->distotile = tcd_tile->distotile; tile_info->thresh = (OPJ_FLOAT64 *) opj_malloc(tcd_tcp->numlayers * sizeof(OPJ_FLOAT64)); + if (!tile_info->thresh) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } } for (layno = 0; layno < tcd_tcp->numlayers; layno++) { @@ -575,23 +589,18 @@ OPJ_BOOL opj_tcd_init( opj_tcd_t *p_tcd, opj_image_t * p_image, opj_cp_t * p_cp ) { - OPJ_UINT32 l_tile_comp_size; - p_tcd->image = p_image; p_tcd->cp = p_cp; - p_tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(sizeof(opj_tcd_tile_t)); + p_tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_calloc(1,sizeof(opj_tcd_tile_t)); if (! p_tcd->tcd_image->tiles) { return OPJ_FALSE; } - memset(p_tcd->tcd_image->tiles,0, sizeof(opj_tcd_tile_t)); - l_tile_comp_size = p_image->numcomps * (OPJ_UINT32)sizeof(opj_tcd_tilecomp_t); - p_tcd->tcd_image->tiles->comps = (opj_tcd_tilecomp_t *) opj_malloc(l_tile_comp_size); + p_tcd->tcd_image->tiles->comps = (opj_tcd_tilecomp_t *) opj_calloc(p_image->numcomps,sizeof(opj_tcd_tilecomp_t)); if (! p_tcd->tcd_image->tiles->comps ) { return OPJ_FALSE; } - memset( p_tcd->tcd_image->tiles->comps , 0 , l_tile_comp_size); p_tcd->tcd_image->tiles->numcomps = p_image->numcomps; p_tcd->tp_pos = p_cp->m_specific_param.m_enc.m_tp_pos; @@ -614,437 +623,478 @@ void opj_tcd_destroy(opj_tcd_t *tcd) { } } +OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec) +{ + if ((l_tilec->data == 00) || ((l_tilec->data_size_needed > l_tilec->data_size) && (l_tilec->ownsData == OPJ_FALSE))) { + l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_tilec->data_size_needed); + if (! l_tilec->data ) { + return OPJ_FALSE; + } + /*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/ + l_tilec->data_size = l_tilec->data_size_needed; + l_tilec->ownsData = OPJ_TRUE; + } + else if (l_tilec->data_size_needed > l_tilec->data_size) { + /* We don't need to keep old data */ + opj_aligned_free(l_tilec->data); + l_tilec->data = (OPJ_INT32 *) opj_aligned_malloc(l_tilec->data_size_needed); + if (! l_tilec->data ) { + l_tilec->data_size = 0; + l_tilec->data_size_needed = 0; + l_tilec->ownsData = OPJ_FALSE; + return OPJ_FALSE; + } + /*fprintf(stderr, "tReallocate data of tilec (int): from %d to %d x OPJ_UINT32n", l_tilec->data_size, l_data_size);*/ + l_tilec->data_size = l_tilec->data_size_needed; + l_tilec->ownsData = OPJ_TRUE; + } + return OPJ_TRUE; +} + /* ----------------------------------------------------------------------- */ -#define OPJ_MACRO_TCD_ALLOCATE(FUNCTION,TYPE,FRACTION,ELEMENT,FUNCTION_ELEMENT) \ -OPJ_BOOL FUNCTION ( opj_tcd_t *p_tcd, \ - OPJ_UINT32 p_tile_no \ - ) \ -{ \ - OPJ_UINT32 (*l_gain_ptr)(OPJ_UINT32) = 00; \ - OPJ_UINT32 compno, resno, bandno, precno, cblkno; \ - opj_tcp_t * l_tcp = 00; \ - opj_cp_t * l_cp = 00; \ - opj_tcd_tile_t * l_tile = 00; \ - opj_tccp_t *l_tccp = 00; \ - opj_tcd_tilecomp_t *l_tilec = 00; \ - opj_image_comp_t * l_image_comp = 00; \ - opj_tcd_resolution_t *l_res = 00; \ - opj_tcd_band_t *l_band = 00; \ - opj_stepsize_t * l_step_size = 00; \ - opj_tcd_precinct_t *l_current_precinct = 00; \ - TYPE* l_code_block = 00; \ - opj_image_t *l_image = 00; \ - OPJ_UINT32 p,q; \ - OPJ_UINT32 l_level_no; \ - OPJ_UINT32 l_pdx, l_pdy; \ - OPJ_UINT32 l_gain; \ - OPJ_INT32 l_x0b, l_y0b; \ - /* extent of precincts , top left, bottom right**/ \ - OPJ_INT32 l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end, l_br_prc_y_end; \ - /* number of precinct for a resolution */ \ - OPJ_UINT32 l_nb_precincts; \ - /* room needed to store l_nb_precinct precinct for a resolution */ \ - OPJ_UINT32 l_nb_precinct_size; \ - /* number of code blocks for a precinct*/ \ - OPJ_UINT32 l_nb_code_blocks; \ - /* room needed to store l_nb_code_blocks code blocks for a precinct*/ \ - OPJ_UINT32 l_nb_code_blocks_size; \ - /* size of data for a tile */ \ - OPJ_UINT32 l_data_size; \ - \ - l_cp = p_tcd->cp; \ - l_tcp = &(l_cp->tcps[p_tile_no]); \ - l_tile = p_tcd->tcd_image->tiles; \ - l_tccp = l_tcp->tccps; \ - l_tilec = l_tile->comps; \ - l_image = p_tcd->image; \ - l_image_comp = p_tcd->image->comps; \ - \ - p = p_tile_no % l_cp->tw; /* tile coordinates */ \ - q = p_tile_no / l_cp->tw; \ - /*fprintf(stderr, "Tile coordinate = %d,%d\n", p, q);*/ \ - \ - /* 4 borders of the tile rescale on the image if necessary */ \ - l_tile->x0 = opj_int_max((OPJ_INT32)(l_cp->tx0 + p * l_cp->tdx), (OPJ_INT32)l_image->x0); \ - l_tile->y0 = opj_int_max((OPJ_INT32)(l_cp->ty0 + q * l_cp->tdy), (OPJ_INT32)l_image->y0); \ - l_tile->x1 = opj_int_min((OPJ_INT32)(l_cp->tx0 + (p + 1) * l_cp->tdx), (OPJ_INT32)l_image->x1); \ - l_tile->y1 = opj_int_min((OPJ_INT32)(l_cp->ty0 + (q + 1) * l_cp->tdy), (OPJ_INT32)l_image->y1); \ - /* testcase 1888.pdf.asan.35.988 */ \ - if (l_tccp->numresolutions == 0) { \ - fprintf(stderr, "tiles require at least one resolution\n"); \ - return OPJ_FALSE; \ - } \ - /*fprintf(stderr, "Tile border = %d,%d,%d,%d\n", l_tile->x0, l_tile->y0,l_tile->x1,l_tile->y1);*/ \ - \ - /*tile->numcomps = image->numcomps; */ \ - for(compno = 0; compno < l_tile->numcomps; ++compno) { \ - /*fprintf(stderr, "compno = %d/%d\n", compno, l_tile->numcomps);*/ \ - \ - /* border of each l_tile component (global) */ \ - l_tilec->x0 = opj_int_ceildiv(l_tile->x0, (OPJ_INT32)l_image_comp->dx); \ - l_tilec->y0 = opj_int_ceildiv(l_tile->y0, (OPJ_INT32)l_image_comp->dy); \ - l_tilec->x1 = opj_int_ceildiv(l_tile->x1, (OPJ_INT32)l_image_comp->dx); \ - l_tilec->y1 = opj_int_ceildiv(l_tile->y1, (OPJ_INT32)l_image_comp->dy); \ - /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/ \ - \ - l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) \ - * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0) * (OPJ_UINT32)sizeof(OPJ_UINT32 );\ - l_tilec->numresolutions = l_tccp->numresolutions; \ - if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) { \ - l_tilec->minimum_num_resolutions = 1; \ - } \ - else { \ - l_tilec->minimum_num_resolutions = l_tccp->numresolutions \ - - l_cp->m_specific_param.m_dec.m_reduce; \ - } \ - \ - if (l_tilec->data == 00) { \ - l_tilec->data = (OPJ_INT32 *) opj_malloc(l_data_size); \ - if (! l_tilec->data ) { \ - return OPJ_FALSE; \ - } \ - /*fprintf(stderr, "\tAllocate data of tilec (int): %d x OPJ_UINT32\n",l_data_size);*/ \ - \ - l_tilec->data_size = l_data_size; \ - } \ - else if (l_data_size > l_tilec->data_size) { \ - OPJ_INT32 * new_data = (OPJ_INT32 *) opj_realloc(l_tilec->data, l_data_size); \ - /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle tile data\n"); */ \ - fprintf(stderr, "Not enough memory to handle tile data\n"); \ - if (! new_data) { \ - opj_free(l_tilec->data); \ - l_tilec->data = NULL; \ - l_tilec->data_size = 0; \ - return OPJ_FALSE; \ - } \ - l_tilec->data = new_data; \ - /*fprintf(stderr, "\tReallocate data of tilec (int): from %d to %d x OPJ_UINT32\n", l_tilec->data_size, l_data_size);*/ \ - l_tilec->data_size = l_data_size; \ - } \ - \ - l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof(opj_tcd_resolution_t); \ - \ - if (l_tilec->resolutions == 00) { \ - l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size); \ - if (! l_tilec->resolutions ) { \ - return OPJ_FALSE; \ - } \ - /*fprintf(stderr, "\tAllocate resolutions of tilec (opj_tcd_resolution_t): %d\n",l_data_size);*/ \ - l_tilec->resolutions_size = l_data_size; \ - memset(l_tilec->resolutions,0,l_data_size); \ - } \ - else if (l_data_size > l_tilec->resolutions_size) { \ - opj_tcd_resolution_t* new_resolutions = (opj_tcd_resolution_t *) opj_realloc(l_tilec->resolutions, l_data_size); \ - if (! new_resolutions) { \ - /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to tile resolutions\n"); */ \ - fprintf(stderr, "Not enough memory to tile resolutions\n"); \ - opj_free(l_tilec->resolutions); \ - l_tilec->resolutions = NULL; \ - l_tilec->resolutions_size = 0; \ - return OPJ_FALSE; \ - } \ - l_tilec->resolutions = new_resolutions; \ - /*fprintf(stderr, "\tReallocate data of tilec (int): from %d to %d x OPJ_UINT32\n", l_tilec->resolutions_size, l_data_size);*/ \ - memset(((OPJ_BYTE*) l_tilec->resolutions)+l_tilec->resolutions_size,0,l_data_size - l_tilec->resolutions_size); \ - l_tilec->resolutions_size = l_data_size; \ - } \ - \ - l_level_no = l_tilec->numresolutions - 1; \ - l_res = l_tilec->resolutions; \ - l_step_size = l_tccp->stepsizes; \ - if (l_tccp->qmfbid == 0) { \ - l_gain_ptr = &opj_dwt_getgain_real; \ - } \ - else { \ - l_gain_ptr = &opj_dwt_getgain; \ - } \ - /*fprintf(stderr, "\tlevel_no=%d\n",l_level_no);*/ \ - \ - for(resno = 0; resno < l_tilec->numresolutions; ++resno) { \ - /*fprintf(stderr, "\t\tresno = %d/%d\n", resno, l_tilec->numresolutions);*/ \ - OPJ_INT32 tlcbgxstart, tlcbgystart /*, brcbgxend, brcbgyend*/; \ - OPJ_UINT32 cbgwidthexpn, cbgheightexpn; \ - OPJ_UINT32 cblkwidthexpn, cblkheightexpn; \ - \ - /* border for each resolution level (global) */ \ - l_res->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no); \ - l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); \ - l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no); \ - l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no); \ - /*fprintf(stderr, "\t\t\tres_x0= %d, res_y0 =%d, res_x1=%d, res_y1=%d\n", l_res->x0, l_res->y0, l_res->x1, l_res->y1);*/ \ - /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ \ - l_pdx = l_tccp->prcw[resno]; \ - l_pdy = l_tccp->prch[resno]; \ - /*fprintf(stderr, "\t\t\tpdx=%d, pdy=%d\n", l_pdx, l_pdy);*/ \ - /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ \ - l_tl_prc_x_start = opj_int_floordivpow2(l_res->x0, (OPJ_INT32)l_pdx) << l_pdx; \ - l_tl_prc_y_start = opj_int_floordivpow2(l_res->y0, (OPJ_INT32)l_pdy) << l_pdy; \ - l_br_prc_x_end = opj_int_ceildivpow2(l_res->x1, (OPJ_INT32)l_pdx) << l_pdx; \ - l_br_prc_y_end = opj_int_ceildivpow2(l_res->y1, (OPJ_INT32)l_pdy) << l_pdy; \ - /*fprintf(stderr, "\t\t\tprc_x_start=%d, prc_y_start=%d, br_prc_x_end=%d, br_prc_y_end=%d \n", l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end ,l_br_prc_y_end );*/ \ - \ - l_res->pw = (l_res->x0 == l_res->x1) ? 0 : (OPJ_UINT32)((l_br_prc_x_end - l_tl_prc_x_start) >> l_pdx); \ - l_res->ph = (l_res->y0 == l_res->y1) ? 0 : (OPJ_UINT32)((l_br_prc_y_end - l_tl_prc_y_start) >> l_pdy); \ - /*fprintf(stderr, "\t\t\tres_pw=%d, res_ph=%d\n", l_res->pw, l_res->ph );*/ \ - \ - l_nb_precincts = l_res->pw * l_res->ph; \ - l_nb_precinct_size = l_nb_precincts * (OPJ_UINT32)sizeof(opj_tcd_precinct_t); \ - if (resno == 0) { \ - tlcbgxstart = l_tl_prc_x_start; \ - tlcbgystart = l_tl_prc_y_start; \ - /*brcbgxend = l_br_prc_x_end;*/ \ - /* brcbgyend = l_br_prc_y_end;*/ \ - cbgwidthexpn = l_pdx; \ - cbgheightexpn = l_pdy; \ - l_res->numbands = 1; \ - } \ - else { \ - tlcbgxstart = opj_int_ceildivpow2(l_tl_prc_x_start, 1); \ - tlcbgystart = opj_int_ceildivpow2(l_tl_prc_y_start, 1); \ - /*brcbgxend = opj_int_ceildivpow2(l_br_prc_x_end, 1);*/ \ - /*brcbgyend = opj_int_ceildivpow2(l_br_prc_y_end, 1);*/ \ - cbgwidthexpn = l_pdx - 1; \ - cbgheightexpn = l_pdy - 1; \ - l_res->numbands = 3; \ - } \ - \ - cblkwidthexpn = opj_uint_min(l_tccp->cblkw, cbgwidthexpn); \ - cblkheightexpn = opj_uint_min(l_tccp->cblkh, cbgheightexpn); \ - l_band = l_res->bands; \ - \ - for (bandno = 0; bandno < l_res->numbands; ++bandno) { \ - OPJ_INT32 numbps; \ - /*fprintf(stderr, "\t\t\tband_no=%d/%d\n", bandno, l_res->numbands );*/ \ - \ - if (resno == 0) { \ - l_band->bandno = 0 ; \ - l_band->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no); \ - l_band->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); \ - l_band->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no); \ - l_band->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no); \ - } \ - else { \ - l_band->bandno = bandno + 1; \ - /* x0b = 1 if bandno = 1 or 3 */ \ - l_x0b = l_band->bandno&1; \ - /* y0b = 1 if bandno = 2 or 3 */ \ - l_y0b = (OPJ_INT32)((l_band->bandno)>>1); \ - /* l_band border (global) */ \ - l_band->x0 = opj_int_ceildivpow2(l_tilec->x0 - (1 << l_level_no) * l_x0b, (OPJ_INT32)(l_level_no + 1)); \ - l_band->y0 = opj_int_ceildivpow2(l_tilec->y0 - (1 << l_level_no) * l_y0b, (OPJ_INT32)(l_level_no + 1)); \ - l_band->x1 = opj_int_ceildivpow2(l_tilec->x1 - (1 << l_level_no) * l_x0b, (OPJ_INT32)(l_level_no + 1)); \ - l_band->y1 = opj_int_ceildivpow2(l_tilec->y1 - (1 << l_level_no) * l_y0b, (OPJ_INT32)(l_level_no + 1)); \ - } \ - \ - /** avoid an if with storing function pointer */ \ - l_gain = (*l_gain_ptr) (l_band->bandno); \ - numbps = (OPJ_INT32)(l_image_comp->prec + l_gain); \ - l_band->stepsize = (OPJ_FLOAT32)(((1.0 + l_step_size->mant / 2048.0) * pow(2.0, (OPJ_INT32) (numbps - l_step_size->expn)))) * FRACTION; \ - l_band->numbps = l_step_size->expn + (OPJ_INT32)l_tccp->numgbits - 1; /* WHY -1 ? */ \ - \ - if (! l_band->precincts) { \ - l_band->precincts = (opj_tcd_precinct_t *) opj_malloc( /*3 * */ l_nb_precinct_size); \ - if (! l_band->precincts) { \ - return OPJ_FALSE; \ - } \ - /*fprintf(stderr, "\t\t\t\tAllocate precincts of a band (opj_tcd_precinct_t): %d\n",l_nb_precinct_size); */ \ - memset(l_band->precincts,0,l_nb_precinct_size); \ - l_band->precincts_data_size = l_nb_precinct_size; \ - } \ - else if (l_band->precincts_data_size < l_nb_precinct_size) { \ - \ - opj_tcd_precinct_t * new_precincts = (opj_tcd_precinct_t *) opj_realloc(l_band->precincts,/*3 * */ l_nb_precinct_size); \ - if (! new_precincts) { \ - /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to handle band precints\n"); */ \ - fprintf(stderr, "Not enough memory to handle band precints\n"); \ - opj_free(l_band->precincts); \ - l_band->precincts = NULL; \ - l_band->precincts_data_size = 0; \ - return OPJ_FALSE; \ - } \ - l_band->precincts = new_precincts; \ - /*fprintf(stderr, "\t\t\t\tReallocate precincts of a band (opj_tcd_precinct_t): from %d to %d\n",l_band->precincts_data_size, l_nb_precinct_size);*/ \ - memset(((OPJ_BYTE *) l_band->precincts) + l_band->precincts_data_size,0,l_nb_precinct_size - l_band->precincts_data_size); \ - l_band->precincts_data_size = l_nb_precinct_size; \ - } \ - \ - l_current_precinct = l_band->precincts; \ - for (precno = 0; precno < l_nb_precincts; ++precno) { \ - OPJ_INT32 tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; \ - OPJ_INT32 cbgxstart = tlcbgxstart + (OPJ_INT32)(precno % l_res->pw) * (1 << cbgwidthexpn); \ - OPJ_INT32 cbgystart = tlcbgystart + (OPJ_INT32)(precno / l_res->pw) * (1 << cbgheightexpn); \ - OPJ_INT32 cbgxend = cbgxstart + (1 << cbgwidthexpn); \ - OPJ_INT32 cbgyend = cbgystart + (1 << cbgheightexpn); \ - /*fprintf(stderr, "\t precno=%d; bandno=%d, resno=%d; compno=%d\n", precno, bandno , resno, compno);*/ \ - /*fprintf(stderr, "\t tlcbgxstart(=%d) + (precno(=%d) percent res->pw(=%d)) * (1 << cbgwidthexpn(=%d)) \n",tlcbgxstart,precno,l_res->pw,cbgwidthexpn);*/ \ - \ - /* precinct size (global) */ \ - /*fprintf(stderr, "\t cbgxstart=%d, l_band->x0 = %d \n",cbgxstart, l_band->x0);*/ \ - \ - l_current_precinct->x0 = opj_int_max(cbgxstart, l_band->x0); \ - l_current_precinct->y0 = opj_int_max(cbgystart, l_band->y0); \ - l_current_precinct->x1 = opj_int_min(cbgxend, l_band->x1); \ - l_current_precinct->y1 = opj_int_min(cbgyend, l_band->y1); \ - /*fprintf(stderr, "\t prc_x0=%d; prc_y0=%d, prc_x1=%d; prc_y1=%d\n",l_current_precinct->x0, l_current_precinct->y0 ,l_current_precinct->x1, l_current_precinct->y1);*/ \ - \ - tlcblkxstart = opj_int_floordivpow2(l_current_precinct->x0, (OPJ_INT32)cblkwidthexpn) << cblkwidthexpn; \ - /*fprintf(stderr, "\t tlcblkxstart =%d\n",tlcblkxstart );*/ \ - tlcblkystart = opj_int_floordivpow2(l_current_precinct->y0, (OPJ_INT32)cblkheightexpn) << cblkheightexpn; \ - /*fprintf(stderr, "\t tlcblkystart =%d\n",tlcblkystart );*/ \ - brcblkxend = opj_int_ceildivpow2(l_current_precinct->x1, (OPJ_INT32)cblkwidthexpn) << cblkwidthexpn; \ - /*fprintf(stderr, "\t brcblkxend =%d\n",brcblkxend );*/ \ - brcblkyend = opj_int_ceildivpow2(l_current_precinct->y1, (OPJ_INT32)cblkheightexpn) << cblkheightexpn; \ - /*fprintf(stderr, "\t brcblkyend =%d\n",brcblkyend );*/ \ - l_current_precinct->cw = (OPJ_UINT32)((brcblkxend - tlcblkxstart) >> cblkwidthexpn); \ - l_current_precinct->ch = (OPJ_UINT32)((brcblkyend - tlcblkystart) >> cblkheightexpn); \ - \ - l_nb_code_blocks = l_current_precinct->cw * l_current_precinct->ch; \ - /*fprintf(stderr, "\t\t\t\t precinct_cw = %d x recinct_ch = %d\n",l_current_precinct->cw, l_current_precinct->ch); */ \ - l_nb_code_blocks_size = l_nb_code_blocks * (OPJ_UINT32)sizeof(TYPE); \ - \ - if (! l_current_precinct->cblks.ELEMENT) { \ - l_current_precinct->cblks.ELEMENT = (TYPE*) opj_malloc(l_nb_code_blocks_size); \ - if (! l_current_precinct->cblks.ELEMENT ) { \ - return OPJ_FALSE; \ - } \ - /*fprintf(stderr, "\t\t\t\tAllocate cblks of a precinct (opj_tcd_cblk_dec_t): %d\n",l_nb_code_blocks_size);*/ \ - \ - memset(l_current_precinct->cblks.ELEMENT,0,l_nb_code_blocks_size); \ - \ - l_current_precinct->block_size = l_nb_code_blocks_size; \ - } \ - else if (l_nb_code_blocks_size > l_current_precinct->block_size) { \ - TYPE *new_ELEMENT = (TYPE*) opj_realloc(l_current_precinct->cblks.ELEMENT, l_nb_code_blocks_size); \ - if (! new_ELEMENT) { \ - opj_free(l_current_precinct->cblks.ELEMENT); \ - l_current_precinct->cblks.ELEMENT = NULL; \ - l_current_precinct->block_size = 0; \ - /* opj_event_msg(p_manager, EVT_ERROR, "Not enough memory for current precinct codeblock element\n"); */ \ - fprintf(stderr, "Not enough memory for current precinct codeblock element\n"); \ - return OPJ_FALSE; \ - } \ - l_current_precinct->cblks.ELEMENT = new_ELEMENT; \ - /*fprintf(stderr, "\t\t\t\tReallocate cblks of a precinct (opj_tcd_cblk_dec_t): from %d to %d\n",l_current_precinct->block_size, l_nb_code_blocks_size); */\ - \ - memset(((OPJ_BYTE *) l_current_precinct->cblks.ELEMENT) + l_current_precinct->block_size \ - ,0 \ - ,l_nb_code_blocks_size - l_current_precinct->block_size); \ - \ - l_current_precinct->block_size = l_nb_code_blocks_size; \ - } \ - \ - if (! l_current_precinct->incltree) { \ - l_current_precinct->incltree = opj_tgt_create(l_current_precinct->cw, \ - l_current_precinct->ch); \ - } \ - else{ \ - l_current_precinct->incltree = opj_tgt_init(l_current_precinct->incltree, \ - l_current_precinct->cw, \ - l_current_precinct->ch); \ - } \ - \ - if (! l_current_precinct->incltree) { \ - fprintf(stderr, "WARNING: No incltree created.\n"); \ - /*return OPJ_FALSE;*/ \ - } \ - \ - if (! l_current_precinct->imsbtree) { \ - l_current_precinct->imsbtree = opj_tgt_create( \ - l_current_precinct->cw, \ - l_current_precinct->ch); \ - } \ - else { \ - l_current_precinct->imsbtree = opj_tgt_init( \ - l_current_precinct->imsbtree, \ - l_current_precinct->cw, \ - l_current_precinct->ch); \ - } \ - \ - if (! l_current_precinct->imsbtree) { \ - fprintf(stderr, "WARNING: No imsbtree created.\n"); \ - /*return OPJ_FALSE;*/ \ - } \ - \ - l_code_block = l_current_precinct->cblks.ELEMENT; \ - \ - for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { \ - OPJ_INT32 cblkxstart = tlcblkxstart + (OPJ_INT32)(cblkno % l_current_precinct->cw) * (1 << cblkwidthexpn); \ - OPJ_INT32 cblkystart = tlcblkystart + (OPJ_INT32)(cblkno / l_current_precinct->cw) * (1 << cblkheightexpn); \ - OPJ_INT32 cblkxend = cblkxstart + (1 << cblkwidthexpn); \ - OPJ_INT32 cblkyend = cblkystart + (1 << cblkheightexpn); \ - \ - /* code-block size (global) */ \ - l_code_block->x0 = opj_int_max(cblkxstart, l_current_precinct->x0); \ - l_code_block->y0 = opj_int_max(cblkystart, l_current_precinct->y0); \ - l_code_block->x1 = opj_int_min(cblkxend, l_current_precinct->x1); \ - l_code_block->y1 = opj_int_min(cblkyend, l_current_precinct->y1); \ - \ - if (! FUNCTION_ELEMENT(l_code_block)) { \ - return OPJ_FALSE; \ - } \ - ++l_code_block; \ - } \ - ++l_current_precinct; \ - } /* precno */ \ - ++l_band; \ - ++l_step_size; \ - } /* bandno */ \ - ++l_res; \ - --l_level_no; \ - } /* resno */ \ - ++l_tccp; \ - ++l_tilec; \ - ++l_image_comp; \ - } /* compno */ \ - return OPJ_TRUE; \ -} \ +static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BOOL isEncoder, OPJ_FLOAT32 fraction, OPJ_SIZE_T sizeof_block, opj_event_mgr_t* manager) +{ + OPJ_UINT32 (*l_gain_ptr)(OPJ_UINT32) = 00; + OPJ_UINT32 compno, resno, bandno, precno, cblkno; + opj_tcp_t * l_tcp = 00; + opj_cp_t * l_cp = 00; + opj_tcd_tile_t * l_tile = 00; + opj_tccp_t *l_tccp = 00; + opj_tcd_tilecomp_t *l_tilec = 00; + opj_image_comp_t * l_image_comp = 00; + opj_tcd_resolution_t *l_res = 00; + opj_tcd_band_t *l_band = 00; + opj_stepsize_t * l_step_size = 00; + opj_tcd_precinct_t *l_current_precinct = 00; + opj_image_t *l_image = 00; + OPJ_UINT32 p,q; + OPJ_UINT32 l_level_no; + OPJ_UINT32 l_pdx, l_pdy; + OPJ_UINT32 l_gain; + OPJ_INT32 l_x0b, l_y0b; + OPJ_UINT32 l_tx0, l_ty0; + /* extent of precincts , top left, bottom right**/ + OPJ_INT32 l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end, l_br_prc_y_end; + /* number of precinct for a resolution */ + OPJ_UINT32 l_nb_precincts; + /* room needed to store l_nb_precinct precinct for a resolution */ + OPJ_UINT32 l_nb_precinct_size; + /* number of code blocks for a precinct*/ + OPJ_UINT32 l_nb_code_blocks; + /* room needed to store l_nb_code_blocks code blocks for a precinct*/ + OPJ_UINT32 l_nb_code_blocks_size; + /* size of data for a tile */ + OPJ_UINT32 l_data_size; + + l_cp = p_tcd->cp; + l_tcp = &(l_cp->tcps[p_tile_no]); + l_tile = p_tcd->tcd_image->tiles; + l_tccp = l_tcp->tccps; + l_tilec = l_tile->comps; + l_image = p_tcd->image; + l_image_comp = p_tcd->image->comps; + + p = p_tile_no % l_cp->tw; /* tile coordinates */ + q = p_tile_no / l_cp->tw; + /*fprintf(stderr, "Tile coordinate = %d,%d\n", p, q);*/ + + /* 4 borders of the tile rescale on the image if necessary */ + l_tx0 = l_cp->tx0 + p * l_cp->tdx; /* can't be greater than l_image->x1 so won't overflow */ + l_tile->x0 = (OPJ_INT32)opj_uint_max(l_tx0, l_image->x0); + l_tile->x1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_tx0, l_cp->tdx), l_image->x1); + l_ty0 = l_cp->ty0 + q * l_cp->tdy; /* can't be greater than l_image->y1 so won't overflow */ + l_tile->y0 = (OPJ_INT32)opj_uint_max(l_ty0, l_image->y0); + l_tile->y1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_ty0, l_cp->tdy), l_image->y1); -OPJ_MACRO_TCD_ALLOCATE(opj_tcd_init_encode_tile, opj_tcd_cblk_enc_t, 1.f, enc, opj_tcd_code_block_enc_allocate) -OPJ_MACRO_TCD_ALLOCATE(opj_tcd_init_decode_tile, opj_tcd_cblk_dec_t, 0.5f, dec, opj_tcd_code_block_dec_allocate) + /* testcase 1888.pdf.asan.35.988 */ + if (l_tccp->numresolutions == 0) { + opj_event_msg(manager, EVT_ERROR, "tiles require at least one resolution\n"); + return OPJ_FALSE; + } + /*fprintf(stderr, "Tile border = %d,%d,%d,%d\n", l_tile->x0, l_tile->y0,l_tile->x1,l_tile->y1);*/ + + /*tile->numcomps = image->numcomps; */ + for (compno = 0; compno < l_tile->numcomps; ++compno) { + /*fprintf(stderr, "compno = %d/%d\n", compno, l_tile->numcomps);*/ + l_image_comp->resno_decoded = 0; + /* border of each l_tile component (global) */ + l_tilec->x0 = opj_int_ceildiv(l_tile->x0, (OPJ_INT32)l_image_comp->dx); + l_tilec->y0 = opj_int_ceildiv(l_tile->y0, (OPJ_INT32)l_image_comp->dy); + l_tilec->x1 = opj_int_ceildiv(l_tile->x1, (OPJ_INT32)l_image_comp->dx); + l_tilec->y1 = opj_int_ceildiv(l_tile->y1, (OPJ_INT32)l_image_comp->dy); + /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/ + + /* compute l_data_size with overflow check */ + l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); + if ((((OPJ_UINT32)-1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0)) { + opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + return OPJ_FALSE; + } + l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); + + if ((((OPJ_UINT32)-1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) { + opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + return OPJ_FALSE; + } + l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32); + l_tilec->numresolutions = l_tccp->numresolutions; + if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) { + l_tilec->minimum_num_resolutions = 1; + } + else { + l_tilec->minimum_num_resolutions = l_tccp->numresolutions - l_cp->m_specific_param.m_dec.m_reduce; + } + + l_tilec->data_size_needed = l_data_size; + if (p_tcd->m_is_decoder && !opj_alloc_tile_component_data(l_tilec)) { + opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + return OPJ_FALSE; + } + + l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof(opj_tcd_resolution_t); + + if (l_tilec->resolutions == 00) { + l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size); + if (! l_tilec->resolutions ) { + return OPJ_FALSE; + } + /*fprintf(stderr, "\tAllocate resolutions of tilec (opj_tcd_resolution_t): %d\n",l_data_size);*/ + l_tilec->resolutions_size = l_data_size; + memset(l_tilec->resolutions,0,l_data_size); + } + else if (l_data_size > l_tilec->resolutions_size) { + opj_tcd_resolution_t* new_resolutions = (opj_tcd_resolution_t *) opj_realloc(l_tilec->resolutions, l_data_size); + if (! new_resolutions) { + opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile resolutions\n"); + opj_free(l_tilec->resolutions); + l_tilec->resolutions = NULL; + l_tilec->resolutions_size = 0; + return OPJ_FALSE; + } + l_tilec->resolutions = new_resolutions; + /*fprintf(stderr, "\tReallocate data of tilec (int): from %d to %d x OPJ_UINT32\n", l_tilec->resolutions_size, l_data_size);*/ + memset(((OPJ_BYTE*) l_tilec->resolutions)+l_tilec->resolutions_size,0,l_data_size - l_tilec->resolutions_size); + l_tilec->resolutions_size = l_data_size; + } + + l_level_no = l_tilec->numresolutions - 1; + l_res = l_tilec->resolutions; + l_step_size = l_tccp->stepsizes; + if (l_tccp->qmfbid == 0) { + l_gain_ptr = &opj_dwt_getgain_real; + } + else { + l_gain_ptr = &opj_dwt_getgain; + } + /*fprintf(stderr, "\tlevel_no=%d\n",l_level_no);*/ + + for (resno = 0; resno < l_tilec->numresolutions; ++resno) { + /*fprintf(stderr, "\t\tresno = %d/%d\n", resno, l_tilec->numresolutions);*/ + OPJ_INT32 tlcbgxstart, tlcbgystart /*, brcbgxend, brcbgyend*/; + OPJ_UINT32 cbgwidthexpn, cbgheightexpn; + OPJ_UINT32 cblkwidthexpn, cblkheightexpn; + + /* border for each resolution level (global) */ + l_res->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no); + l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); + l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no); + l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no); + /*fprintf(stderr, "\t\t\tres_x0= %d, res_y0 =%d, res_x1=%d, res_y1=%d\n", l_res->x0, l_res->y0, l_res->x1, l_res->y1);*/ + /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ + l_pdx = l_tccp->prcw[resno]; + l_pdy = l_tccp->prch[resno]; + /*fprintf(stderr, "\t\t\tpdx=%d, pdy=%d\n", l_pdx, l_pdy);*/ + /* p. 64, B.6, ISO/IEC FDIS15444-1 : 2000 (18 august 2000) */ + l_tl_prc_x_start = opj_int_floordivpow2(l_res->x0, (OPJ_INT32)l_pdx) << l_pdx; + l_tl_prc_y_start = opj_int_floordivpow2(l_res->y0, (OPJ_INT32)l_pdy) << l_pdy; + l_br_prc_x_end = opj_int_ceildivpow2(l_res->x1, (OPJ_INT32)l_pdx) << l_pdx; + l_br_prc_y_end = opj_int_ceildivpow2(l_res->y1, (OPJ_INT32)l_pdy) << l_pdy; + /*fprintf(stderr, "\t\t\tprc_x_start=%d, prc_y_start=%d, br_prc_x_end=%d, br_prc_y_end=%d \n", l_tl_prc_x_start, l_tl_prc_y_start, l_br_prc_x_end ,l_br_prc_y_end );*/ + + l_res->pw = (l_res->x0 == l_res->x1) ? 0 : (OPJ_UINT32)((l_br_prc_x_end - l_tl_prc_x_start) >> l_pdx); + l_res->ph = (l_res->y0 == l_res->y1) ? 0 : (OPJ_UINT32)((l_br_prc_y_end - l_tl_prc_y_start) >> l_pdy); + /*fprintf(stderr, "\t\t\tres_pw=%d, res_ph=%d\n", l_res->pw, l_res->ph );*/ + + l_nb_precincts = l_res->pw * l_res->ph; + l_nb_precinct_size = l_nb_precincts * (OPJ_UINT32)sizeof(opj_tcd_precinct_t); + if (resno == 0) { + tlcbgxstart = l_tl_prc_x_start; + tlcbgystart = l_tl_prc_y_start; + /*brcbgxend = l_br_prc_x_end;*/ + /* brcbgyend = l_br_prc_y_end;*/ + cbgwidthexpn = l_pdx; + cbgheightexpn = l_pdy; + l_res->numbands = 1; + } + else { + tlcbgxstart = opj_int_ceildivpow2(l_tl_prc_x_start, 1); + tlcbgystart = opj_int_ceildivpow2(l_tl_prc_y_start, 1); + /*brcbgxend = opj_int_ceildivpow2(l_br_prc_x_end, 1);*/ + /*brcbgyend = opj_int_ceildivpow2(l_br_prc_y_end, 1);*/ + cbgwidthexpn = l_pdx - 1; + cbgheightexpn = l_pdy - 1; + l_res->numbands = 3; + } + + cblkwidthexpn = opj_uint_min(l_tccp->cblkw, cbgwidthexpn); + cblkheightexpn = opj_uint_min(l_tccp->cblkh, cbgheightexpn); + l_band = l_res->bands; + + for (bandno = 0; bandno < l_res->numbands; ++bandno) { + OPJ_INT32 numbps; + /*fprintf(stderr, "\t\t\tband_no=%d/%d\n", bandno, l_res->numbands );*/ + + if (resno == 0) { + l_band->bandno = 0 ; + l_band->x0 = opj_int_ceildivpow2(l_tilec->x0, (OPJ_INT32)l_level_no); + l_band->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); + l_band->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no); + l_band->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no); + } + else { + l_band->bandno = bandno + 1; + /* x0b = 1 if bandno = 1 or 3 */ + l_x0b = l_band->bandno&1; + /* y0b = 1 if bandno = 2 or 3 */ + l_y0b = (OPJ_INT32)((l_band->bandno)>>1); + /* l_band border (global) */ + l_band->x0 = opj_int64_ceildivpow2(l_tilec->x0 - ((OPJ_INT64)l_x0b << l_level_no), (OPJ_INT32)(l_level_no + 1)); + l_band->y0 = opj_int64_ceildivpow2(l_tilec->y0 - ((OPJ_INT64)l_y0b << l_level_no), (OPJ_INT32)(l_level_no + 1)); + l_band->x1 = opj_int64_ceildivpow2(l_tilec->x1 - ((OPJ_INT64)l_x0b << l_level_no), (OPJ_INT32)(l_level_no + 1)); + l_band->y1 = opj_int64_ceildivpow2(l_tilec->y1 - ((OPJ_INT64)l_y0b << l_level_no), (OPJ_INT32)(l_level_no + 1)); + } + + /** avoid an if with storing function pointer */ + l_gain = (*l_gain_ptr) (l_band->bandno); + numbps = (OPJ_INT32)(l_image_comp->prec + l_gain); + l_band->stepsize = (OPJ_FLOAT32)(((1.0 + l_step_size->mant / 2048.0) * pow(2.0, (OPJ_INT32) (numbps - l_step_size->expn)))) * fraction; + l_band->numbps = l_step_size->expn + (OPJ_INT32)l_tccp->numgbits - 1; /* WHY -1 ? */ + + if (!l_band->precincts && (l_nb_precincts > 0U)) { + l_band->precincts = (opj_tcd_precinct_t *) opj_malloc( /*3 * */ l_nb_precinct_size); + if (! l_band->precincts) { + return OPJ_FALSE; + } + /*fprintf(stderr, "\t\t\t\tAllocate precincts of a band (opj_tcd_precinct_t): %d\n",l_nb_precinct_size); */ + memset(l_band->precincts,0,l_nb_precinct_size); + l_band->precincts_data_size = l_nb_precinct_size; + } + else if (l_band->precincts_data_size < l_nb_precinct_size) { + + opj_tcd_precinct_t * new_precincts = (opj_tcd_precinct_t *) opj_realloc(l_band->precincts,/*3 * */ l_nb_precinct_size); + if (! new_precincts) { + opj_event_msg(manager, EVT_ERROR, "Not enough memory to handle band precints\n"); + opj_free(l_band->precincts); + l_band->precincts = NULL; + l_band->precincts_data_size = 0; + return OPJ_FALSE; + } + l_band->precincts = new_precincts; + /*fprintf(stderr, "\t\t\t\tReallocate precincts of a band (opj_tcd_precinct_t): from %d to %d\n",l_band->precincts_data_size, l_nb_precinct_size);*/ + memset(((OPJ_BYTE *) l_band->precincts) + l_band->precincts_data_size,0,l_nb_precinct_size - l_band->precincts_data_size); + l_band->precincts_data_size = l_nb_precinct_size; + } + + l_current_precinct = l_band->precincts; + for (precno = 0; precno < l_nb_precincts; ++precno) { + OPJ_INT32 tlcblkxstart, tlcblkystart, brcblkxend, brcblkyend; + OPJ_INT32 cbgxstart = tlcbgxstart + (OPJ_INT32)(precno % l_res->pw) * (1 << cbgwidthexpn); + OPJ_INT32 cbgystart = tlcbgystart + (OPJ_INT32)(precno / l_res->pw) * (1 << cbgheightexpn); + OPJ_INT32 cbgxend = cbgxstart + (1 << cbgwidthexpn); + OPJ_INT32 cbgyend = cbgystart + (1 << cbgheightexpn); + /*fprintf(stderr, "\t precno=%d; bandno=%d, resno=%d; compno=%d\n", precno, bandno , resno, compno);*/ + /*fprintf(stderr, "\t tlcbgxstart(=%d) + (precno(=%d) percent res->pw(=%d)) * (1 << cbgwidthexpn(=%d)) \n",tlcbgxstart,precno,l_res->pw,cbgwidthexpn);*/ + + /* precinct size (global) */ + /*fprintf(stderr, "\t cbgxstart=%d, l_band->x0 = %d \n",cbgxstart, l_band->x0);*/ + + l_current_precinct->x0 = opj_int_max(cbgxstart, l_band->x0); + l_current_precinct->y0 = opj_int_max(cbgystart, l_band->y0); + l_current_precinct->x1 = opj_int_min(cbgxend, l_band->x1); + l_current_precinct->y1 = opj_int_min(cbgyend, l_band->y1); + /*fprintf(stderr, "\t prc_x0=%d; prc_y0=%d, prc_x1=%d; prc_y1=%d\n",l_current_precinct->x0, l_current_precinct->y0 ,l_current_precinct->x1, l_current_precinct->y1);*/ + + tlcblkxstart = opj_int_floordivpow2(l_current_precinct->x0, (OPJ_INT32)cblkwidthexpn) << cblkwidthexpn; + /*fprintf(stderr, "\t tlcblkxstart =%d\n",tlcblkxstart );*/ + tlcblkystart = opj_int_floordivpow2(l_current_precinct->y0, (OPJ_INT32)cblkheightexpn) << cblkheightexpn; + /*fprintf(stderr, "\t tlcblkystart =%d\n",tlcblkystart );*/ + brcblkxend = opj_int_ceildivpow2(l_current_precinct->x1, (OPJ_INT32)cblkwidthexpn) << cblkwidthexpn; + /*fprintf(stderr, "\t brcblkxend =%d\n",brcblkxend );*/ + brcblkyend = opj_int_ceildivpow2(l_current_precinct->y1, (OPJ_INT32)cblkheightexpn) << cblkheightexpn; + /*fprintf(stderr, "\t brcblkyend =%d\n",brcblkyend );*/ + l_current_precinct->cw = (OPJ_UINT32)((brcblkxend - tlcblkxstart) >> cblkwidthexpn); + l_current_precinct->ch = (OPJ_UINT32)((brcblkyend - tlcblkystart) >> cblkheightexpn); + + l_nb_code_blocks = l_current_precinct->cw * l_current_precinct->ch; + /*fprintf(stderr, "\t\t\t\t precinct_cw = %d x recinct_ch = %d\n",l_current_precinct->cw, l_current_precinct->ch); */ + l_nb_code_blocks_size = l_nb_code_blocks * (OPJ_UINT32)sizeof_block; + + if (!l_current_precinct->cblks.blocks && (l_nb_code_blocks > 0U)) { + l_current_precinct->cblks.blocks = opj_malloc(l_nb_code_blocks_size); + if (! l_current_precinct->cblks.blocks ) { + return OPJ_FALSE; + } + /*fprintf(stderr, "\t\t\t\tAllocate cblks of a precinct (opj_tcd_cblk_dec_t): %d\n",l_nb_code_blocks_size);*/ + + memset(l_current_precinct->cblks.blocks,0,l_nb_code_blocks_size); + + l_current_precinct->block_size = l_nb_code_blocks_size; + } + else if (l_nb_code_blocks_size > l_current_precinct->block_size) { + void *new_blocks = opj_realloc(l_current_precinct->cblks.blocks, l_nb_code_blocks_size); + if (! new_blocks) { + opj_free(l_current_precinct->cblks.blocks); + l_current_precinct->cblks.blocks = NULL; + l_current_precinct->block_size = 0; + opj_event_msg(manager, EVT_ERROR, "Not enough memory for current precinct codeblock element\n"); + return OPJ_FALSE; + } + l_current_precinct->cblks.blocks = new_blocks; + /*fprintf(stderr, "\t\t\t\tReallocate cblks of a precinct (opj_tcd_cblk_dec_t): from %d to %d\n",l_current_precinct->block_size, l_nb_code_blocks_size); */ + + memset(((OPJ_BYTE *) l_current_precinct->cblks.blocks) + l_current_precinct->block_size + ,0 + ,l_nb_code_blocks_size - l_current_precinct->block_size); + + l_current_precinct->block_size = l_nb_code_blocks_size; + } + + if (! l_current_precinct->incltree) { + l_current_precinct->incltree = opj_tgt_create(l_current_precinct->cw, l_current_precinct->ch, manager); + } + else{ + l_current_precinct->incltree = opj_tgt_init(l_current_precinct->incltree, l_current_precinct->cw, l_current_precinct->ch, manager); + } -#undef OPJ_MACRO_TCD_ALLOCATE + if (! l_current_precinct->incltree) { + opj_event_msg(manager, EVT_WARNING, "No incltree created.\n"); + /*return OPJ_FALSE;*/ + } + + if (! l_current_precinct->imsbtree) { + l_current_precinct->imsbtree = opj_tgt_create(l_current_precinct->cw, l_current_precinct->ch, manager); + } + else { + l_current_precinct->imsbtree = opj_tgt_init(l_current_precinct->imsbtree, l_current_precinct->cw, l_current_precinct->ch, manager); + } + + if (! l_current_precinct->imsbtree) { + opj_event_msg(manager, EVT_WARNING, "No imsbtree created.\n"); + /*return OPJ_FALSE;*/ + } + + for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { + OPJ_INT32 cblkxstart = tlcblkxstart + (OPJ_INT32)(cblkno % l_current_precinct->cw) * (1 << cblkwidthexpn); + OPJ_INT32 cblkystart = tlcblkystart + (OPJ_INT32)(cblkno / l_current_precinct->cw) * (1 << cblkheightexpn); + OPJ_INT32 cblkxend = cblkxstart + (1 << cblkwidthexpn); + OPJ_INT32 cblkyend = cblkystart + (1 << cblkheightexpn); + + if (isEncoder) { + opj_tcd_cblk_enc_t* l_code_block = l_current_precinct->cblks.enc + cblkno; + + if (! opj_tcd_code_block_enc_allocate(l_code_block)) { + return OPJ_FALSE; + } + /* code-block size (global) */ + l_code_block->x0 = opj_int_max(cblkxstart, l_current_precinct->x0); + l_code_block->y0 = opj_int_max(cblkystart, l_current_precinct->y0); + l_code_block->x1 = opj_int_min(cblkxend, l_current_precinct->x1); + l_code_block->y1 = opj_int_min(cblkyend, l_current_precinct->y1); + + if (! opj_tcd_code_block_enc_allocate_data(l_code_block)) { + return OPJ_FALSE; + } + } else { + opj_tcd_cblk_dec_t* l_code_block = l_current_precinct->cblks.dec + cblkno; + + if (! opj_tcd_code_block_dec_allocate(l_code_block)) { + return OPJ_FALSE; + } + /* code-block size (global) */ + l_code_block->x0 = opj_int_max(cblkxstart, l_current_precinct->x0); + l_code_block->y0 = opj_int_max(cblkystart, l_current_precinct->y0); + l_code_block->x1 = opj_int_min(cblkxend, l_current_precinct->x1); + l_code_block->y1 = opj_int_min(cblkyend, l_current_precinct->y1); + } + } + ++l_current_precinct; + } /* precno */ + ++l_band; + ++l_step_size; + } /* bandno */ + ++l_res; + --l_level_no; + } /* resno */ + ++l_tccp; + ++l_tilec; + ++l_image_comp; + } /* compno */ + return OPJ_TRUE; +} + +OPJ_BOOL opj_tcd_init_encode_tile (opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, opj_event_mgr_t* p_manager) +{ + return opj_tcd_init_tile(p_tcd, p_tile_no, OPJ_TRUE, 1.0F, sizeof(opj_tcd_cblk_enc_t), p_manager); +} + +OPJ_BOOL opj_tcd_init_decode_tile (opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, opj_event_mgr_t* p_manager) +{ + return opj_tcd_init_tile(p_tcd, p_tile_no, OPJ_FALSE, 0.5F, sizeof(opj_tcd_cblk_dec_t), p_manager); +} /** - * Allocates memory for an encoding code block. + * Allocates memory for an encoding code block (but not data memory). */ -OPJ_BOOL opj_tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block) +static OPJ_BOOL opj_tcd_code_block_enc_allocate (opj_tcd_cblk_enc_t * p_code_block) { - if (! p_code_block->data) { + if (! p_code_block->layers) { + /* no memset since data */ + p_code_block->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t)); + if (! p_code_block->layers) { + return OPJ_FALSE; + } + } + if (! p_code_block->passes) { + p_code_block->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t)); + if (! p_code_block->passes) { + return OPJ_FALSE; + } + } + return OPJ_TRUE; +} - p_code_block->data = (OPJ_BYTE*) opj_malloc(OPJ_J2K_DEFAULT_CBLK_DATA_SIZE*2); /*why +1 ?*/ - if(! p_code_block->data) { - return OPJ_FALSE; - } - - p_code_block->data[0] = 0; - p_code_block->data+=1; - - /* no memset since data */ - p_code_block->layers = (opj_tcd_layer_t*) opj_malloc(100 * sizeof(opj_tcd_layer_t)); - if (! p_code_block->layers) { - return OPJ_FALSE; - } - - p_code_block->passes = (opj_tcd_pass_t*) opj_malloc(100 * sizeof(opj_tcd_pass_t)); - if (! p_code_block->passes) { - return OPJ_FALSE; - } - } - - memset(p_code_block->layers,0,100 * sizeof(opj_tcd_layer_t)); - memset(p_code_block->passes,0,100 * sizeof(opj_tcd_pass_t)); - - return OPJ_TRUE; +/** + * Allocates data memory for an encoding code block. + */ +static OPJ_BOOL opj_tcd_code_block_enc_allocate_data (opj_tcd_cblk_enc_t * p_code_block) +{ + OPJ_UINT32 l_data_size; + + l_data_size = (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) * (p_code_block->y1 - p_code_block->y0) * (OPJ_INT32)sizeof(OPJ_UINT32)); + + if (l_data_size > p_code_block->data_size) { + if (p_code_block->data) { + opj_free(p_code_block->data - 1); /* again, why -1 */ + } + p_code_block->data = (OPJ_BYTE*) opj_malloc(l_data_size+1); + if(! p_code_block->data) { + p_code_block->data_size = 0U; + return OPJ_FALSE; + } + p_code_block->data_size = l_data_size; + + p_code_block->data[0] = 0; + p_code_block->data+=1; /*why +1 ?*/ + } + return OPJ_TRUE; } /** * Allocates memory for a decoding code block. */ -OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) +static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) { - OPJ_UINT32 l_seg_size; - if (! p_code_block->data) { p_code_block->data = (OPJ_BYTE*) opj_malloc(OPJ_J2K_DEFAULT_CBLK_DATA_SIZE); @@ -1054,19 +1104,27 @@ OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block) p_code_block->data_max_size = OPJ_J2K_DEFAULT_CBLK_DATA_SIZE; /*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/ - l_seg_size = OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t); - p_code_block->segs = (opj_tcd_seg_t *) opj_malloc(l_seg_size); + p_code_block->segs = (opj_tcd_seg_t *) opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS,sizeof(opj_tcd_seg_t)); if (! p_code_block->segs) { return OPJ_FALSE; } - memset(p_code_block->segs,0,l_seg_size); /*fprintf(stderr, "Allocate %d elements of code_block->data\n", OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/ p_code_block->m_current_max_segs = OPJ_J2K_DEFAULT_NB_SEGS; /*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/ - } - /* TODO */ - /*p_code_block->numsegs = 0; */ + } else { + /* sanitize */ + OPJ_BYTE* l_data = p_code_block->data; + OPJ_UINT32 l_data_max_size = p_code_block->data_max_size; + opj_tcd_seg_t * l_segs = p_code_block->segs; + OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs; + + memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t)); + p_code_block->data = l_data; + p_code_block->data_max_size = l_data_max_size; + p_code_block->segs = l_segs; + p_code_block->m_current_max_segs = l_current_max_segs; + } return OPJ_TRUE; } @@ -1135,6 +1193,10 @@ OPJ_BOOL opj_tcd_encode_tile( opj_tcd_t *p_tcd, p_cstr_info->tile[p_tile_no].pdy[i] = (int)l_tccp->prch[i]; } p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t*) opj_calloc((size_t)p_cstr_info->numcomps * (size_t)p_cstr_info->numlayers * l_num_packs, sizeof(opj_packet_info_t)); + if (!p_cstr_info->tile[p_tile_no].packet) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } } /* << INDEX */ @@ -1192,7 +1254,8 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, OPJ_BYTE *p_src, OPJ_UINT32 p_max_length, OPJ_UINT32 p_tile_no, - opj_codestream_index_t *p_cstr_index + opj_codestream_index_t *p_cstr_index, + opj_event_mgr_t *p_manager ) { OPJ_UINT32 l_data_read; @@ -1225,7 +1288,7 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, /*--------------TIER2------------------*/ /* FIXME _ProfStart(PGROUP_T2); */ l_data_read = 0; - if (! opj_tcd_t2_decode(p_tcd, p_src, &l_data_read, p_max_length, p_cstr_index)) + if (! opj_tcd_t2_decode(p_tcd, p_src, &l_data_read, p_max_length, p_cstr_index, p_manager)) { return OPJ_FALSE; } @@ -1254,7 +1317,7 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd, /*----------------MCT-------------------*/ /* FIXME _ProfStart(PGROUP_MCT); */ if - (! opj_tcd_mct_decode(p_tcd)) + (! opj_tcd_mct_decode(p_tcd, p_manager)) { return OPJ_FALSE; } @@ -1388,7 +1451,7 @@ OPJ_BOOL opj_tcd_update_tile_data ( opj_tcd_t *p_tcd, -void opj_tcd_free_tile(opj_tcd_t *p_tcd) +static void opj_tcd_free_tile(opj_tcd_t *p_tcd) { OPJ_UINT32 compno, resno, bandno, precno; opj_tcd_tile_t *l_tile = 00; @@ -1454,9 +1517,12 @@ void opj_tcd_free_tile(opj_tcd_t *p_tcd) l_tile_comp->resolutions = 00; } - if (l_tile_comp->data) { - opj_free(l_tile_comp->data); + if (l_tile_comp->ownsData && l_tile_comp->data) { + opj_aligned_free(l_tile_comp->data); l_tile_comp->data = 00; + l_tile_comp->ownsData = 0; + l_tile_comp->data_size = 0; + l_tile_comp->data_size_needed = 0; } ++l_tile_comp; } @@ -1468,11 +1534,12 @@ void opj_tcd_free_tile(opj_tcd_t *p_tcd) } -OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, +static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, OPJ_BYTE * p_src_data, OPJ_UINT32 * p_data_read, OPJ_UINT32 p_max_src_size, - opj_codestream_index_t *p_cstr_index + opj_codestream_index_t *p_cstr_index, + opj_event_mgr_t *p_manager ) { opj_t2_t * l_t2; @@ -1489,7 +1556,8 @@ OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, p_src_data, p_data_read, p_max_src_size, - p_cstr_index)) { + p_cstr_index, + p_manager)) { opj_t2_destroy(l_t2); return OPJ_FALSE; } @@ -1500,7 +1568,7 @@ OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd, return OPJ_TRUE; } -OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; opj_t1_t * l_t1; @@ -1509,7 +1577,7 @@ OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd ) opj_tccp_t * l_tccp = p_tcd->tcp->tccps; - l_t1 = opj_t1_create(); + l_t1 = opj_t1_create(OPJ_FALSE); if (l_t1 == 00) { return OPJ_FALSE; } @@ -1530,7 +1598,7 @@ OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd ) } -OPJ_BOOL opj_tcd_dwt_decode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_dwt_decode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; @@ -1570,7 +1638,7 @@ OPJ_BOOL opj_tcd_dwt_decode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) { opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcp_t * l_tcp = p_tcd->tcp; @@ -1588,7 +1656,7 @@ OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd ) if ((l_tile->comps[0].x1 - l_tile->comps[0].x0) * (l_tile->comps[0].y1 - l_tile->comps[0].y0) < (OPJ_INT32)l_samples || (l_tile->comps[1].x1 - l_tile->comps[1].x0) * (l_tile->comps[1].y1 - l_tile->comps[1].y0) < (OPJ_INT32)l_samples || (l_tile->comps[2].x1 - l_tile->comps[2].x0) * (l_tile->comps[2].y1 - l_tile->comps[2].y0) < (OPJ_INT32)l_samples) { - fprintf(stderr, "Tiles don't all have the same dimension. Skip the MCT step.\n"); + opj_event_msg(p_manager, EVT_ERROR, "Tiles don't all have the same dimension. Skip the MCT step.\n"); return OPJ_FALSE; } else if (l_tcp->mct == 2) { @@ -1640,15 +1708,14 @@ OPJ_BOOL opj_tcd_mct_decode ( opj_tcd_t *p_tcd ) } } else { - /* FIXME need to use opj_event_msg function */ - fprintf(stderr,"Number of components (%d) is inconsistent with a MCT. Skip the MCT step.\n",l_tile->numcomps); + opj_event_msg(p_manager, EVT_ERROR, "Number of components (%d) is inconsistent with a MCT. Skip the MCT step.\n",l_tile->numcomps); } return OPJ_TRUE; } -OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; opj_tcd_tilecomp_t * l_tile_comp = 00; @@ -1698,7 +1765,7 @@ OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) for (j=0;jm_dc_level_shift, l_min, l_max); ; + *l_current_ptr = opj_int_clamp((OPJ_INT32)opj_lrintf(l_value) + l_tccp->m_dc_level_shift, l_min, l_max); ; ++l_current_ptr; } l_current_ptr += l_stride; @@ -1718,7 +1785,7 @@ OPJ_BOOL opj_tcd_dc_level_shift_decode ( opj_tcd_t *p_tcd ) /** * Deallocates the encoding data of the given precinct. */ -void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) +static void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) { OPJ_UINT32 cblkno , l_nb_code_blocks; @@ -1756,7 +1823,7 @@ void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct) /** * Deallocates the encoding data of the given precinct. */ -void opj_tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct) +static void opj_tcd_code_block_enc_deallocate (opj_tcd_precinct_t * p_precinct) { OPJ_UINT32 cblkno , l_nb_code_blocks; @@ -1817,7 +1884,7 @@ OPJ_UINT32 opj_tcd_get_encoded_tile_size ( opj_tcd_t *p_tcd ) return l_data_size; } -OPJ_BOOL opj_tcd_dc_level_shift_encode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_dc_level_shift_encode ( opj_tcd_t *p_tcd ) { OPJ_UINT32 compno; opj_tcd_tilecomp_t * l_tile_comp = 00; @@ -1857,7 +1924,7 @@ OPJ_BOOL opj_tcd_dc_level_shift_encode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -OPJ_BOOL opj_tcd_mct_encode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_mct_encode ( opj_tcd_t *p_tcd ) { opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; @@ -1912,7 +1979,7 @@ OPJ_BOOL opj_tcd_mct_encode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -OPJ_BOOL opj_tcd_dwt_encode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_dwt_encode ( opj_tcd_t *p_tcd ) { opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; @@ -1938,18 +2005,20 @@ OPJ_BOOL opj_tcd_dwt_encode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) +static OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) { opj_t1_t * l_t1; const OPJ_FLOAT64 * l_mct_norms; + OPJ_UINT32 l_mct_numcomps = 0U; opj_tcp_t * l_tcp = p_tcd->tcp; - l_t1 = opj_t1_create(); + l_t1 = opj_t1_create(OPJ_TRUE); if (l_t1 == 00) { return OPJ_FALSE; } if (l_tcp->mct == 1) { + l_mct_numcomps = 3U; /* irreversible encoding */ if (l_tcp->tccps->qmfbid == 0) { l_mct_norms = opj_mct_get_mct_norms_real(); @@ -1959,10 +2028,11 @@ OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) } } else { + l_mct_numcomps = p_tcd->image->numcomps; l_mct_norms = (const OPJ_FLOAT64 *) (l_tcp->mct_norms); } - if (! opj_t1_encode_cblks(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms)) { + if (! opj_t1_encode_cblks(l_t1, p_tcd->tcd_image->tiles , l_tcp, l_mct_norms, l_mct_numcomps)) { opj_t1_destroy(l_t1); return OPJ_FALSE; } @@ -1972,7 +2042,7 @@ OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd ) return OPJ_TRUE; } -OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, +static OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_dest_size, @@ -2010,7 +2080,7 @@ OPJ_BOOL opj_tcd_t2_encode (opj_tcd_t *p_tcd, } -OPJ_BOOL opj_tcd_rate_allocate_encode( opj_tcd_t *p_tcd, +static OPJ_BOOL opj_tcd_rate_allocate_encode( opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 p_max_dest_size, opj_codestream_info_t *p_cstr_info ) diff --git a/src/lib/openjp2/tcd.h b/src/lib/openjp2/tcd.h index 360923b1..07f8379a 100644 --- a/src/lib/openjp2/tcd.h +++ b/src/lib/openjp2/tcd.h @@ -87,15 +87,16 @@ typedef struct opj_tcd_layer { FIXME DOC */ typedef struct opj_tcd_cblk_enc { - OPJ_BYTE* data; /* Data */ - opj_tcd_layer_t* layers; /* layer information */ - opj_tcd_pass_t* passes; /* information about the passes */ - OPJ_INT32 x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_BYTE* data; /* Data */ + opj_tcd_layer_t* layers; /* layer information */ + opj_tcd_pass_t* passes; /* information about the passes */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ OPJ_UINT32 numbps; OPJ_UINT32 numlenbits; - OPJ_UINT32 numpasses; /* number of pass already done for the code-blocks */ - OPJ_UINT32 numpassesinlayers; /* number of passes in the layer */ - OPJ_UINT32 totalpasses; /* total number of passes */ + OPJ_UINT32 data_size; /* Size of allocated data buffer */ + OPJ_UINT32 numpasses; /* number of pass already done for the code-blocks */ + OPJ_UINT32 numpassesinlayers; /* number of passes in the layer */ + OPJ_UINT32 totalpasses; /* total number of passes */ } opj_tcd_cblk_enc_t; @@ -105,7 +106,7 @@ typedef struct opj_tcd_cblk_dec { OPJ_INT32 x0, y0, x1, y1; /* position of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ OPJ_UINT32 numbps; OPJ_UINT32 numlenbits; - OPJ_UINT32 data_max_size; /* Size of allocated data buffer */ + OPJ_UINT32 data_max_size; /* Size of allocated data buffer */ OPJ_UINT32 data_current_size; /* Size of used data buffer */ OPJ_UINT32 numnewpasses; /* number of pass added to the code-blocks */ OPJ_UINT32 numsegs; /* number of segments */ @@ -122,6 +123,7 @@ typedef struct opj_tcd_precinct { union{ /* code-blocks information */ opj_tcd_cblk_enc_t* enc; opj_tcd_cblk_dec_t* dec; + void* blocks; } cblks; OPJ_UINT32 block_size; /* size taken by cblks (in bytes) */ opj_tgt_tree_t *incltree; /* inclusion tree */ @@ -155,14 +157,16 @@ FIXME DOC */ typedef struct opj_tcd_tilecomp { - OPJ_INT32 x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ - OPJ_UINT32 numresolutions; /* number of resolutions level */ - OPJ_UINT32 minimum_num_resolutions; /* number of resolutions level to decode (at max)*/ - opj_tcd_resolution_t *resolutions; /* resolutions information */ - OPJ_UINT32 resolutions_size; /* size of data for resolutions (in bytes) */ - OPJ_INT32 *data; /* data of the component */ - OPJ_UINT32 data_size; /* size of the data of the component */ - OPJ_INT32 numpix; /* add fixed_quality */ + OPJ_INT32 x0, y0, x1, y1; /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ + OPJ_UINT32 numresolutions; /* number of resolutions level */ + OPJ_UINT32 minimum_num_resolutions; /* number of resolutions level to decode (at max)*/ + opj_tcd_resolution_t *resolutions; /* resolutions information */ + OPJ_UINT32 resolutions_size; /* size of data for resolutions (in bytes) */ + OPJ_INT32 *data; /* data of the component */ + OPJ_BOOL ownsData; /* if true, then need to free after usage, otherwise do not free */ + OPJ_UINT32 data_size_needed; /* we may either need to allocate this amount of data, or re-use image data and ignore this value */ + OPJ_UINT32 data_size; /* size of the data of the component */ + OPJ_INT32 numpix; /* add fixed_quality */ } opj_tcd_tilecomp_t; @@ -258,10 +262,11 @@ OPJ_BOOL opj_tcd_init( opj_tcd_t *p_tcd, * @param p_tcd the tile decoder. * @param p_tile_no the index of the tile received in sequence. This not necessarily lead to the * tile at index p_tile_no. + * @param p_manager the event manager. * * @return true if the remaining data is sufficient. */ -OPJ_BOOL opj_tcd_init_decode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no); +OPJ_BOOL opj_tcd_init_decode_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, opj_event_mgr_t* p_manager); void opj_tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno, OPJ_UINT32 final); @@ -291,7 +296,7 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size (opj_tcd_t *p_tcd ); * @param p_data_written pointer to an int that is incremented by the number of bytes really written on p_dest * @param p_len Maximum length of the destination buffer * @param p_cstr_info Codestream information structure - * @return true if the coding is successfull. + * @return true if the coding is successful. */ OPJ_BOOL opj_tcd_encode_tile( opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, @@ -308,12 +313,14 @@ Decode a tile from a buffer into a raw image @param len Length of source buffer @param tileno Number that identifies one of the tiles to be decoded @param cstr_info FIXME DOC +@param manager the event manager. */ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *tcd, OPJ_BYTE *src, OPJ_UINT32 len, OPJ_UINT32 tileno, - opj_codestream_index_t *cstr_info); + opj_codestream_index_t *cstr_info, + opj_event_mgr_t *manager); /** @@ -333,11 +340,12 @@ OPJ_UINT32 opj_tcd_get_encoded_tile_size ( opj_tcd_t *p_tcd ); * * @param p_tcd TCD handle. * @param p_tile_no current tile index to encode. + * @param p_manager the event manager. * * @return true if the encoding values could be set (false otherwise). */ OPJ_BOOL opj_tcd_init_encode_tile ( opj_tcd_t *p_tcd, - OPJ_UINT32 p_tile_no ); + OPJ_UINT32 p_tile_no, opj_event_mgr_t* p_manager ); /** * Copies tile data from the given memory block onto the system. @@ -346,6 +354,13 @@ OPJ_BOOL opj_tcd_copy_tile_data (opj_tcd_t *p_tcd, OPJ_BYTE * p_src, OPJ_UINT32 p_src_length ); +/** + * Allocates tile component data + * + * + */ +OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/src/lib/openjp2/tgt.c b/src/lib/openjp2/tgt.c index e77adb3b..5e34aa91 100644 --- a/src/lib/openjp2/tgt.c +++ b/src/lib/openjp2/tgt.c @@ -45,7 +45,7 @@ ========================================================== */ -opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { +opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv, opj_event_mgr_t *manager) { OPJ_INT32 nplh[32]; OPJ_INT32 nplv[32]; opj_tgt_node_t *node = 00; @@ -57,12 +57,11 @@ opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { OPJ_UINT32 numlvls; OPJ_UINT32 n; - tree = (opj_tgt_tree_t *) opj_malloc(sizeof(opj_tgt_tree_t)); + tree = (opj_tgt_tree_t *) opj_calloc(1,sizeof(opj_tgt_tree_t)); if(!tree) { - fprintf(stderr, "ERROR in tgt_create while allocating tree\n"); + opj_event_msg(manager, EVT_ERROR, "Not enough memory to create Tag-tree\n"); return 00; } - memset(tree,0,sizeof(opj_tgt_tree_t)); tree->numleafsh = numleafsh; tree->numleafsv = numleafsv; @@ -82,17 +81,16 @@ opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { /* ADD */ if (tree->numnodes == 0) { opj_free(tree); - fprintf(stderr, "WARNING in tgt_create tree->numnodes == 0, no tree created.\n"); + opj_event_msg(manager, EVT_WARNING, "tgt_create tree->numnodes == 0, no tree created.\n"); return 00; } tree->nodes = (opj_tgt_node_t*) opj_calloc(tree->numnodes, sizeof(opj_tgt_node_t)); if(!tree->nodes) { - fprintf(stderr, "ERROR in tgt_create while allocating node of the tree\n"); + opj_event_msg(manager, EVT_ERROR, "Not enough memory to create Tag-tree nodes\n"); opj_free(tree); return 00; } - memset(tree->nodes,0,tree->numnodes * sizeof(opj_tgt_node_t)); tree->nodes_size = tree->numnodes * (OPJ_UINT32)sizeof(opj_tgt_node_t); node = tree->nodes; @@ -132,7 +130,7 @@ opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv) { * @param p_num_leafs_v the height of the array of leafs of the tree * @return a new tag-tree if successful, NULL otherwise */ -opj_tgt_tree_t *opj_tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v) +opj_tgt_tree_t *opj_tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, OPJ_UINT32 p_num_leafs_v, opj_event_mgr_t *p_manager) { OPJ_INT32 l_nplh[32]; OPJ_INT32 l_nplv[32]; @@ -177,7 +175,7 @@ opj_tgt_tree_t *opj_tgt_init(opj_tgt_tree_t * p_tree,OPJ_UINT32 p_num_leafs_h, O if (l_node_size > p_tree->nodes_size) { opj_tgt_node_t* new_nodes = (opj_tgt_node_t*) opj_realloc(p_tree->nodes, l_node_size); if (! new_nodes) { - fprintf(stderr, "ERROR Not enough memory to reinitialize the tag tree\n"); + opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to reinitialize the tag tree\n"); opj_tgt_destroy(p_tree); return 00; } diff --git a/src/lib/openjp2/tgt.h b/src/lib/openjp2/tgt.h index 3d152f8a..10223805 100644 --- a/src/lib/openjp2/tgt.h +++ b/src/lib/openjp2/tgt.h @@ -83,7 +83,7 @@ Create a tag-tree @param numleafsv Height of the array of leafs of the tree @return Returns a new tag-tree if successful, returns NULL otherwise */ -opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv); +opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv, opj_event_mgr_t *manager); /** * Reinitialises a tag-tree from an exixting one. @@ -91,11 +91,12 @@ opj_tgt_tree_t *opj_tgt_create(OPJ_UINT32 numleafsh, OPJ_UINT32 numleafsv); * @param p_tree the tree to reinitialize. * @param p_num_leafs_h the width of the array of leafs of the tree * @param p_num_leafs_v the height of the array of leafs of the tree + * @param p_manager the event manager * @return a new tag-tree if successful, NULL otherwise */ opj_tgt_tree_t *opj_tgt_init(opj_tgt_tree_t * p_tree, OPJ_UINT32 p_num_leafs_h, - OPJ_UINT32 p_num_leafs_v); + OPJ_UINT32 p_num_leafs_v, opj_event_mgr_t *p_manager); /** Destroy a tag-tree, liberating memory @param tree Tag-tree to destroy diff --git a/src/lib/openjp3d/CMakeLists.txt b/src/lib/openjp3d/CMakeLists.txt index 8f034ffe..0bbafea3 100644 --- a/src/lib/openjp3d/CMakeLists.txt +++ b/src/lib/openjp3d/CMakeLists.txt @@ -27,6 +27,9 @@ if(UNIX) target_link_libraries(${OPENJP3D_LIBRARY_NAME} m) endif() set_target_properties(${OPENJP3D_LIBRARY_NAME} PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(${OPENJP3D_LIBRARY_NAME} PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS}) +endif() # Install library install(TARGETS ${OPENJP3D_LIBRARY_NAME} diff --git a/src/lib/openjp3d/cio.h b/src/lib/openjp3d/cio.h index 3617dad7..3cfa6fcb 100644 --- a/src/lib/openjp3d/cio.h +++ b/src/lib/openjp3d/cio.h @@ -65,7 +65,7 @@ Write some bytes @param cio CIO handle @param v Value to write @param n Number of bytes to write -@return Returns the number of bytes written or 0 if an error occured +@return Returns the number of bytes written or 0 if an error occurred */ unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n); /** @@ -86,7 +86,7 @@ Write some bytes @param cio CIO handle @param v Signed integer value to write @param n Number of bytes to write -@return Returns the number of bytes written or 0 if an error occured +@return Returns the number of bytes written or 0 if an error occurred */ int cio_write_int(opj_cio_t *cio, int v, int n); /** diff --git a/src/lib/openjp3d/dwt.c b/src/lib/openjp3d/dwt.c index 1558cc3f..a1e4e104 100644 --- a/src/lib/openjp3d/dwt.c +++ b/src/lib/openjp3d/dwt.c @@ -89,12 +89,12 @@ Inverse lazy transform (axial) */ static void dwt_interleave_z(int *a, int *b, int dn, int sn, int xy, int cas); /** -Forward 5-3 wavelet tranform in 1-D +Forward 5-3 wavelet transform in 1-D */ static void dwt_encode_53(int *a, int dn, int sn, int cas); static void dwt_encode_97(int *a, int dn, int sn, int cas); /** -Inverse 5-3 wavelet tranform in 1-D +Inverse 5-3 wavelet transform in 1-D */ static void dwt_decode_53(int *a, int dn, int sn, int cas); static void dwt_decode_97(int *a, int dn, int sn, int cas); @@ -333,7 +333,7 @@ static void dwt_interleave_z(int *a, int *b, int dn, int sn, int xy, int cas) { /* */ -/* Forward 5-3 or 9-7 wavelet tranform in 1-D. */ +/* Forward 5-3 or 9-7 wavelet transform in 1-D. */ /* */ static void dwt_encode_53(int *a, int dn, int sn, int cas) { int i; @@ -409,7 +409,7 @@ static void dwt_encode_97(int *a, int dn, int sn, int cas) { } } /* */ -/* Inverse 5-3 or 9-7 wavelet tranform in 1-D. */ +/* Inverse 5-3 or 9-7 wavelet transform in 1-D. */ /* */ static void dwt_decode_53(int *a, int dn, int sn, int cas) { int i; @@ -661,7 +661,7 @@ static void dwt_encode_stepsize(int stepsize, int numbps, opj_stepsize_t *bandno ========================================================== */ /* */ -/* Forward 5-3 wavelet tranform in 3-D. */ +/* Forward 5-3 wavelet transform in 3-D. */ /* */ void dwt_encode(opj_tcd_tilecomp_t * tilec, int dwtid[3]) { int i, j, k; @@ -792,7 +792,7 @@ void dwt_encode(opj_tcd_tilecomp_t * tilec, int dwtid[3]) { /* */ -/* Inverse 5-3 wavelet tranform in 3-D. */ +/* Inverse 5-3 wavelet transform in 3-D. */ /* */ void dwt_decode(opj_tcd_tilecomp_t * tilec, int stops[3], int dwtid[3]) { int i, j, k; diff --git a/src/lib/openjp3d/dwt.h b/src/lib/openjp3d/dwt.h index 5c3f6847..00082900 100644 --- a/src/lib/openjp3d/dwt.h +++ b/src/lib/openjp3d/dwt.h @@ -63,14 +63,14 @@ typedef struct opj_wtfilt { /*@{*/ /* ----------------------------------------------------------------------- */ /** -Forward 5-3 wavelet tranform in 3-D. +Forward 5-3 wavelet transform in 3-D. Apply a reversible DWT transform to a component of an volume. @param tilec Tile component information (current tile) @param dwtid Number of identification of wavelet kernel(s) used in DWT in each direction */ void dwt_encode(opj_tcd_tilecomp_t * tilec, int dwtid[3]); /** -Inverse 5-3 wavelet tranform in 3-D. +Inverse 5-3 wavelet transform in 3-D. Apply a reversible inverse DWT transform to a component of an volume. @param tilec Tile component information (current tile) @param stops Number of decoded resolution levels in each dimension diff --git a/src/lib/openjp3d/jp3d.c b/src/lib/openjp3d/jp3d.c index f445fb36..9e060df7 100644 --- a/src/lib/openjp3d/jp3d.c +++ b/src/lib/openjp3d/jp3d.c @@ -1008,6 +1008,7 @@ static void j3d_write_qcx(opj_j3d_t *j3d, int compno) { cio_write(cio, tccp->qntsty + (tccp->numgbits << 5), 1); /* Sqcx : Table A28 de 15444-1*/ + numbands = 0; // compiler warning if (j3d->cinfo->codec_format == CODEC_J2K) numbands = tccp->qntsty == J3D_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolution[0] * 3 - 2; else if (j3d->cinfo->codec_format == CODEC_J3D) { diff --git a/src/lib/openjp3d/mct.c b/src/lib/openjp3d/mct.c index 5759047b..685a9f88 100644 --- a/src/lib/openjp3d/mct.c +++ b/src/lib/openjp3d/mct.c @@ -46,7 +46,7 @@ static const double mct_norms[3] = { 1.732, .8292, .8292 }; static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; /* */ -/* Foward reversible MCT. */ +/* Forward reversible MCT. */ /* */ void mct_encode(int *c0, int *c1, int *c2, int n) { int i; @@ -91,7 +91,7 @@ double mct_getnorm(int compno) { } /* */ -/* Foward irreversible MCT. */ +/* Forward irreversible MCT. */ /* */ void mct_encode_real(int *c0, int *c1, int *c2, int n) { int i; diff --git a/src/lib/openjp3d/openjp3d.h b/src/lib/openjp3d/openjp3d.h index ae2507c0..a720bd37 100644 --- a/src/lib/openjp3d/openjp3d.h +++ b/src/lib/openjp3d/openjp3d.h @@ -60,7 +60,7 @@ The following ifdef block is the standard way of creating macros which make expo from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS symbol defined on the command line. this symbol should not be defined on any project that uses this DLL. This way any other project whose source files include this file see -OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +OPJ_API functions as being imported from a DLL, whereas this DLL sees symbols defined with this macro as being exported. */ #if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) diff --git a/src/lib/openjp3d/pi.h b/src/lib/openjp3d/pi.h index b3f287a3..c81f9ef0 100644 --- a/src/lib/openjp3d/pi.h +++ b/src/lib/openjp3d/pi.h @@ -82,7 +82,7 @@ typedef struct opj_pi_comp { Packet iterator */ typedef struct opj_pi_iterator { -/** precise if the packet has been already used (usefull for progression order change) */ +/** precise if the packet has been already used (useful for progression order change) */ short int *include; /** layer step used to localize the packet in the include vector */ int step_l; diff --git a/src/lib/openjp3d/tcd.c b/src/lib/openjp3d/tcd.c index 0c662ce8..1d0d0f52 100644 --- a/src/lib/openjp3d/tcd.c +++ b/src/lib/openjp3d/tcd.c @@ -1601,7 +1601,7 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno) { if (l == -999) { eof = 1; - opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bistream\n"); + opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bitstream\n"); } /*------------------TIER1-----------------*/ @@ -1631,7 +1631,7 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno) { golomb_destroy(gr); if (l == -999) { eof = 1; - opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bistream\n"); + opj_event_msg(tcd->cinfo, EVT_ERROR, "Tcd_decode_tile: incomplete bitstream\n"); } */ } diff --git a/src/lib/openjpip/CMakeLists.txt b/src/lib/openjpip/CMakeLists.txt index c149ef3f..858a1095 100644 --- a/src/lib/openjpip/CMakeLists.txt +++ b/src/lib/openjpip/CMakeLists.txt @@ -61,6 +61,9 @@ endif() add_library(openjpip ${OPENJPIP_SRCS} ${LOCAL_SRCS}) set_target_properties(openjpip PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(openjpip PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS}) +endif() target_link_libraries(openjpip ${OPENJPEG_LIBRARY_NAME}) if(WIN32) # add Winsock on windows+mingw diff --git a/src/lib/openjpip/cachemodel_manager.h b/src/lib/openjpip/cachemodel_manager.h index ac54026d..041f1ad9 100644 --- a/src/lib/openjpip/cachemodel_manager.h +++ b/src/lib/openjpip/cachemodel_manager.h @@ -80,7 +80,7 @@ void print_cachemodel( cachemodel_param_t cachemodel); /** * search a cache model of a target * - * @param[in] target refering target + * @param[in] target referring target * @param[in] cachemodellist cache model list * @return found cache model pointer */ diff --git a/src/lib/openjpip/imgsock_manager.c b/src/lib/openjpip/imgsock_manager.c index 10e997b1..4337e608 100644 --- a/src/lib/openjpip/imgsock_manager.c +++ b/src/lib/openjpip/imgsock_manager.c @@ -181,19 +181,19 @@ void send_PNMstream( SOCKET connected_socket, Byte_t *pnmstream, unsigned int wi void send_SIZstream( SOCKET connected_socket, unsigned int width, unsigned int height) { - Byte_t responce[9]; + Byte_t response[9]; - responce[0] = 'S'; - responce[1] = 'I'; - responce[2] = 'Z'; - responce[3] = (width >> 16) & 0xff; - responce[4] = (width >> 8) & 0xff; - responce[5] = width & 0xff; - responce[6] = (height >> 16) & 0xff; - responce[7] = (height >> 8) & 0xff; - responce[8] = height & 0xff; + response[0] = 'S'; + response[1] = 'I'; + response[2] = 'Z'; + response[3] = (width >> 16) & 0xff; + response[4] = (width >> 8) & 0xff; + response[5] = width & 0xff; + response[6] = (height >> 16) & 0xff; + response[7] = (height >> 8) & 0xff; + response[8] = height & 0xff; - send_stream( connected_socket, responce, 9); + send_stream( connected_socket, response, 9); } void response_signal( SOCKET connected_socket, OPJ_BOOL succeed) diff --git a/src/lib/openjpip/jpip_parser.c b/src/lib/openjpip/jpip_parser.c index c206662d..d44c84c8 100644 --- a/src/lib/openjpip/jpip_parser.c +++ b/src/lib/openjpip/jpip_parser.c @@ -357,7 +357,7 @@ void enqueue_precincts( int xmin, int xmax, int ymin, int ymax, int tile_id, int Byte4_t xminP, xmaxP, yminP, ymaxP; codeidx = msgqueue->cachemodel->target->codeidx; - /* MM: shouldnt xmin/xmax be Byte4_t instead ? */ + /* MM: shouldn't xmin/xmax be Byte4_t instead ? */ if( xmin < 0 || xmax < 0 || ymin < 0 || ymax < 0) return; /* MM: I think the API should not really be int should it ? */ diff --git a/src/lib/openjpip/target_manager.h b/src/lib/openjpip/target_manager.h index 4ed99a79..561510f5 100644 --- a/src/lib/openjpip/target_manager.h +++ b/src/lib/openjpip/target_manager.h @@ -46,7 +46,7 @@ typedef struct target_param{ #endif int csn; /**< codestream number */ index_param_t *codeidx; /**< index information of codestream */ - int num_of_use; /**< numbers of sessions refering to this target */ + int num_of_use; /**< numbers of sessions referring to this target */ OPJ_BOOL jppstream; /**< if this target can return JPP-stream */ OPJ_BOOL jptstream; /**< if this target can return JPP-stream */ struct target_param *next; /**< pointer to the next target */ diff --git a/src/lib/openjpwl/CMakeLists.txt b/src/lib/openjpwl/CMakeLists.txt index 616edf58..9e2ace75 100644 --- a/src/lib/openjpwl/CMakeLists.txt +++ b/src/lib/openjpwl/CMakeLists.txt @@ -51,6 +51,9 @@ if(UNIX) endif() set_target_properties(openjpwl PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(openjpwl PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS}) +endif() # Install library install(TARGETS openjpwl diff --git a/src/lib/openjpwl/jpwl.c b/src/lib/openjpwl/jpwl.c index 79d0e04c..99a34990 100644 --- a/src/lib/openjpwl/jpwl.c +++ b/src/lib/openjpwl/jpwl.c @@ -1296,7 +1296,7 @@ opj_bool jpwl_check_tile(opj_j2k_t *j2k, opj_tcd_t *tcd, int tileno) { opj_event_msg(j2k->cinfo, JPWL_ASSUME ? EVT_WARNING : EVT_ERROR, "JPWL: wrong x-cord of block origin %d => x-prec is (%d, %d)\n", block->x0, prec->x0, prec->x1); - if (!JPWL_ASSUME || JPWL_ASSUME) + if (!JPWL_ASSUME) return OPJ_FALSE; }; } diff --git a/src/lib/openjpwl/jpwl.h b/src/lib/openjpwl/jpwl.h index 748a6b38..ca0ee0a1 100644 --- a/src/lib/openjpwl/jpwl.h +++ b/src/lib/openjpwl/jpwl.h @@ -357,7 +357,7 @@ opj_bool jpwl_correct(opj_j2k_t *j2k); @param post_len length of post_data @param conn is a pointer to the length of all connected (packed) EPBs @param L4_bufp is a pointer to the buffer pointer of redundancy data -@return returns true if correction could be succesfully performed +@return returns true if correction could be successfully performed */ opj_bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn, unsigned char **L4_bufp); diff --git a/src/lib/openjpwl/rs.c b/src/lib/openjpwl/rs.c index e35781f6..a0bd7c71 100644 --- a/src/lib/openjpwl/rs.c +++ b/src/lib/openjpwl/rs.c @@ -225,7 +225,7 @@ void init_rs(int k) of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for example the polynomial representation of @^5 would be given by the binary representation of the integer "alpha_to[5]". - Similarily, index_of[] can be used as follows: + Similarly, index_of[] can be used as follows: As above, let @ represent the primitive element of GF(2^m) that is the root of the primitive polynomial p(x). In order to find the power of @ (alpha) that has the polynomial representation @@ -237,7 +237,7 @@ void init_rs(int k) NOTE: The element alpha_to[2^m-1] = 0 always signifying that the representation of "@^infinity" = 0 is (0,0,0,...,0). - Similarily, the element index_of[0] = A0 always signifying + Similarly, the element index_of[0] = A0 always signifying that the power of alpha which has the polynomial representation (0,0,...,0) is "infinity". diff --git a/src/lib/openmj2/CMakeLists.txt b/src/lib/openmj2/CMakeLists.txt index 775c9318..dbb7e7ce 100644 --- a/src/lib/openmj2/CMakeLists.txt +++ b/src/lib/openmj2/CMakeLists.txt @@ -46,6 +46,9 @@ if(UNIX) target_link_libraries(${OPENMJ2_LIBRARY_NAME} m) endif() set_target_properties(${OPENMJ2_LIBRARY_NAME} PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES}) +if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(${OPENMJ2_LIBRARY_NAME} PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS}) +endif() # Install library install(TARGETS ${OPENMJ2_LIBRARY_NAME} diff --git a/src/lib/openmj2/cio.h b/src/lib/openmj2/cio.h index f389d4e2..3cae708e 100644 --- a/src/lib/openmj2/cio.h +++ b/src/lib/openmj2/cio.h @@ -74,7 +74,7 @@ Write some bytes @param cio CIO handle @param v Value to write @param n Number of bytes to write -@return Returns the number of bytes written or 0 if an error occured +@return Returns the number of bytes written or 0 if an error occurred */ OPJ_API unsigned int OPJ_CALLCONV cio_write(opj_cio_t *cio, unsigned int64 v, int n); /** diff --git a/src/lib/openmj2/dwt.h b/src/lib/openmj2/dwt.h index 3cb3b209..5b9645bf 100644 --- a/src/lib/openmj2/dwt.h +++ b/src/lib/openmj2/dwt.h @@ -54,13 +54,13 @@ DWT.C are used by some function in TCD.C. /*@{*/ /* ----------------------------------------------------------------------- */ /** -Forward 5-3 wavelet tranform in 2-D. +Forward 5-3 wavelet transform in 2-D. Apply a reversible DWT transform to a component of an image. @param tilec Tile component information (current tile) */ void dwt_encode(opj_tcd_tilecomp_t * tilec); /** -Inverse 5-3 wavelet tranform in 2-D. +Inverse 5-3 wavelet transform in 2-D. Apply a reversible inverse DWT transform to a component of an image. @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode diff --git a/src/lib/openmj2/jp2.h b/src/lib/openmj2/jp2.h index f1b9c0d3..fbd17a4d 100644 --- a/src/lib/openmj2/jp2.h +++ b/src/lib/openmj2/jp2.h @@ -58,7 +58,7 @@ /* ----------------------------------------------------------------------- */ /** -Channel description: channel index, type, assocation +Channel description: channel index, type, association */ typedef struct opj_jp2_cdef_info { diff --git a/src/lib/openmj2/mct.c b/src/lib/openmj2/mct.c index e507a781..0f926194 100644 --- a/src/lib/openmj2/mct.c +++ b/src/lib/openmj2/mct.c @@ -52,7 +52,7 @@ static const double mct_norms[3] = { 1.732, .8292, .8292 }; static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; /* */ -/* Foward reversible MCT. */ +/* Forward reversible MCT. */ /* */ void mct_encode( int* restrict c0, @@ -105,7 +105,7 @@ double mct_getnorm(int compno) { } /* */ -/* Foward irreversible MCT. */ +/* Forward irreversible MCT. */ /* */ void mct_encode_real( int* restrict c0, diff --git a/src/lib/openmj2/mj2.h b/src/lib/openmj2/mj2.h index 611e6350..8761111f 100644 --- a/src/lib/openmj2/mj2.h +++ b/src/lib/openmj2/mj2.h @@ -378,7 +378,7 @@ Read the structure of an MJ2 file */ OPJ_API int OPJ_CALLCONV mj2_read_struct(FILE *file, opj_mj2_t *mj2); /** -Write the the MOOV box to an output buffer stream +Write the MOOV box to an output buffer stream @param movie MJ2 movie structure @param cio Output buffer stream */ diff --git a/src/lib/openmj2/openjpeg.h b/src/lib/openmj2/openjpeg.h index f765fc2c..132ec2fd 100644 --- a/src/lib/openmj2/openjpeg.h +++ b/src/lib/openmj2/openjpeg.h @@ -62,7 +62,7 @@ The following ifdef block is the standard way of creating macros which make expo from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS symbol defined on the command line. this symbol should not be defined on any project that uses this DLL. This way any other project whose source files include this file see -OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +OPJ_API functions as being imported from a DLL, whereas this DLL sees symbols defined with this macro as being exported. */ #if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) diff --git a/src/lib/openmj2/opj_malloc.h b/src/lib/openmj2/opj_malloc.h index 9e4af234..1b62ab02 100644 --- a/src/lib/openmj2/opj_malloc.h +++ b/src/lib/openmj2/opj_malloc.h @@ -64,7 +64,7 @@ void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements); #endif /** -Allocate memory aligned to a 16 byte boundry +Allocate memory aligned to a 16 byte boundary @param size Bytes to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ diff --git a/src/lib/openmj2/pi.h b/src/lib/openmj2/pi.h index fa0d08ab..7f2fe3ef 100644 --- a/src/lib/openmj2/pi.h +++ b/src/lib/openmj2/pi.h @@ -73,7 +73,7 @@ Packet iterator typedef struct opj_pi_iterator { /** Enabling Tile part generation*/ char tp_on; - /** precise if the packet has been already used (usefull for progression order change) */ + /** precise if the packet has been already used (useful for progression order change) */ short int *include; /** layer step used to localize the packet in the include vector */ int step_l; diff --git a/src/lib/openmj2/tcd.c b/src/lib/openmj2/tcd.c index 5eb5f4bb..7875737c 100644 --- a/src/lib/openmj2/tcd.c +++ b/src/lib/openmj2/tcd.c @@ -1386,7 +1386,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno if (l == -999) { eof = 1; - opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bistream\n"); + opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bitstream\n"); } /*------------------TIER1-----------------*/ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 64f63e83..ee39de8e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,7 @@ include_directories( # First thing define the common source: set(compare_images_SRCS compare_images.c ${OPENJPEG_SOURCE_DIR}/src/bin/jp2/convert.c + ${OPENJPEG_SOURCE_DIR}/src/bin/jp2/converttif.c ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c ) diff --git a/tests/compare_images.c b/tests/compare_images.c index cb1b1301..b28d4957 100644 --- a/tests/compare_images.c +++ b/tests/compare_images.c @@ -85,7 +85,7 @@ static void compare_images_help_display(void) fprintf(stdout,"\n"); fprintf(stdout," -b \t REQUIRED \t filename to the reference/baseline PGX/TIF/PNM image \n"); fprintf(stdout," -t \t REQUIRED \t filename to the test PGX/TIF/PNM image\n"); - fprintf(stdout," -n \t REQUIRED \t number of component of the image (used to generate correct filename)\n"); + fprintf(stdout," -n \t REQUIRED \t number of component of the image (used to generate correct filename, not used when both input files are TIF)\n"); fprintf(stdout," -m \t OPTIONAL \t list of MSE tolerances, separated by : (size must correspond to the number of component) of \n"); fprintf(stdout," -p \t OPTIONAL \t list of PEAK tolerances, separated by : (size must correspond to the number of component) \n"); fprintf(stdout," -s \t OPTIONAL \t 1 or 2 filename separator to take into account PGX/PNM image with different components, " @@ -279,8 +279,6 @@ static opj_image_t* readImageFromFileTIF(const char* filename, int nbFilenamePGX return NULL; } - /* \postconditions */ - assert( image_read->numcomps == 1 || image_read->numcomps == 3 ); return image_read; } diff --git a/tests/compare_raw_files.c b/tests/compare_raw_files.c index e7ab8c94..01b2122d 100644 --- a/tests/compare_raw_files.c +++ b/tests/compare_raw_files.c @@ -120,14 +120,14 @@ int main(int argc, char **argv) int pos = 0; test_cmp_parameters inParam; FILE *file_test=NULL, *file_base=NULL; - unsigned char equal = 1; + unsigned char equal = 0U; /* returns error by default */ /* Get parameters from command line*/ if (parse_cmdline_cmp(argc, argv, &inParam)) - { + { compare_raw_files_help_display(); goto cleanup; - } + } file_test = fopen(inParam.test_filename, "rb"); if (!file_test) { @@ -142,8 +142,9 @@ int main(int argc, char **argv) } /* Read simultaneously the two files*/ + equal = 1U; while (equal) - { + { unsigned char value_test = 0; unsigned char eof_test = 0; unsigned char value_base = 0; @@ -165,19 +166,19 @@ int main(int argc, char **argv) /* End of file reached only by one file?*/ if (eof_test || eof_base) - { + { fprintf(stdout,"Files have different sizes.\n"); equal = 0; - } + } /* Binary values are equal?*/ if (value_test != value_base) - { + { fprintf(stdout,"Binary values read in the file are different %x vs %x at position %d.\n", value_test, value_base, pos); equal = 0; - } - pos++; } + pos++; + } if(equal) fprintf(stdout,"---- TEST SUCCEED: Files are equal ----\n"); cleanup: diff --git a/tests/conformance/CMakeLists.txt b/tests/conformance/CMakeLists.txt index 0b2ed0a0..3a07dbc4 100644 --- a/tests/conformance/CMakeLists.txt +++ b/tests/conformance/CMakeLists.txt @@ -439,6 +439,8 @@ foreach(numFileJP2 RANGE 1 9) COMMAND opj_decompress -i ${INPUT_CONF}/${filenameInput} -o ${TEMP}/${filenameInput}.tif + -p 8S + -force-rgb ) add_test(NAME ETS-JP2-${filenameInput}-compare2ref @@ -508,10 +510,17 @@ foreach(kdu_file ${kdu_j2k_conf_files}) set( filenameInput "${kdu_file}.j2c" ) set( filenameRef "${kdu_file}.ppm" ) + if("${kdu_file}" STREQUAL "a6_mono_colr") + set(kdu_test_args -upsample -split-pnm ) + else() + set(kdu_test_args -upsample ) + endif() + add_test(NAME ETS-KDU-${filenameInput}-decode COMMAND opj_decompress -i ${INPUT_CONF}/${filenameInput} -o ${TEMP}/${filenameInput}.ppm + ${kdu_test_args} ) if("${kdu_file}" STREQUAL "a6_mono_colr") diff --git a/tests/nonregression/CMakeLists.txt b/tests/nonregression/CMakeLists.txt index 175c3d16..ce95af87 100644 --- a/tests/nonregression/CMakeLists.txt +++ b/tests/nonregression/CMakeLists.txt @@ -1,5 +1,7 @@ # NON-REGRESSION TESTS ON THIS DATASET LOCATED ${OPJ_DATA_ROOT}/input/nonregression +cmake_minimum_required(VERSION 2.8.7) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Temporary) set(TEMP ${CMAKE_CURRENT_BINARY_DIR}/Temporary) @@ -13,6 +15,8 @@ set(INPUT_CONF_PATH ${OPJ_DATA_ROOT}/input/conformance) # need kdu_expand if possible find_package(KAKADU) +# need jpylyzer if possible +find_package(JPYLYZER) ######################################################################### # GENERATION OF THE TEST SUITE (DUMP) @@ -42,12 +46,15 @@ set(BLACKLIST_JPEG2000_TMP edf_c2_101463.jp2 edf_c2_1674177.jp2 edf_c2_1673169.jp2 + issue429.jp2 + issue427-null-image-size.jp2 + issue427-illegal-tile-offset.jp2 ) # Define a list of file which should be gracefully rejected: set(BLACKLIST_JPEG2000 ${BLACKLIST_JPEG2000_TMP} - broken.jp2 + broken1.jp2 broken2.jp2 broken3.jp2 broken4.jp2 @@ -57,6 +64,21 @@ set(BLACKLIST_JPEG2000 gdal_fuzzer_unchecked_numresolutions.jp2 mem-b2ace68c-1381.jp2 1851.pdf.SIGSEGV.ce9.948.jp2 + 1888.pdf.asan.35.988.jp2 + issue362-2863.jp2 #kdu_jp2info ok + issue362-2866.jp2 + issue362-2894.jp2 + issue400.jp2 #kdu_jp2info ok + issue364-38.jp2 + issue364-903.jp2 #kdu_jp2info ok + issue393.jp2 #kdu_jp2info ok + issue408.jp2 #kdu_jp2info ok + issue420.jp2 #kdu_jp2info ok + 27ac957758a35d00d6765a0c86350d9c.SIGFPE.d25.537.jpc #kdu_jp2info crash + 3672da2f1f67bbecad27d7181b4e9d7c.SIGFPE.d25.805.jpc #kdu_jp2info crash + issue476.jp2 #kdu_jp2info ok + issue475.jp2 #kdu_jp2info ok + issue413.jp2 #kdu_jp2info ok ) file(GLOB_RECURSE OPJ_DATA_NR_LIST @@ -317,6 +339,40 @@ foreach(OPJ_TEST_CMD_LINE ${OPJ_TEST_CMD_LINE_LIST}) NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref) endif() + + # Test the encoded file is a valid JP2 file + if (JPYLYZER_EXECUTABLE) + if (${OUTPUT_FILENAME} MATCHES "\\.jp2$") + add_test(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-jpylyser + COMMAND ${JPYLYZER_EXECUTABLE} + ${OUTPUT_FILENAME} + ) + set_tests_properties(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-jpylyser PROPERTIES + DEPENDS NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode + PASS_REGULAR_EXPRESSION "True" + ) + endif() + endif(JPYLYZER_EXECUTABLE) + + # If lossless compression (simple test is 4 arguments), decompress & compare + list(LENGTH CMD_ARG_LIST_2 ARG_COUNT) + if (ARG_COUNT EQUAL 4) + # can we compare with the input image ? + if (${INPUT_FILENAME_NAME} MATCHES "\\.tif$") + add_test(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-lossless-decode + COMMAND opj_decompress -i ${OUTPUT_FILENAME} -o ${OUTPUT_FILENAME}.lossless.tif + ) + set_tests_properties(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-lossless-decode PROPERTIES + DEPENDS NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode + ) + add_test(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-lossless-compare + COMMAND compare_images -b ${INPUT_FILENAME} -t ${OUTPUT_FILENAME}.lossless.tif -n 1 -d + ) + set_tests_properties(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-lossless-compare PROPERTIES + DEPENDS NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-lossless-decode + ) + endif() + endif() endif() # DECODER TEST SUITE @@ -349,7 +405,7 @@ foreach(OPJ_TEST_CMD_LINE ${OPJ_TEST_CMD_LINE_LIST}) ) # FIXME: add a compare2base function base on raw which -# can output png diff files if necesary +# can output png diff files if necessary # add_test(NR-${filename}-compare2base # ${EXECUTABLE_OUTPUT_PATH}/compare_images # -b ${BASELINE_NR}/opj_${filenameRef} diff --git a/tests/nonregression/checkmd5refs.cmake b/tests/nonregression/checkmd5refs.cmake index d6198af0..40e019b7 100644 --- a/tests/nonregression/checkmd5refs.cmake +++ b/tests/nonregression/checkmd5refs.cmake @@ -32,7 +32,7 @@ get_filename_component(OUTFILENAME_NAME ${OUTFILENAME} NAME) string(FIND ${OUTFILENAME_NAME} "." SHORTEST_EXT_POS REVERSE) string(SUBSTRING ${OUTFILENAME_NAME} 0 ${SHORTEST_EXT_POS} OUTFILENAME_NAME_WE) -file(GLOB globfiles "Temporary/${OUTFILENAME_NAME_WE}*.pgx" "Temporary/${OUTFILENAME_NAME_WE}*.png") +file(GLOB globfiles "Temporary/${OUTFILENAME_NAME_WE}*.pgx" "Temporary/${OUTFILENAME_NAME_WE}*.png" "Temporary/${OUTFILENAME_NAME_WE}*.tif") if(NOT globfiles) message(SEND_ERROR "Could not find output PGX files: ${OUTFILENAME_NAME_WE}") endif() @@ -41,22 +41,12 @@ endif() file(READ ${REFFILE} variable) foreach(pgxfullpath ${globfiles}) + file(MD5 ${pgxfullpath} output) get_filename_component(pgxfile ${pgxfullpath} NAME) - execute_process( - COMMAND ${CMAKE_COMMAND} -E md5sum ${pgxfile} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Temporary - RESULT_VARIABLE res - OUTPUT_VARIABLE output - ERROR_VARIABLE error_output - OUTPUT_STRIP_TRAILING_WHITESPACE # important - ) - - # Pass the output back to ctest - if(res) - message(SEND_ERROR "md5 could not be computed, it failed with value ${res}. Output was: ${error_output}") - endif() string(REGEX MATCH "[0-9a-f]+ ${pgxfile}" output_var "${variable}") + + set(output "${output} ${pgxfile}") if("${output_var}" STREQUAL "${output}") message(STATUS "equal: [${output_var}] vs [${output}]") diff --git a/tests/nonregression/md5refs.txt b/tests/nonregression/md5refs.txt index f52bed61..499441c0 100644 --- a/tests/nonregression/md5refs.txt +++ b/tests/nonregression/md5refs.txt @@ -24,32 +24,30 @@ c6091c07bf0ff221008dfb60d893cdff issue134.jp2_2.pgx cccccccccccccccccccccccccccccccc issue135.j2k_0.pgx cccccccccccccccccccccccccccccccc issue135.j2k_1.pgx cccccccccccccccccccccccccccccccc issue135.j2k_2.pgx -619694e5674992b3286244bf13058f7c issue142.j2k_0.pgx -c675c4b77dc3cc2a0d6542a32b438a48 issue142.j2k_1.pgx -663ebdd12dd6a36915ea1152c43cb69a issue142.j2k_2.pgx +aa7461b31e14641586803b23b7fb04f2 issue142.j2k_0.pgx +a809006e7a0c1eed68bc86c96af43fe3 issue142.j2k_1.pgx +74f7a7a194a74a947245b843c62c4054 issue142.j2k_2.pgx c44662b1f7fe01caa2ebf3ad62948e3e issue171.jp2_0.pgx f70e8a4e5dbefeb44d50edd79b6c4cf6 issue171.jp2_1.pgx 18bc167a1c851db2fd9f8c7af3289134 issue171.jp2_2.pgx adda4f5e46845b96dd3df14a76aa7229 issue188_beach_64bitsbox.jp2_0.pgx 90a9709c166019d1e101e7b96d257ed9 issue188_beach_64bitsbox.jp2_1.pgx 37e23d2df06ee60bf0f9f5e1c16054d8 issue188_beach_64bitsbox.jp2_2.pgx -cb89739232898a823355861d834b5734 issue205.jp2_0.pgx -a09d34928fd86e6f2d7e6edc1764d2b7 issue205.jp2_1.pgx -6f712d0685f2c5522f01b238365f4284 issue205.jp2_2.pgx -de992d54d59032eb07d21983dbe8155b issue205.jp2_3.pgx -8fae7a39e459409f64e4529d2214087a issue206_image-000.jp2_0.pgx -555a504a93c9a14f61c894da3b393e87 issue206_image-000.jp2_1.pgx -5f06b7c45446ae20c22cada46478a9dc issue206_image-000.jp2_2.pgx -8c0025fe9ffbff839e7735c18f56f596 issue208.jp2_0.pgx -285fedd7e5e92624177d00eaa543e551 issue208.jp2_1.pgx -bc5178a807be5901938d7f555275933f issue208.jp2_2.pgx -37546d44ecf7f2ea40a4f25d177910f3 issue208.jp2_3.pgx +4507d80b4133fc8d8f84beca949dbca5 issue205.jp2_0.pgx +697b6a4b1a7eea09110a029fa28cf51e issue205.jp2_1.pgx +911a6e6b3dec0fa7c5dd821f92dd707f issue205.jp2_2.pgx +1a507a95237768e41cd0987ad0f134f4 issue206_image-000.jp2_0.pgx +dacea42ff8bb859504820100637de2b6 issue206_image-000.jp2_1.pgx +1831abb207d2c85e9b8d4da308144213 issue206_image-000.jp2_2.pgx +6e40cbf1dbf7db68ff7975a7a99362b9 issue208.jp2_0.pgx +822f330a38c053130c707cadd31d3b41 issue208.jp2_1.pgx +60316fb101af743c0f3e24924365b178 issue208.jp2_2.pgx a0823d21d9de699353a3bd1adb23bd1c issue211.jp2_0.pgx 1820161df26c360a62d11800d6cf173f issue211.jp2_1.pgx e1807db57b5f5192c4b77b83e8b5c477 issue228.j2k_0.pgx -cccccccccccccccccccccccccccccccc issue254.jp2_0.pgx -cccccccccccccccccccccccccccccccc issue254.jp2_1.pgx -cccccccccccccccccccccccccccccccc issue254.jp2_2.pgx +e58242abc2c6d44df187397c55e6fbff issue254.jp2_0.pgx +e58242abc2c6d44df187397c55e6fbff issue254.jp2_1.pgx +e58242abc2c6d44df187397c55e6fbff issue254.jp2_2.pgx 4093cc34d838780b35a8be410247fa7f j2k32.j2k_0.pgx ce4e556aaa0844b92a92c35c200fc43e j2k32.j2k_1.pgx ea926520f990640862f3fe6616097613 j2k32.j2k_2.pgx @@ -57,12 +55,15 @@ ea926520f990640862f3fe6616097613 j2k32.j2k_2.pgx 12a8a4668315d9ae27969991251ce85f kodak_2layers_lrcp.j2c_0.pgx 56d0b0c547d6d5bb12f0c36e88722b11 kodak_2layers_lrcp.j2c_1.pgx 48ba092fb40090c160bbd08bdf7bdbf2 kodak_2layers_lrcp.j2c_2.pgx +12a8a4668315d9ae27969991251ce85f kodak_2layers_lrcp-l2.j2c_0.pgx +56d0b0c547d6d5bb12f0c36e88722b11 kodak_2layers_lrcp-l2.j2c_1.pgx +48ba092fb40090c160bbd08bdf7bdbf2 kodak_2layers_lrcp-l2.j2c_2.pgx 05c062aca83d13b8095460f38a690a08 MarkerIsNotCompliant.j2k_0.pgx ff73d2bd32951d9e55b02186aac24aff Marrin.jp2_0.pgx 55ce884dd2346af6a5172a434ee578fa Marrin.jp2_1.pgx -41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_0.pgx -41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_1.pgx -41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_2.pgx +9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_0.pgx +9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_1.pgx +9271a64c96094765a8168f9610aabc8b mem-b2b86b74-2753.jp2_2.pgx 97557ab9e38a7aff621e583fbb66b099 merged.jp2_0.pgx 386fbdcd294429733e3272d62ed5a15a merged.jp2_1.pgx d3907bbd67be1dae31b4377fa4dc0373 merged.jp2_2.pgx @@ -91,63 +92,181 @@ fdad26b1e078aa32bd4b77a5f44da43c orb-blue10-lin-jp2.jp2_2.pgx 7442756e83571c0e87493e03f12b2d34 orb-blue10-win-jp2.jp2_1.pgx 5f99ff2aeb17e167fe7049bcf339d0b3 orb-blue10-win-jp2.jp2_2.pgx fe028d56d6c7aaee87239a115093412a orb-blue10-win-jp2.jp2_3.pgx -dc78dd4b7739c92cd5291b043cc232ed p0_04_1.j2k.png -e157ce3ec092931d48cdaf275180ed34 p0_04_2.j2k.png -0f0a9b3b8b41f2afaf5d80bf2f36f68c p0_04_3.j2k.png -f78b09250d08365b836654f717ec798c p0_04_4.j2k.png -d7243f4004a30d8856ef4dfa0b9f4bc8 p0_04_5.j2k.png -344233bbe643ad651f82d4e8aaa3be54 p0_04_6_1.j2k.png -d105747d8fb755ef18b37ef83832f7d3 p0_04_6_2.j2k.png -89000c4cb8a83fcb4166624055905258 p0_04_6_3.j2k.png -af2a3ce7be9c8fb2db66ddbceff1dd53 p0_04_6_4.j2k.png -757340902e8dc6d5baa4f8f4628e2bc4 p0_04_6_5.j2k.png -4ec7002317a835f71630a7787cbff30a p0_04_6.j2k.png -d7ed089096806af2f1bf687e1adb427f p0_04.j2k.png -4fecc6d5ebdc2db3bf3ef6bbbbb5b031 p1_04_10.j2k.png -ab969b1d17341d062a6f4d6966a1f221 p1_04_11.j2k.png -70fd9d6f155585258b13cb4b6c469e3f p1_04_12.j2k.png -38f9113129eed30445266dd67ac8ad7d p1_04_13.j2k.png -92945201639e6d8718dc474058f63e45 p1_04_14.j2k.png -bf7b8807d1617b8baa1cbd11af727061 p1_04_15.j2k.png -22afbf50bda7cd1ad562e6c0601c759a p1_04_16.j2k.png -d41f829c40140ec9972edf86681ee53a p1_04_17_t63.j2k.png -70fd9d6f155585258b13cb4b6c469e3f p1_04_17_t63_r2.j2k.png -80bde56ea4d1a5c2b81f3c4227ef754c p1_04_18.t12.j2k.png -5bb3e76ec9d742ec742959f3bb865018 p1_04_19_t12_r1.j2k.png -ef287e72806290a81f61e3d271bdb1dc p1_04_1.j2k.png -d41f829c40140ec9972edf86681ee53a p1_04_2.j2k.png -4dd2a41c60bcf71b8c410833b12706cf p1_04_3.j2k.png -75b9b427ddded86219e361206669482a p1_04_4.j2k.png -de2e66f82b9da9bc2dabda183a455b2f p1_04_5.j2k.png -d12b3c90d4b1cf78f0ad23eedcabe0ea p1_04_6.j2k.png -b3fccf3cbb7186841ba7b86e34cac0c2 p1_04.j2k.png -071597783b2141a12db1765b85943c1d p1_06_10_1.j2k.png -6778de9e9236144747fe4542d03bf6e5 p1_06_10_2.j2k.png -af083204299bbdd993286892b4c9cd29 p1_06_10.j2k.png -af083204299bbdd993286892b4c9cd29 p1_06_11.j2k.png -72a7f65be34450c9ec126fbc58399354 p1_06_1.j2k.png -85b4f3b8f7b987f83972a820d34372a7 p1_06_2.j2k.png -d4fc3ff73e8b5eafbcc2a111b97d362b p1_06_3.j2k.png -a954722553fb25692556cfa87a26bc1a p1_06_4.j2k.png -a62bb79d066e230ea7b34e24681de189 p1_06_5.j2k.png -13d78a5091b06239c2b2012f7927dce8 p1_06_6.j2k.png -da21d175c4dcb03ce1f0a227f49ed7b8 p1_06_7_1.j2k.png -5c434a489375fc9624bab49679cdec76 p1_06_7_2.j2k.png -ce2de61ad83a71c9b13ca5df0a987a69 p1_06_7_3.j2k.png -18f9fbfb0d29e83f697fa93523c53a2b p1_06_7_4.j2k.png -66ede889502134412872b9d8b1e40887 p1_06_7_5.j2k.png -071597783b2141a12db1765b85943c1d p1_06_7_6.j2k.png -85a2b9a1324d72a8cec7041f80529242 p1_06_7.j2k.png -7045c8722e92fb2d447a6dc235a3c619 p1_06_9_1.j2k.png -d41856648d936229f1e3e2cf7d7c7a4d p1_06_9_2.j2k.png -85b4f3b8f7b987f83972a820d34372a7 p1_06_9_3.j2k.png -5fa6e85d6cfa0ed51e5933b2e35f4854 p1_06_9.j2k.png -2e80dbe4a6af432b7f1b54dfa4e164ae p1_06.j2k.png +03bd6de1f4e9924f2dcff8d4edaab718 p0_04_1.j2k.png +7898b580781d69fda800016378bab80c p0_04_2.j2k.png +e7cde963434e37ba00e128efb7e5c5c3 p0_04_3.j2k.png +a486db59bf5e7c39275aaf62304cf0b7 p0_04_4.j2k.png +59a08fe073e52a778128f22feffcdaf8 p0_04_5.j2k.png +c6f01ceef58442fed6a6af181b27ff06 p0_04_6_1.j2k.png +c3cbab7a2a5bf6b10f67afdd4e125120 p0_04_6_2.j2k.png +04457ca5d9bde5700140cedf8cf2aeea p0_04_6_3.j2k.png +dac32a0a17d0cc4e4f67d49767fc54c1 p0_04_6_4.j2k.png +ef27ff4ff2f6d7d3919808d7378bf119 p0_04_6_5.j2k.png +44ac3a7d98c90f5ab24b6801a601faa9 p0_04_6.j2k.png +bd0f12125f8e3f367dae1c6179f52212 p0_04.j2k.png +ff00bc86aa73a8266e381c5428c17c28 p1_04_10.j2k.png +72a6b3b455c6b3397f95cdf40ead75a0 p1_04_11.j2k.png +060809d8a5969f162f3b662adc3cbccb p1_04_12.j2k.png +92d8168db18cf51d108b0fc1a4f0aeea p1_04_13.j2k.png +bd5650ff4c977e42e4d84304c92222a0 p1_04_14.j2k.png +3920307d5b6cb855065f144b7683609b p1_04_15.j2k.png +1e94024252ca36e86b09e37370005ad0 p1_04_16.j2k.png +d271f149dc89c4d897fbd935189b159b p1_04_17_t63.j2k.png +060809d8a5969f162f3b662adc3cbccb p1_04_17_t63_r2.j2k.png +c92cb973e7dc716830ddf3d257e93fb3 p1_04_18.t12.j2k.png +c9b66b78895609fb0250ca5bd2e89c1d p1_04_19_t12_r1.j2k.png +68e1408710e68669f434937714fd5623 p1_04_1.j2k.png +d271f149dc89c4d897fbd935189b159b p1_04_2.j2k.png +9583a4c09567d8b67d23c5857ca10dc5 p1_04_3.j2k.png +6f405d502508b37f6133342ab2e7876c p1_04_4.j2k.png +4f084579cba30bec1cc9d89e55e99c5a p1_04_5.j2k.png +cd5326c62fa50d68b0d8f08bc3da617c p1_04_6.j2k.png +e50b0e1c1d28f0a40ad9d5c64a4b1cf4 p1_04.j2k.png +b367ad625d2a44a066b3cdd291da619c p1_06_10_1.j2k.png +0bc2db37548e0f6e342af2ea86380300 p1_06_10_2.j2k.png +32415e97cb64b4fda976c883bbb16103 p1_06_10.j2k.png +32415e97cb64b4fda976c883bbb16103 p1_06_11.j2k.png +3a99df46b0fbf7a9e7703d2b0e7355a5 p1_06_1.j2k.png +2702da6fca94765767365c7d80933ee2 p1_06_2.j2k.png +bb8d24257705393e5536fa77bdeb362c p1_06_3.j2k.png +9add0b9211f51ae2da1d01588ed3f9cf p1_06_4.j2k.png +5d037fefa22029a90d8e3ac82246a2e1 p1_06_5.j2k.png +821d1c176a2908136f5246599a47c462 p1_06_6.j2k.png +9d4cf96edeae63e461bff66d8c0b7b82 p1_06_7_1.j2k.png +6d6713374c1e443539a02f82baad5c98 p1_06_7_2.j2k.png +8317d23c60a0e891405339e0d9848efa p1_06_7_3.j2k.png +aa4a63ad4322a92c7f4d5a7f29ad0723 p1_06_7_4.j2k.png +e8748d54c7696069e14501c85d6f6638 p1_06_7_5.j2k.png +b367ad625d2a44a066b3cdd291da619c p1_06_7_6.j2k.png +93c72c4eaffdf0c3081a00e1d21829f6 p1_06_7.j2k.png +024d2b209513c21438f9b5c60b7d945d p1_06_9_1.j2k.png +c3f42d42eef90d42a98ad27d0612af9f p1_06_9_2.j2k.png +2702da6fca94765767365c7d80933ee2 p1_06_9_3.j2k.png +695444198428363c61871586add6d666 p1_06_9.j2k.png +c494419005e8aae82f46d3f48da6caf1 p1_06.j2k.png 371aa0a7ff40a73b45f1fa41e210d1db pacs.ge.j2k_0.pgx 6ae110e1fb5a869af3dbc5fbc735b0bd relax.jp2_0.pgx 518a8f28dacc034982507f43763b88dd relax.jp2_1.pgx c678b04f4d3e59b9d66a8bce37c553c0 relax.jp2_2.pgx cdb1d69eb48ffd8545751326b86d9d7e test_lossless.j2k_0.pgx -a37e7e5811d7c0c7adb61582790ccd33 text_GBR.jp2_0.pgx -fc2173be54954a146b4e2887ee14be06 text_GBR.jp2_1.pgx -14108b4fb8d9126750db0424417ed17d text_GBR.jp2_2.pgx +efc9c7f21a542a7888a9eeb73b0f7092 text_GBR.jp2_0.pgx +54790b332b3dcbda28e1bcb31270b946 text_GBR.jp2_1.pgx +d9bcbdc818febb8c0a6bc5f940a4ea85 text_GBR.jp2_2.pgx +a73bec4d6d82c8a64203e8fdf893b86d issue412.jp2_0.pgx +a73bec4d6d82c8a64203e8fdf893b86d issue428.jp2_0.pgx +2354cf24a1cc5e4a3b72896b333ba361 issue412.jp2_1.pgx +2354cf24a1cc5e4a3b72896b333ba361 issue428.jp2_1.pgx +77d707ff949371e561e13a8d720108b5 issue412.jp2_2.pgx +77d707ff949371e561e13a8d720108b5 issue428.jp2_2.pgx +2fc600f30ec0bc013befb1874e7adaeb issue414.jp2_0.pgx +354f9bb4668717d5c814cda354ec2b43 issue414.jp2_1.pgx +8b96a253937c4c7dd6b41b4aa11367d9 issue414.jp2_2.pgx +ec6886229ffaeaddfe22ce02b7a75e15 issue414.jp2_3.pgx +6aa5c69c83d6f4d5d65968f34f9bc2a3 issue414.jp2_4.pgx +00f34217ad2f88f4d4e1c5cd0d2c4329 issue399.j2k_0.pgx +d8fb69def2a48a3686483c4353544f4b issue411-ycc444.jp2_0.pgx +d2911f75ed1758057f9b1bf26bcb2400 issue411-ycc444.jp2_1.pgx +f7c23ee589ceda07ffb77a83018606cc issue411-ycc444.jp2_2.pgx +7e5e5546ae7ab4e9257ec30185ff9155 issue411-ycc422.jp2_0.pgx +d5ecef537edf294af83826763c0cf860 issue411-ycc422.jp2_1.pgx +3a8d91d7cf3e8887dd0d29beac030620 issue411-ycc422.jp2_2.pgx +07480962d25b3d8cce18096648963c8a issue411-ycc420.jp2_0.pgx +149a69831b42401f20b8f7492ef99d97 issue411-ycc420.jp2_1.pgx +ec8d1c99db9763a8ba489df4f41dda53 issue411-ycc420.jp2_2.pgx +3c7ff2e4bdae849167be36589f32bcd5 issue458.jp2_0.pgx +f004b48eafb2e52529cc9c7b6a3ff5d2 issue458.jp2_1.pgx +3127bd0a591d113c3c2428c8d2c14ec8 issue458.jp2_2.pgx +dacaf60e4c430916a8c2a9ebec32e71c issue458.jp2_3.pgx +d33fb5dbddb9b9b4438eb51fa27445a3 issue495.jp2_0.pgx +27db8c35e12a5d5eb94d403d2aae2909 issue495.jp2_1.pgx +97da625d2f2d0b75bf891d8083ce8bfb issue495.jp2_2.pgx +86729c5f2b74b2dfd42cb0d8e47aef79 a1_mono_tif-1.tif +fa9b7b896536b25a7a1d8eeeacb59141 a1_mono_tif-10.tif +b0ee13aa90ca4421e09a3b7b41f410c0 a1_mono_tif-12.tif +4699894fedd3758727d8288cd7adb56c a1_mono_tif-14.tif +4ad682c58e63d3223914c10a6656c8ae a1_mono_tif-16.tif +22c2fa09a4d7b9fade6a3cddc6c6a4dc a1_mono_tif-2.tif +996c5e67a663218be90e86bff8ecad89 a1_mono_tif-4.tif +7f451a5ac89915c5cdc023fd8c813a3c a1_mono_tif-6.tif +c3ebfcf478b1c4fc786748813f2b5d53 a1_mono_tif-8.tif +31650ec40241737634179fff6ad306f8 basn4a08_tif-1.tif +abf884080bcfbf58c044a9d86bfa5e5d basn4a08_tif-10.tif +916d97c098d9792993cc91fee4a83f77 basn4a08_tif-12.tif +57643174986481d336db6ddf04b970df basn4a08_tif-14.tif +fb5cf848d63c61dc485c87c9246ee9c7 basn4a08_tif-16.tif +5d7b01d98c82ad563bb28c2d83484a2a basn4a08_tif-2.tif +2401cebbb1d5494fcbe0d899484c342d basn4a08_tif-4.tif +6dbeb5b708bbde76e204c0887da61f6b basn4a08_tif-6.tif +dc40cc1da6de28e7e973c8ba796ca189 basn4a08_tif-8.tif +59e32c45591fd3bb44fe99381a116ba1 basn6a08_tif-1.tif +630e6fb6deba0b3efd93b610561d607a basn6a08_tif-10.tif +765555e75e59de27f7b2177d04f36bc1 basn6a08_tif-12.tif +62384c112d5fe40aefd0a9b0b9a4bcc6 basn6a08_tif-14.tif +d725d41557658a28ab31dff74e2467fa basn6a08_tif-16.tif +96d91df6b10e866ea26ebbf0b8ddc7da basn6a08_tif-2.tif +a324032339808d5fe85d6e354f14c183 basn6a08_tif-4.tif +d60864a6a5c8a49a202d98ae6f5165c7 basn6a08_tif-6.tif +c3e93f61125f82a9832d0b9440468034 basn6a08_tif-8.tif +cfe04d15cf9d615fc36357dcb3b3956b p0_14_tif-1.tif +9ad87e7fddc77ac85e2e92509bee2365 p0_14_tif-10.tif +38e67f9d573e61166761d5eee0104448 p0_14_tif-12.tif +77486f0468694b94290d0b55361498a0 p0_14_tif-14.tif +51be675689949dd08b6ee1427af3eb4a p0_14_tif-16.tif +3e34e94bd8f7380c8d159676fee9ea57 p0_14_tif-2.tif +b6f71c941e3a5b8d2547792ccec58d54 p0_14_tif-4.tif +81fcdd90917efb95aed94c6522d1c188 p0_14_tif-6.tif +6808377b760b4ef3559ba8b14ed9b91a p0_14_tif-8.tif +dd15b3d487d36a3682be0679300a4319 issue235.jp2_0.pgx +b9cd6dc76b141fb1fec15f50c1f70e01 issue235.jp2_1.pgx +3edef2ae197ef30b08deda1b28825399 issue235.jp2_2.pgx +b6a84b3215333efc80326715f9078c58 a1_mono_png-1.png +88f96456667b8b3fd69c406fe40636b5 a1_mono_png-10.png +077148452a9506a2337afa2777c57834 a1_mono_png-12.png +c4eee75c1da8d43e1510cb36326f948b a1_mono_png-14.png +b22b7badb943c5c375b7c55032f49def a1_mono_png-16.png +c7e209abe0d4c5ec1407bfe2cfa932de a1_mono_png-2.png +313d1e2d0d41231003587d3061b6119f a1_mono_png-4.png +d92241d97e8603509027176dd3b3168a a1_mono_png-6.png +a86b3b0720229491ce82556d3fc97bf3 a1_mono_png-8.png +159d1413263e2183e50ecc8dc7487b98 basn4a08_png-1.png +cc501ac5219200ed5d7d33df907d3390 basn4a08_png-10.png +9006ec767be7645c1808eef4e8c6ee7a basn4a08_png-12.png +df3484a4ecfaddc1f62d4bf202944ad5 basn4a08_png-14.png +699c25624e99c72fd45cfdb5660920c2 basn4a08_png-16.png +95090b2194e811e8c490e12632e8a5f3 basn4a08_png-2.png +c66f969b198eff8ddf663a3ccbb8e272 basn4a08_png-4.png +02484627d57e7bcb45d3c1bff11a4687 basn4a08_png-6.png +3bf91c974abc17e520c6a5efa883a58a basn4a08_png-8.png +cd6b948268967b1e9b54d60607b8de0a basn6a08_png-1.png +549e7a5566f37f7e08030cfa2aee8994 basn6a08_png-10.png +d9e6472bc020607327cd082464d03616 basn6a08_png-12.png +54e9b4d5e3fadd939a54722f05cadbe9 basn6a08_png-14.png +94bba5bebc9e9209f2af13c6dd5a2c12 basn6a08_png-16.png +16a9287d409a1c80158973f95eb3c04e basn6a08_png-2.png +4065c615d124289bd06cd9c9bfb4adab basn6a08_png-4.png +3235c0b759dd47e0c2df5bc9ac827e70 basn6a08_png-6.png +0db8bf6fa69191c20936701ef365b82a basn6a08_png-8.png +d3c82c8552f2e47c179372933725c8d7 p0_14_png-1.png +7bce012868556bd04e5c0567b67d2896 p0_14_png-10.png +d66fe6bbe653a18e60416e0cda1b1949 p0_14_png-12.png +b3f01308ae57518ff157c926563b01b2 p0_14_png-14.png +629bc0a76c5454e875eab9cacc653dfd p0_14_png-16.png +fc2844a9f3c8e924e349180ba9e122dd p0_14_png-2.png +428c7a19b9df4120d35b5df7fafdf253 p0_14_png-4.png +0c1cc85c051dd95394d06103c8d9bbef p0_14_png-6.png +230e4968cb445b222ee2095014ba1d26 p0_14_png-8.png +5a6131ad9ea5d191ffcdf6435be89cb4 v4dwt_interleave_h.gsr105.j2k_0.pgx +4426ed46f75a45782c551d82818b9e60 dwt_interleave_h.gsr105.jp2_0.pgx +382e7297e062d729a7a7726e964f1a0a dwt_interleave_h.gsr105.jp2_1.pgx +64c1027db97421e348f823178b5d9c4b dwt_interleave_h.gsr105.jp2_2.pgx +63bf755af5a1f8a478d65079dc7c8964 issue205-tif.jp2.tif +b01ed87dbac424bc820b2ac590e4884e issue236-ESYCC-CDEF.jp2_0.pgx +2635cc00b1e18ef11adcba09e845d459 issue236-ESYCC-CDEF.jp2_1.pgx +f9c95d0aec2f6e7b814fa1d09edcdbda issue236-ESYCC-CDEF.jp2_2.pgx +5f0c1d5c5127c1eabb86a5e0112f139b issue559-eci-090-CIELab.jp2_0.pgx +cdae87485eaada56be3671eec39452e6 issue559-eci-090-CIELab.jp2_1.pgx +e163102afcc857cf001337178241f518 issue559-eci-090-CIELab.jp2_2.pgx +b004b2e08b0dfb217c131b353cf157eb issue559-eci-091-CIELab.jp2_0.pgx +2400da6b8ed6b1747b9913af544580f9 issue559-eci-091-CIELab.jp2_1.pgx +cf73dda887967928dbcf5cc87ab204cc issue559-eci-091-CIELab.jp2_2.pgx +3bf91c974abc17e520c6a5efa883a58a issue653-zero-unknownbox.jp2.png diff --git a/tests/nonregression/test_suite.ctest.in b/tests/nonregression/test_suite.ctest.in index 186527c2..c316a5ea 100644 --- a/tests/nonregression/test_suite.ctest.in +++ b/tests/nonregression/test_suite.ctest.in @@ -1,7 +1,7 @@ # This file list all the input commands of the tests run by the ctest command which # are not related to the conformance files. # -# For each line of this file (exept line which begin with #) an opj_compress test or a +# For each line of this file (except line which begin with #) an opj_compress test or a # opj_decompress is run and its related tests. # + For encoder related tests = dump, compare dump to base, decode the encoded file with # reference and compare the decoded file with the baseline decoded previously with @@ -40,19 +40,109 @@ opj_compress -i @INPUT_NR_PATH@/X_5_2K_24_235_CBR_STEM24_000.tif -o @TEMP_PATH@/ opj_compress -i @INPUT_NR_PATH@/X_6_2K_24_FULL_CBR_CIRCLE_000.tif -o @TEMP_PATH@/X_6_2K_24_FULL_CBR_CIRCLE_000_C2K_48.j2k -cinema2K 48 opj_compress -i @INPUT_NR_PATH@/ElephantDream_4K.tif -o @TEMP_PATH@/ElephantDream_4K_C4K.j2k -cinema4K # issue 141 -opj_compress -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141.rawl.j2k -F 2048,2816,1,16,u -opj_compress -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141.rawl.j2k -F 2048,2816,1,16,u -I +opj_compress -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141.rawl.j2k -F 2048,32,1,16,u +opj_compress -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141-I.rawl.j2k -F 2048,32,1,16,u -I # issue 46: -opj_compress -i @INPUT_NR_PATH@/Bretagne2.ppm -o @TEMP_PATH@/Bretagne2_0.j2k -c [64,64] +opj_compress -i @INPUT_NR_PATH@/Bretagne2.ppm -o @TEMP_PATH@/Bretagne2_5.j2k -c [64,64] # issue 316 opj_compress -i @INPUT_NR_PATH@/issue316.png -o @TEMP_PATH@/issue316.png.jp2 +# issue 416 (cdef for png with alpha) + issue 436 (MCT norm read buffer overflow for num comp > 3 + Issue 215 number of decomp levels +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn6a08.png -o @TEMP_PATH@/basn6a08.png.jp2 -n 6 +# issue 203 BMP Files not handled properly +opj_compress -i @INPUT_NR_PATH@/issue203-8bpp-width1.bmp -o @TEMP_PATH@/issue203-8bpp-width1.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-rle8.bmp -o @TEMP_PATH@/issue203-rle8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-y8.bmp -o @TEMP_PATH@/issue203-32x32-y8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-33x33-y8.bmp -o @TEMP_PATH@/issue203-33x33-y8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-34x34-y8.bmp -o @TEMP_PATH@/issue203-34x34-y8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-35x35-y8.bmp -o @TEMP_PATH@/issue203-35x35-y8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgr.bmp -o @TEMP_PATH@/issue203-32x32-bgr.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-33x33-bgr.bmp -o @TEMP_PATH@/issue203-33x33-bgr.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-34x34-bgr.bmp -o @TEMP_PATH@/issue203-34x34-bgr.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-35x35-bgr.bmp -o @TEMP_PATH@/issue203-35x35-bgr.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-y-rle8.bmp -o @TEMP_PATH@/issue203-32x32-y-rle8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgr-rle8.bmp -o @TEMP_PATH@/issue203-32x32-bgr-rle8.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-y-rle4.bmp -o @TEMP_PATH@/issue203-32x32-y-rle4.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgr-rle4.bmp -o @TEMP_PATH@/issue203-32x32-bgr-rle4.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgra.bmp -o @TEMP_PATH@/issue203-32x32-bgra.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgrx.bmp -o @TEMP_PATH@/issue203-32x32-bgrx.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgr16.bmp -o @TEMP_PATH@/issue203-32x32-bgr16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-33x33-bgr16.bmp -o @TEMP_PATH@/issue203-33x33-bgr16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgra16.bmp -o @TEMP_PATH@/issue203-32x32-bgra16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-33x33-bgra16.bmp -o @TEMP_PATH@/issue203-33x33-bgra16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-32x32-bgrx16.bmp -o @TEMP_PATH@/issue203-32x32-bgrx16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-33x33-bgrx16.bmp -o @TEMP_PATH@/issue203-33x33-bgrx16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-127x64-bgr16.bmp -o @TEMP_PATH@/issue203-127x64-bgr16.bmp.jp2 +opj_compress -i @INPUT_NR_PATH@/issue203-127x64-bgrx.bmp -o @TEMP_PATH@/issue203-127x64-bgrx.bmp.jp2 + +# issue 322 limited tif support +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-01.tif -o @TEMP_PATH@/flower-minisblack-01.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-02.tif -o @TEMP_PATH@/flower-minisblack-02.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-04.tif -o @TEMP_PATH@/flower-minisblack-04.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-06.tif -o @TEMP_PATH@/flower-minisblack-06.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-08.tif -o @TEMP_PATH@/flower-minisblack-08.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-10.tif -o @TEMP_PATH@/flower-minisblack-10.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-12.tif -o @TEMP_PATH@/flower-minisblack-12.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-14.tif -o @TEMP_PATH@/flower-minisblack-14.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-minisblack-16.tif -o @TEMP_PATH@/flower-minisblack-16.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-02.tif -o @TEMP_PATH@/flower-rgb-contig-02.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-04.tif -o @TEMP_PATH@/flower-rgb-contig-04.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-08.tif -o @TEMP_PATH@/flower-rgb-contig-08.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-10.tif -o @TEMP_PATH@/flower-rgb-contig-10.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-12.tif -o @TEMP_PATH@/flower-rgb-contig-12.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-14.tif -o @TEMP_PATH@/flower-rgb-contig-14.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-contig-16.tif -o @TEMP_PATH@/flower-rgb-contig-16.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-02.tif -o @TEMP_PATH@/flower-rgb-planar-02.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-04.tif -o @TEMP_PATH@/flower-rgb-planar-04.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-08.tif -o @TEMP_PATH@/flower-rgb-planar-08.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-10.tif -o @TEMP_PATH@/flower-rgb-planar-10.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-12.tif -o @TEMP_PATH@/flower-rgb-planar-12.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-14.tif -o @TEMP_PATH@/flower-rgb-planar-14.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/flower-rgb-planar-16.tif -o @TEMP_PATH@/flower-rgb-planar-16.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/basn6a08.tif -o @TEMP_PATH@/basn6a08.tif.jp2 +opj_compress -i @INPUT_NR_PATH@/basn4a08.tif -o @TEMP_PATH@/basn4a08.tif.jp2 + +# issue 536 (PNG images are always read as RGB(A) images) + issue 264 (convert.c is unmaintainable) +# Test all images from pngsuite +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn0g01.png -o @TEMP_PATH@/basn0g01.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn0g02.png -o @TEMP_PATH@/basn0g02.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn0g04.png -o @TEMP_PATH@/basn0g04.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn0g08.png -o @TEMP_PATH@/basn0g08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn0g16.png -o @TEMP_PATH@/basn0g16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn2c08.png -o @TEMP_PATH@/basn2c08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn2c16.png -o @TEMP_PATH@/basn2c16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn3p01.png -o @TEMP_PATH@/basn3p01.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn3p02.png -o @TEMP_PATH@/basn3p02.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn3p04.png -o @TEMP_PATH@/basn3p04.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn3p08.png -o @TEMP_PATH@/basn3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn4a08.png -o @TEMP_PATH@/basn4a08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn4a16.png -o @TEMP_PATH@/basn4a16.png.jp2 +# already done opj_compress -i @INPUT_NR_PATH@/pngsuite/basn6a08.png -o @TEMP_PATH@/basn6a08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/basn6a16.png -o @TEMP_PATH@/basn6a16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbbn0g01.png -o @TEMP_PATH@/ftbbn0g01.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbbn0g02.png -o @TEMP_PATH@/ftbbn0g02.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbbn0g04.png -o @TEMP_PATH@/ftbbn0g04.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbbn2c16.png -o @TEMP_PATH@/ftbbn2c16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbbn3p08.png -o @TEMP_PATH@/ftbbn3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbgn2c16.png -o @TEMP_PATH@/ftbgn2c16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbgn3p08.png -o @TEMP_PATH@/ftbgn3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbrn2c08.png -o @TEMP_PATH@/ftbrn2c08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbwn0g16.png -o @TEMP_PATH@/ftbwn0g16.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbwn3p08.png -o @TEMP_PATH@/ftbwn3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftbyn3p08.png -o @TEMP_PATH@/ftbyn3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftp0n0g08.png -o @TEMP_PATH@/ftp0n0g08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftp0n2c08.png -o @TEMP_PATH@/ftp0n2c08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftp0n3p08.png -o @TEMP_PATH@/ftp0n3p08.png.jp2 +opj_compress -i @INPUT_NR_PATH@/pngsuite/ftp1n3p08.png -o @TEMP_PATH@/ftp1n3p08.png.jp2 + +# issue 571 Lossless is not lossless on linux x86 +opj_compress -i @INPUT_NR_PATH@/issue571.tif -o @TEMP_PATH@/issue571.tif.j2k # DECODER TEST SUITE opj_decompress -i @INPUT_NR_PATH@/Bretagne2.j2k -o @TEMP_PATH@/Bretagne2.j2k.pgx opj_decompress -i @INPUT_NR_PATH@/_00042.j2k -o @TEMP_PATH@/_00042.j2k.pgx opj_decompress -i @INPUT_NR_PATH@/123.j2c -o @TEMP_PATH@/123.j2c.pgx # The 4 following tests should failed (kakadu indicates that they are corrupted) -!opj_decompress -i @INPUT_NR_PATH@/broken.jp2 -o @TEMP_PATH@/broken.jp2.pgx +!opj_decompress -i @INPUT_NR_PATH@/broken1.jp2 -o @TEMP_PATH@/broken1.jp2.pgx !opj_decompress -i @INPUT_NR_PATH@/broken2.jp2 -o @TEMP_PATH@/broken2.jp2.pgx !opj_decompress -i @INPUT_NR_PATH@/broken3.jp2 -o @TEMP_PATH@/broken3.jp2.pgx !opj_decompress -i @INPUT_NR_PATH@/broken4.jp2 -o @TEMP_PATH@/broken4.jp2.pgx @@ -83,7 +173,7 @@ opj_decompress -i @INPUT_NR_PATH@/text_GBR.jp2 -o @TEMP_PATH@/text_GBR.jp2.pgx opj_decompress -i @INPUT_NR_PATH@/pacs.ge.j2k -o @TEMP_PATH@/pacs.ge.j2k.pgx # related to issue 135 opj_decompress -i @INPUT_NR_PATH@/kodak_2layers_lrcp.j2c -o @TEMP_PATH@/kodak_2layers_lrcp.j2c.pgx -opj_decompress -i @INPUT_NR_PATH@/kodak_2layers_lrcp.j2c -o @TEMP_PATH@/kodak_2layers_lrcp.j2c.pgx -l 2 +opj_decompress -i @INPUT_NR_PATH@/kodak_2layers_lrcp.j2c -o @TEMP_PATH@/kodak_2layers_lrcp-l2.j2c.pgx -l 2 # related to issue 104 and 110 opj_decompress -i @INPUT_NR_PATH@/issue104_jpxstream.jp2 -o @TEMP_PATH@/issue104_jpxstream.jp2.pgx # File not supported by kakadu (Malformed PCLR box) and not supoprter by openjpeg (problem with value of TPSot) @@ -174,6 +264,72 @@ opj_decompress -i @INPUT_NR_PATH@/issue226.j2k -o @TEMP_PATH@/ #!opj_decompress -i @INPUT_NR_PATH@/3459.pdf.asan.6c.2734.0.jp2 -o @TEMP_PATH@/3459.pdf.asan.6c.2734.0.jp2.pgx #!opj_decompress -i @INPUT_NR_PATH@/3459.pdf.asan.6c.2734.1.jp2 -o @TEMP_PATH@/3459.pdf.asan.6c.2734.1.jp2.pgx #!opj_decompress -i @INPUT_NR_PATH@/3459.pdf.asan.6c.2734.2.jp2 -o @TEMP_PATH@/3459.pdf.asan.6c.2734.2.jp2.pgx +# issue 362 (from pdfium fuzz engine) +# Invalid PPM Marker +!opj_decompress -i @INPUT_NR_PATH@/issue362-2863.jp2 -o @TEMP_PATH@/issue362-2863.jp2.pgx +# Invalid ftyp box size +!opj_decompress -i @INPUT_NR_PATH@/issue362-2866.jp2 -o @TEMP_PATH@/issue362-2866.jp2.pgx +!opj_decompress -i @INPUT_NR_PATH@/issue362-2894.jp2 -o @TEMP_PATH@/issue362-2894.jp2.pgx +# issue 363 (from pdfium fuzz engine) +# Invalid Tile part length +!opj_decompress -i @INPUT_NR_PATH@/issue363-4723.jp2 -o @TEMP_PATH@/issue363-4723.jp2.pgx +# Invalid Marker length +!opj_decompress -i @INPUT_NR_PATH@/issue363-4740.jp2 -o @TEMP_PATH@/issue363-4740.jp2.pgx +!opj_decompress -i @INPUT_NR_PATH@/issue363-4792.jp2 -o @TEMP_PATH@/issue363-4792.jp2.pgx +# issue 390 (from pdfium fuzz engine) Invalid segment size +!opj_decompress -i @INPUT_NR_PATH@/issue390.jp2 -o @TEMP_PATH@/issue390.jp2.pgx +# issue 391 (from pdfium fuzz engine) Invalid segment size +!opj_decompress -i @INPUT_NR_PATH@/issue391.jp2 -o @TEMP_PATH@/issue391.jp2.pgx +# issue 400 (from pdfium fuzz engine) Unknown Scod value in COD marker +!opj_decompress -i @INPUT_NR_PATH@/issue400.jp2 -o @TEMP_PATH@/issue400.jp2.pgx +# issue 413 (from pdfium fuzz engine) Unknown progression order in COD marker +!opj_decompress -i @INPUT_NR_PATH@/issue413.jp2 -o @TEMP_PATH@/issue413.jp2.pgx +# issue 364 (from pdfium fuzz engine) +# Inconsistent box length for jp2 box +!opj_decompress -i @INPUT_NR_PATH@/issue364-38.jp2 -o @TEMP_PATH@/issue364-38.jp2.pgx +# No ihdr box +!opj_decompress -i @INPUT_NR_PATH@/issue364-903.jp2 -o @TEMP_PATH@/issue364-903.jp2.pgx +# issue 393 (from pdfium fuzz engine) Zppm found twice +!opj_decompress -i @INPUT_NR_PATH@/issue393.jp2 -o @TEMP_PATH@/issue393.jp2.pgx +# issue 395 (from pdfium fuzz engine) Stream too short +!opj_decompress -i @INPUT_NR_PATH@/issue395.jp2 -o @TEMP_PATH@/issue395.jp2.pgx +# issue 397 (from pdfium fuzz engine) Incomplete channel definitions. +!opj_decompress -i @INPUT_NR_PATH@/issue397.jp2 -o @TEMP_PATH@/issue397.jp2.pgx +# issue 399 (from pdfium fuzz engine) Incomplete channel definitions. +opj_decompress -i @INPUT_NR_PATH@/issue399.j2k -o @TEMP_PATH@/issue399.j2k.pgx +# issue 408 (from pdfium fuzz engine) No COD marker in main j2k header. +!opj_decompress -i @INPUT_NR_PATH@/issue408.jp2 -o @TEMP_PATH@/issue408.jp2.pgx +# issue 412 Palette image with cdef fails to decompress. +opj_decompress -i @INPUT_NR_PATH@/issue412.jp2 -o @TEMP_PATH@/issue412.jp2.pgx +# issue 428 Palette image with cdef fails to decompress properly. +opj_decompress -i @INPUT_NR_PATH@/issue412.jp2 -o @TEMP_PATH@/issue428.jp2.pgx -t 0 +# issue 414 Image with per channel alpha (cdef) does not decode properly. +opj_decompress -i @INPUT_NR_PATH@/issue414.jp2 -o @TEMP_PATH@/issue414.jp2.pgx +# issue 418 (from pdfium fuzz engine) Tile part length size inconsistent with stream length. +!opj_decompress -i @INPUT_NR_PATH@/issue418.jp2 -o @TEMP_PATH@/issue418.jp2.pgx +# issue 420 (from pdfium fuzz engine) Illegal custom precinct exponent. +!opj_decompress -i @INPUT_NR_PATH@/issue420.jp2 -o @TEMP_PATH@/issue420.jp2.pgx +# issue 422 (rework of issue 411). ycc with odd width/height +opj_decompress -i @INPUT_NR_PATH@/issue411-ycc444.jp2 -o @TEMP_PATH@/issue411-ycc444.jp2.pgx +opj_decompress -i @INPUT_NR_PATH@/issue411-ycc422.jp2 -o @TEMP_PATH@/issue411-ycc422.jp2.pgx +opj_decompress -i @INPUT_NR_PATH@/issue411-ycc420.jp2 -o @TEMP_PATH@/issue411-ycc420.jp2.pgx +# issue 429 (from pdfium fuzz engine) 0 entries in PCLR box. +!opj_decompress -i @INPUT_NR_PATH@/issue429.jp2 -o @TEMP_PATH@/issue429.jp2.pgx +# issue 432 (from pdfium fuzz engine) Overflow in tcd tilec data size computation. +!opj_decompress -i @INPUT_NR_PATH@/issue432.jp2 -o @TEMP_PATH@/issue432.jp2.pgx +# issue 427 image width is 0 +!opj_decompress -i @INPUT_NR_PATH@/issue427-null-image-size.jp2 -o @TEMP_PATH@/issue427-null-image-size.jp2.pgx +# issue 427 illegal tile offset +!opj_decompress -i @INPUT_NR_PATH@/issue427-illegal-tile-offset.jp2 -o @TEMP_PATH@/issue427-illegal-tile-offset.jp2.pgx +# issue 458 component precision upscaling +opj_decompress -i @INPUT_NR_PATH@/issue458.jp2 -o @TEMP_PATH@/issue458.jp2.pgx +# issue 476 Multiple COD in MH +!opj_decompress -i @INPUT_NR_PATH@/issue476.jp2 -o @TEMP_PATH@/issue476.jp2.pgx +# issue 475 Invalid number of layers +!opj_decompress -i @INPUT_NR_PATH@/issue475.jp2 -o @TEMP_PATH@/issue475.jp2.pgx +# issue 495 Overflow op_image_comp_header_updat +opj_decompress -i @INPUT_NR_PATH@/issue495.jp2 -o @TEMP_PATH@/issue495.jp2.pgx + # decode with specific area # prec=12; nb_c=1 @@ -248,3 +404,107 @@ opj_decompress -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_5.j2k.png - #opj_decompress -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_3.j2k.png -d 10,150,190,210 #opj_decompress -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_4.j2k.png -d 100,80,200,150 #opj_decompress -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_5.j2k.png -d 150,20,200,50 + +# issue 322 limited tif support +# GRAYSCALE +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-1.tif -p 1S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-2.tif -p 2S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-4.tif -p 4S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-6.tif -p 6S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-8.tif -p 8S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-10.tif -p 10S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-12.tif -p 12S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-14.tif -p 14S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-16.tif -p 16S +# GRAYSCALE ALPHA +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-1.tif -p 1S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-2.tif -p 2S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-4.tif -p 4S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-6.tif -p 6S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-8.tif -p 8S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-10.tif -p 10S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-12.tif -p 12S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-14.tif -p 14S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-16.tif -p 16S +# RGB +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-1.tif -p 1S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-2.tif -p 2S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-4.tif -p 4S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-6.tif -p 6S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-8.tif -p 8S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-10.tif -p 10S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-12.tif -p 12S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-14.tif -p 14S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-16.tif -p 16S +# RGBA +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-1.tif -p 1S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-2.tif -p 2S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-4.tif -p 4S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-6.tif -p 6S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-8.tif -p 8S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-10.tif -p 10S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-12.tif -p 12S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-14.tif -p 14S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-16.tif -p 16S + +#issue 235 CMAP outside jp2h box. CMAP is buggy +opj_decompress -i @INPUT_NR_PATH@/issue235.jp2 -o @TEMP_PATH@/issue235.jp2.pgx + +# issue 264, add checks for png +# GRAYSCALE +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-1.png -p 1S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-2.png -p 2S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-4.png -p 4S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-6.png -p 6S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-8.png -p 8S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-10.png -p 10S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-12.png -p 12S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-14.png -p 14S +opj_decompress -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-16.png -p 16S +# GRAYSCALE ALPHA +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-1.png -p 1S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-2.png -p 2S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-4.png -p 4S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-6.png -p 6S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-8.png -p 8S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-10.png -p 10S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-12.png -p 12S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-14.png -p 14S +opj_decompress -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-16.png -p 16S +# RGB +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-1.png -p 1S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-2.png -p 2S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-4.png -p 4S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-6.png -p 6S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-8.png -p 8S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-10.png -p 10S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-12.png -p 12S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-14.png -p 14S +opj_decompress -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-16.png -p 16S +# RGBA +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-1.png -p 1S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-2.png -p 2S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-4.png -p 4S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-6.png -p 6S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-8.png -p 8S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-10.png -p 10S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-12.png -p 12S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-14.png -p 14S +opj_decompress -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-16.png -p 16S + +# issue 388 +!opj_decompress -i @INPUT_NR_PATH@/v4dwt_interleave_h.gsr105.j2k -o @TEMP_PATH@/v4dwt_interleave_h.gsr105.j2k.pgx +opj_decompress -i @INPUT_NR_PATH@/dwt_interleave_h.gsr105.jp2 -o @TEMP_PATH@/dwt_interleave_h.gsr105.jp2.pgx + +# PR 559 : CMYK tif output +opj_decompress -i @INPUT_NR_PATH@/issue205.jp2 -o @TEMP_PATH@/issue205-tif.jp2.tif + +# issue 236: esYCC colorspace +opj_decompress -i @INPUT_NR_PATH@/issue236-ESYCC-CDEF.jp2 -o @TEMP_PATH@/issue236-ESYCC-CDEF.jp2.pgx + +# issue 326 + PR 559: CIELab colorspace +opj_decompress -i @INPUT_NR_PATH@/issue559-eci-090-CIELab.jp2 -o @TEMP_PATH@/issue559-eci-090-CIELab.jp2.pgx +opj_decompress -i @INPUT_NR_PATH@/issue559-eci-091-CIELab.jp2 -o @TEMP_PATH@/issue559-eci-091-CIELab.jp2.pgx + +# issue 653 Last box of undefined size byg +opj_decompress -i @INPUT_NR_PATH@/issue653-zero-unknownbox.jp2 -o @TEMP_PATH@/issue653-zero-unknownbox.jp2.png -p 8S diff --git a/tests/pdf2jp2.c b/tests/pdf2jp2.c index 830cbf4e..38aa739f 100644 --- a/tests/pdf2jp2.c +++ b/tests/pdf2jp2.c @@ -37,6 +37,11 @@ * only work on linux since I need memmem function */ +/* + * Add support for other signatures: + * + * obj<>stream + */ #define _GNU_SOURCE #include #include @@ -98,7 +103,17 @@ int main(int argc, char *argv[]) assert( r ); /*fprintf( stderr, "DEBUG: %s", r );*/ s = sscanf(r, "JPXDecode]/Length %d/Width %*d/BitsPerComponent %*d/Height %*d", &len); - assert( s == 1 ); + if( s == 0 ) + { // try again harder + const int ret = fseek(f, offets[i] - 40, SEEK_SET); // 40 is magic number + assert( ret == 0 ); + r = fgets(buffer, sizeof(buffer), f); + assert( r ); + const char needle2[] = "/Length"; + char * s2 = strstr(buffer, needle2); + s = sscanf(s2, "/Length %d/", &len); + } + if( s == 1 ) { FILE *jp2; int j; diff --git a/thirdparty/include/zconf.h b/thirdparty/include/zconf.h index 02ce56c4..9987a775 100644 --- a/thirdparty/include/zconf.h +++ b/thirdparty/include/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. + * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -15,11 +15,13 @@ * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block @@ -27,9 +29,11 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 @@ -40,44 +44,53 @@ # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams +# define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table -# define gz_error z_gz_error -# define gz_intmax z_gz_intmax -# define gz_strwinerror z_gz_strwinerror -# define gzbuffer z_gzbuffer -# define gzclearerr z_gzclearerr -# define gzclose z_gzclose -# define gzclose_r z_gzclose_r -# define gzclose_w z_gzclose_w -# define gzdirect z_gzdirect -# define gzdopen z_gzdopen -# define gzeof z_gzeof -# define gzerror z_gzerror -# define gzflush z_gzflush -# define gzgetc z_gzgetc -# define gzgets z_gzgets -# define gzoffset z_gzoffset -# define gzoffset64 z_gzoffset64 -# define gzopen z_gzopen -# define gzopen64 z_gzopen64 -# define gzprintf z_gzprintf -# define gzputc z_gzputc -# define gzputs z_gzputs -# define gzread z_gzread -# define gzrewind z_gzrewind -# define gzseek z_gzseek -# define gzseek64 z_gzseek64 -# define gzsetparams z_gzsetparams -# define gztell z_gztell -# define gztell64 z_gztell64 -# define gzungetc z_gzungetc -# define gzwrite z_gzwrite +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd @@ -92,16 +105,22 @@ # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table -# define uncompress z_uncompress +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif # define zError z_zError -# define zcalloc z_zcalloc -# define zcfree z_zcfree +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion @@ -111,7 +130,9 @@ # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func -# define gzFile z_gzFile +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func @@ -197,6 +218,12 @@ # endif #endif +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL @@ -243,6 +270,14 @@ # endif #endif +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(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 @@ -356,12 +391,47 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + #ifdef STDC -# include /* for off_t */ +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and @@ -370,21 +440,38 @@ typedef uLong FAR uLongf; * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ -#if -_LARGEFILE64_SOURCE - -1 == 1 +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif -#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# ifndef z_off_t -# define z_off_t off_t +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif # endif #endif -#ifndef SEEK_SET +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) # 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" */ @@ -394,18 +481,14 @@ typedef uLong FAR uLongf; # define z_off_t long #endif -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +#if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else -# define z_off64_t z_off_t -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif #endif /* MVS linker does not support external names larger than 8 bytes */ diff --git a/thirdparty/include/zconf.h.cmake.msvc b/thirdparty/include/zconf.h.cmake.msvc deleted file mode 100644 index 57465e07..00000000 --- a/thirdparty/include/zconf.h.cmake.msvc +++ /dev/null @@ -1,430 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H -/* #undef Z_PREFIX */ -/* #undef Z_HAVE_UNISTD_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. - * Even better than compiling with -DZ_PREFIX would be to use configure to set - * this permanently in zconf.h using "./configure --zprefix". - */ -#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ - -/* all linked symbols */ -# define _dist_code z__dist_code -# define _length_code z__length_code -# define _tr_align z__tr_align -# define _tr_flush_block z__tr_flush_block -# define _tr_init z__tr_init -# define _tr_stored_block z__tr_stored_block -# define _tr_tally z__tr_tally -# define adler32 z_adler32 -# define adler32_combine z_adler32_combine -# define adler32_combine64 z_adler32_combine64 -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define crc32 z_crc32 -# define crc32_combine z_crc32_combine -# define crc32_combine64 z_crc32_combine64 -# define deflate z_deflate -# define deflateBound z_deflateBound -# define deflateCopy z_deflateCopy -# define deflateEnd z_deflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateInit_ z_deflateInit_ -# define deflateParams z_deflateParams -# define deflatePrime z_deflatePrime -# define deflateReset z_deflateReset -# define deflateSetDictionary z_deflateSetDictionary -# define deflateSetHeader z_deflateSetHeader -# define deflateTune z_deflateTune -# define deflate_copyright z_deflate_copyright -# define get_crc_table z_get_crc_table -# define gz_error z_gz_error -# define gz_intmax z_gz_intmax -# define gz_strwinerror z_gz_strwinerror -# define gzbuffer z_gzbuffer -# define gzclearerr z_gzclearerr -# define gzclose z_gzclose -# define gzclose_r z_gzclose_r -# define gzclose_w z_gzclose_w -# define gzdirect z_gzdirect -# define gzdopen z_gzdopen -# define gzeof z_gzeof -# define gzerror z_gzerror -# define gzflush z_gzflush -# define gzgetc z_gzgetc -# define gzgets z_gzgets -# define gzoffset z_gzoffset -# define gzoffset64 z_gzoffset64 -# define gzopen z_gzopen -# define gzopen64 z_gzopen64 -# define gzprintf z_gzprintf -# define gzputc z_gzputc -# define gzputs z_gzputs -# define gzread z_gzread -# define gzrewind z_gzrewind -# define gzseek z_gzseek -# define gzseek64 z_gzseek64 -# define gzsetparams z_gzsetparams -# define gztell z_gztell -# define gztell64 z_gztell64 -# define gzungetc z_gzungetc -# define gzwrite z_gzwrite -# define inflate z_inflate -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define inflateBackInit_ z_inflateBackInit_ -# define inflateCopy z_inflateCopy -# define inflateEnd z_inflateEnd -# define inflateGetHeader z_inflateGetHeader -# define inflateInit2_ z_inflateInit2_ -# define inflateInit_ z_inflateInit_ -# define inflateMark z_inflateMark -# define inflatePrime z_inflatePrime -# define inflateReset z_inflateReset -# define inflateReset2 z_inflateReset2 -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateUndermine z_inflateUndermine -# define inflate_copyright z_inflate_copyright -# define inflate_fast z_inflate_fast -# define inflate_table z_inflate_table -# define uncompress z_uncompress -# define zError z_zError -# define zcalloc z_zcalloc -# define zcfree z_zcfree -# define zlibCompileFlags z_zlibCompileFlags -# define zlibVersion z_zlibVersion - -/* all zlib typedefs in zlib.h and zconf.h */ -# define Byte z_Byte -# define Bytef z_Bytef -# define alloc_func z_alloc_func -# define charf z_charf -# define free_func z_free_func -# define gzFile z_gzFile -# define gz_header z_gz_header -# define gz_headerp z_gz_headerp -# define in_func z_in_func -# define intf z_intf -# define out_func z_out_func -# define uInt z_uInt -# define uIntf z_uIntf -# define uLong z_uLong -# define uLongf z_uLongf -# define voidp z_voidp -# define voidpc z_voidpc -# define voidpf z_voidpf - -/* all zlib structs in zlib.h and zconf.h */ -# define gz_header_s z_gz_header_s -# define internal_state z_internal_state - -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#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). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# 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 - -/* 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. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -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 const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ -# define Z_HAVE_UNISTD_H -#endif - -#ifdef STDC -# include /* for off_t */ -#endif - -/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and - * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even - * though the former does not conform to the LFS document), but considering - * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as - * equivalently requesting no 64-bit operations - */ -#if -_LARGEFILE64_SOURCE - -1 == 1 -# undef _LARGEFILE64_SOURCE -#endif - -#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# ifndef z_off_t -# define z_off_t off_t -# endif -#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 - -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 -# define z_off64_t off64_t -#else -# define z_off64_t z_off_t -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -#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(deflateBound,"DEBND") - #pragma map(inflateInit_,"ININ") - #pragma map(inflateInit2_,"ININ2") - #pragma map(inflateEnd,"INEND") - #pragma map(inflateSync,"INSY") - #pragma map(inflateSetDictionary,"INSEDI") - #pragma map(compressBound,"CMBND") - #pragma map(inflate_table,"INTABL") - #pragma map(inflate_fast,"INFA") - #pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ diff --git a/thirdparty/include/zlib.h b/thirdparty/include/zlib.h index bfbba83e..3e0c7672 100644 --- a/thirdparty/include/zlib.h +++ b/thirdparty/include/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.5, April 19th, 2010 + version 1.2.8, April 28th, 2013 - Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2013 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 @@ -24,8 +24,8 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.5" -#define ZLIB_VERNUM 0x1250 +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /* @@ -83,15 +83,15 @@ typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ + z_const 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 */ + uLong total_in; /* total number 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 */ + uLong total_out; /* total number of bytes output so far */ - char *msg; /* last error message, NULL if no error */ + z_const 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 */ @@ -327,8 +327,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); 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 the - value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and 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). @@ -451,23 +452,29 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); 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 approach may be used for the single - inflate() call. + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK or Z_TREES is used. + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary + below), inflate sets strm->adler to the Adler-32 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, + strm->adler to the Adler-32 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 @@ -478,7 +485,9 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. 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 @@ -580,10 +589,15 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, 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). + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. 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 @@ -610,8 +624,8 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) 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(). + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, @@ -688,9 +702,29 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. */ +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); @@ -703,8 +737,9 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, than or equal to 16, and that many of the least significant bits of value will be inserted in the output. - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, @@ -790,10 +825,11 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is @@ -803,19 +839,38 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + 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 + Skips invalid compressed data until a possible full flush point (see above + for 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. + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible 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 inflateCopy OF((z_streamp dest, @@ -962,12 +1017,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, @@ -975,11 +1031,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. @@ -1088,6 +1145,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); 27-31: 0 (reserved) */ +#ifndef Z_SOLO /* utility functions */ @@ -1149,10 +1207,11 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, 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 or incomplete. + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. */ - /* gzip file access functions */ /* @@ -1162,7 +1221,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, wrapper, documented in RFC 1952, wrapped around a deflate stream. */ -typedef voidp gzFile; /* opaque gzip file descriptor */ +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); @@ -1172,13 +1231,28 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) Also "a" - can be used instead of "w" to request that the gzip stream that will be - written be appended to the file. "+" will result in an error, since reading - and writing to the same gzip file is not supported. + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. 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. + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was @@ -1197,7 +1271,11 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not @@ -1235,14 +1313,26 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); 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. + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream, or failing that, reading the rest - of the input file directly without decompression. The entire input file - will be read if gzread is called until it returns less than the requested - len. + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. @@ -1256,7 +1346,7 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, error. */ -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of @@ -1301,7 +1391,10 @@ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); 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. + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); @@ -1397,9 +1490,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. This state can change from - false to true while reading the input file if the end of a gzip stream is - reached, but is followed by data that is not another gzip stream. + (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. @@ -1408,6 +1499,13 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); @@ -1419,7 +1517,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, or Z_OK on success. + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); @@ -1457,6 +1556,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); file that is being written concurrently. */ +#endif /* !Z_SOLO */ /* checksum functions */ @@ -1492,16 +1592,17 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the for the crc. Pre- and post-conditioning (one's - complement) is performed within this function so it shouldn't be done by the - application. + 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: @@ -1544,17 +1645,42 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); #define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if @@ -1562,7 +1688,7 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +#ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); @@ -1571,14 +1697,23 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif -#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# ifdef _LARGEFILE64_SOURCE +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); @@ -1595,6 +1730,13 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; @@ -1603,8 +1745,21 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif #ifdef __cplusplus } diff --git a/thirdparty/liblcms2/include/lcms2.h b/thirdparty/liblcms2/include/lcms2.h index ef121cba..a0eeea73 100644 --- a/thirdparty/liblcms2/include/lcms2.h +++ b/thirdparty/liblcms2/include/lcms2.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.1 +// Version 2.6 // #ifndef _lcms2_H @@ -40,9 +40,6 @@ // Uncomment this if your compiler doesn't work with fast floor function // #define CMS_DONT_USE_FAST_FLOOR 1 -// Uncomment this line if your system does not support multithreading -#define CMS_DONT_USE_PTHREADS 1 - // Uncomment this line if you want lcms to use the black point tag in profile, // if commented, lcms will compute the black point by its own. // It is safer to leave it commented out @@ -55,6 +52,12 @@ // require "KEYWORD" on undefined identifiers, keep it comented out unless needed // #define CMS_STRICT_CGATS 1 +// Uncomment to get rid of the tables for "half" float support +// #define CMS_NO_HALF_SUPPORT 1 + +// Uncomment to get rid of pthreads/windows dependency +// #define CMS_NO_PTHREADS 1 + // ********** End of configuration toggles ****************************** // Needed for streams @@ -72,7 +75,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2010 +#define LCMS_VERSION 2060 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -81,6 +84,10 @@ extern "C" { typedef unsigned char cmsUInt8Number; // That is guaranteed by the C99 spec typedef signed char cmsInt8Number; // That is guaranteed by the C99 spec +#if CHAR_BIT != 8 +# error "Unable to find 8 bit type, unsupported compiler" +#endif + // IEEE float storage numbers typedef float cmsFloat32Number; typedef double cmsFloat64Number; @@ -169,26 +176,42 @@ typedef int cmsBool; // Try to detect big endian platforms. This list can be endless, so only some checks are performed over here. // you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar +#if defined(__sgi__) || defined(__sgi) || defined(sparc) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#if defined(__s390__) || defined(__s390x__) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +# ifdef TARGET_CPU_PPC +# if TARGET_CPU_PPC +# define CMS_USE_BIG_ENDIAN 1 +# endif +# endif + +#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC) +# define CMS_USE_BIG_ENDIAN 1 +# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +// // Don't use big endian for PowerPC little endian mode +# undef CMS_USE_BIG_ENDIAN +# endif +# endif +#endif + +// WORDS_BIGENDIAN takes precedence #if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) # define CMS_USE_BIG_ENDIAN 1 #endif -#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) -# define CMS_USE_BIG_ENDIAN 1 -#endif - -#if defined(__ppc__) || defined(__s390__) || defined(__s390x__) -# define CMS_USE_BIG_ENDIAN 1 -#endif - -#if TARGET_CPU_PPC -# define CMS_USE_BIG_ENDIAN 1 -#endif - #ifdef macintosh # ifdef __BIG_ENDIAN__ # define CMS_USE_BIG_ENDIAN 1 # endif +# ifdef __LITTLE_ENDIAN__ +# undef CMS_USE_BIG_ENDIAN +# endif #endif // Calling convention -- this is hardly platform and compiler dependent @@ -214,6 +237,14 @@ typedef int cmsBool; # define CMSAPI #endif +#ifdef HasTHREADS +# if HasTHREADS == 1 +# undef CMS_NO_PTHREADS +# else +# define CMS_NO_PTHREADS 1 +# endif +#endif + // Some common definitions #define cmsMAX_PATH 256 @@ -247,6 +278,7 @@ typedef enum { cmsSigCrdInfoType = 0x63726469, // 'crdi' cmsSigCurveType = 0x63757276, // 'curv' cmsSigDataType = 0x64617461, // 'data' + cmsSigDictType = 0x64696374, // 'dict' cmsSigDateTimeType = 0x6474696D, // 'dtim' cmsSigDeviceSettingsType = 0x64657673, // 'devs' cmsSigLut16Type = 0x6d667432, // 'mft2' @@ -273,9 +305,10 @@ typedef enum { cmsSigUInt32ArrayType = 0x75693332, // 'ui32' cmsSigUInt64ArrayType = 0x75693634, // 'ui64' cmsSigUInt8ArrayType = 0x75693038, // 'ui08' + cmsSigVcgtType = 0x76636774, // 'vcgt' cmsSigViewingConditionsType = 0x76696577, // 'view' - cmsSigXYZType = 0x58595A20, // 'XYZ ' - cmsSigVcgtType = 0x76636774 // 'vcgt' + cmsSigXYZType = 0x58595A20 // 'XYZ ' + } cmsTagTypeSignature; @@ -330,6 +363,7 @@ typedef enum { cmsSigPreview1Tag = 0x70726531, // 'pre1' cmsSigPreview2Tag = 0x70726532, // 'pre2' cmsSigProfileDescriptionTag = 0x64657363, // 'desc' + cmsSigProfileDescriptionMLTag = 0x6473636d, // 'dscm' cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq' cmsSigProfileSequenceIdTag = 0x70736964, // 'psid' cmsSigPs2CRD0Tag = 0x70736430, // 'psd0' @@ -348,7 +382,8 @@ typedef enum { cmsSigUcrBgTag = 0x62666420, // 'bfd ' cmsSigViewingCondDescTag = 0x76756564, // 'vued' cmsSigViewingConditionsTag = 0x76696577, // 'view' - cmsSigVcgtTag = 0x76636774 // 'vcgt' + cmsSigVcgtTag = 0x76636774, // 'vcgt' + cmsSigMetaTag = 0x6D657461 // 'meta' } cmsTagSignature; @@ -407,12 +442,12 @@ typedef enum { cmsSigMCH7Data = 0x4D434837, // 'MCH7' cmsSigMCH8Data = 0x4D434838, // 'MCH8' cmsSigMCH9Data = 0x4D434839, // 'MCH9' - cmsSigMCHAData = 0x4D43483A, // 'MCHA' - cmsSigMCHBData = 0x4D43483B, // 'MCHB' - cmsSigMCHCData = 0x4D43483C, // 'MCHC' - cmsSigMCHDData = 0x4D43483D, // 'MCHD' - cmsSigMCHEData = 0x4D43483E, // 'MCHE' - cmsSigMCHFData = 0x4D43483F, // 'MCHF' + cmsSigMCHAData = 0x4D434841, // 'MCHA' + cmsSigMCHBData = 0x4D434842, // 'MCHB' + cmsSigMCHCData = 0x4D434843, // 'MCHC' + cmsSigMCHDData = 0x4D434844, // 'MCHD' + cmsSigMCHEData = 0x4D434845, // 'MCHE' + cmsSigMCHFData = 0x4D434846, // 'MCHF' cmsSigNamedData = 0x6e6d636c, // 'nmcl' cmsSig1colorData = 0x31434C52, // '1CLR' cmsSig2colorData = 0x32434C52, // '2CLR' @@ -483,7 +518,13 @@ typedef enum { cmsSigLabV4toV2 = 0x34203220, // '4 2 ' // Identities - cmsSigIdentityElemType = 0x69646E20 // 'idn ' + cmsSigIdentityElemType = 0x69646E20, // 'idn ' + + // Float to floatPCS + cmsSigLab2FloatPCS = 0x64326C20, // 'd2l ' + cmsSigFloatPCS2Lab = 0x6C326420, // 'l2d ' + cmsSigXYZ2FloatPCS = 0x64327820, // 'd2x ' + cmsSigFloatPCS2XYZ = 0x78326420 // 'x2d ' } cmsStageSignature; @@ -597,7 +638,6 @@ typedef struct { // Little CMS specific typedefs -typedef void* cmsContext; // Context identifier for multithreaded environments typedef void* cmsHANDLE ; // Generic handle typedef void* cmsHPROFILE; // Opaque typedefs to hide internals typedef void* cmsHTRANSFORM; @@ -606,7 +646,9 @@ typedef void* cmsHTRANSFORM; // Format of pixel is defined by one cmsUInt32Number, using bit fields as follows // -// A O TTTTT U Y F P X S EEE CCCC BBB +// 2 1 0 +// 3 2 10987 6 5 4 3 2 1 098 7654 321 +// A O TTTTT U Y F P X S EEE CCCC BBB // // A: Floating point -- With this flag we can differentiate 16 bits as float and as int // O: Optimized -- previous optimization already returns the final 8-bit value @@ -714,16 +756,19 @@ typedef void* cmsHTRANSFORM; #define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) #define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) #define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) #define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) #define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) #define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) #define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) #define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) #define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) -#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) #define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)) #define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) @@ -805,8 +850,8 @@ typedef void* cmsHTRANSFORM; #define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)) #define TYPE_LabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)) -#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)) -#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)) +#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)) #define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)) #define TYPE_LabV2_16 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(2)) #define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2)) @@ -844,22 +889,40 @@ typedef void* cmsHTRANSFORM; // Float formatters. #define TYPE_XYZ_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4)) -#define TYPE_XYZA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)) #define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)) + #define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_ARGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)) +#define TYPE_BGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) +#define TYPE_BGRA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) + #define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) -// Floating point formatters. +// Floating point formatters. // NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield #define TYPE_XYZ_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0)) #define TYPE_Lab_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)) #define TYPE_GRAY_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0)) #define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_BGR_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1)) #define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) +// IEEE 754-2008 "half" +#define TYPE_GRAY_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_RGB_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_CMYK_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)) + +#define TYPE_RGBA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_ARGB_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_BGR_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_BGRA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ABGR_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) + #endif // Colorspaces @@ -944,10 +1007,25 @@ typedef struct { CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); -// Plug-In registering --------------------------------------------------------------------------------------------------- + +// Context handling -------------------------------------------------------------------------------------------------------- + +// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility +// though using the global context is not recomended. Proper context handling makes lcms more thread-safe. + +typedef struct _cmsContext_struct* cmsContext; + +CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData); +CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID); +CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData); +CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID); + +// Plug-In registering -------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); +CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); +CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID); // Error logging ---------------------------------------------------------------------------------------------------------- @@ -984,6 +1062,7 @@ typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Numb // Allows user to set any specific logger CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); +CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn); // Conversions -------------------------------------------------------------------------------------------------------------- @@ -1090,6 +1169,10 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); +// Tone curve tabular estimation +CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t); +CMSAPI const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t); + // Implements pipelines of multi-processing elements ------------------------------------------------------------- @@ -1102,6 +1185,7 @@ CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUIn CMSAPI void CMSEXPORT cmsPipelineFree(cmsPipeline* lut); CMSAPI cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig); +CMSAPI cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut); CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut); CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut); @@ -1118,7 +1202,7 @@ CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lu // Where to place/locate the stages in the pipeline chain typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc; -CMSAPI void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); +CMSAPI int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe); // This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements @@ -1162,10 +1246,9 @@ typedef cmsInt32Number (* cmsSAMPLERFLOAT)(register const cmsFloat32Number In[], #define SAMPLER_INSPECT 0x01000000 // For CLUT only -CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags); CMSAPI cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags); - // Slicers CMSAPI cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], cmsSAMPLER16 Sampler, void * Cargo); @@ -1203,6 +1286,13 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], char ObtainedLanguage[3], char ObtainedCountry[3]); +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu); + +CMSAPI cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]); + // Undercolorremoval & black generation ------------------------------------------------------------------------------------- typedef struct { @@ -1275,6 +1365,7 @@ CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform); // Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others // come from Profile Sequence Identifier Tag typedef struct { + cmsSignature deviceMfg; cmsSignature deviceModel; cmsUInt64Number attributes; @@ -1298,6 +1389,27 @@ CMSAPI cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext CMSAPI cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq); CMSAPI void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq); +// Dictionaries -------------------------------------------------------------------------------------------------------- + +typedef struct _cmsDICTentry_struct { + + struct _cmsDICTentry_struct* Next; + + cmsMLU *DisplayName; + cmsMLU *DisplayValue; + wchar_t* Name; + wchar_t* Value; + +} cmsDICTentry; + +CMSAPI cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsDictFree(cmsHANDLE hDict); +CMSAPI cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict); + +CMSAPI cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue); +CMSAPI const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict); +CMSAPI const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e); + // Access to Profile data ---------------------------------------------------------------------------------------------- CMSAPI cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID); @@ -1317,9 +1429,9 @@ CMSAPI cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSig CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size); // Access header data -#define cmsEmbeddedProfileFalse 0x00000000 -#define cmsEmbeddedProfileTrue 0x00000001 -#define cmsUseAnywhere 0x00000000 +#define cmsEmbeddedProfileFalse 0x00000000 +#define cmsEmbeddedProfileTrue 0x00000001 +#define cmsUseAnywhere 0x00000000 #define cmsUseWithEmbeddedDataOnly 0x00000002 CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile); @@ -1331,6 +1443,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProf CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile); CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile); CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model); CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags); @@ -1411,6 +1524,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext Context CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write); CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName); @@ -1501,6 +1615,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransfo // Call with NULL as parameters to get the intent count CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); // Flags @@ -1605,18 +1720,40 @@ CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void * OutputBuffer, cmsUInt32Number Size); -CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, + const void * InputBuffer, + void * OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); + + +CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + +CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, + const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); + + + // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d); + + // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); +// Grab the input/output formats +CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform); + // For backwards compatibility -CMSAPI cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, - cmsUInt32Number InputFormat, +CMSAPI cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat); @@ -1663,12 +1800,15 @@ CMSAPI cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* c CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* cProp, const char *Str); CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val); CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer); CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer); CMSAPI const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* cProp); CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp); +CMSAPI const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey); CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames); +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames); // Datasets CMSAPI const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col); @@ -1698,10 +1838,13 @@ CMSAPI cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE hIT8, int n, con CMSAPI int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames); CMSAPI const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer); +CMSAPI int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch); // The LABEL extension CMSAPI int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); +CMSAPI cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample); + // Formatter for double CMSAPI void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter); @@ -1717,6 +1860,7 @@ CMSAPI cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIEL // Estimate the black point CMSAPI cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags); // Estimate total area coverage CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile); diff --git a/thirdparty/liblcms2/include/lcms2_plugin.h b/thirdparty/liblcms2/include/lcms2_plugin.h index 896fa498..0c95d1f7 100644 --- a/thirdparty/liblcms2/include/lcms2_plugin.h +++ b/thirdparty/liblcms2/include/lcms2_plugin.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -131,7 +131,7 @@ struct _cms_io_handler { // Endianess adjust functions CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word); CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value); -CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord); +CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord); // Helper IO functions CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n); @@ -147,7 +147,7 @@ CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUI CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n); CMSAPI cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n); CMSAPI cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n); -CMSAPI cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n); CMSAPI cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n); CMSAPI cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ); CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array); @@ -181,6 +181,11 @@ CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v); CMSAPI void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source); CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest); +//---------------------------------------------------------------------------------------------------------- + +// Shared callbacks for user data +typedef void (* _cmsFreeUserDataFn)(cmsContext ContextID, void* Data); +typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data); //---------------------------------------------------------------------------------------------------------- @@ -196,6 +201,8 @@ CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeN #define cmsPluginRenderingIntentSig 0x696E7448 // 'intH' #define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' #define cmsPluginOptimizationSig 0x6F707448 // 'optH' +#define cmsPluginTransformSig 0x7A666D48 // 'xfmH' +#define cmsPluginMutexSig 0x6D747A48 // 'mtxH' typedef struct _cmsPluginBaseStruct { @@ -212,19 +219,28 @@ typedef struct _cmsPluginBaseStruct { //---------------------------------------------------------------------------------------------------------- // Memory handler. Each new plug-in type replaces current behaviour + +typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr); +typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + +typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + typedef struct { cmsPluginBase base; // Required - void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size); - void (* FreePtr)(cmsContext ContextID, void *Ptr); - void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + _cmsMallocFnPtrType MallocPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; // Optional - void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size); - void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); - void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; } cmsPluginMemHandler; @@ -387,7 +403,7 @@ typedef struct _cms_typehandler_struct { void *Ptr); // Additional parameters used by the calling thread - cmsContext ContextID; + cmsContext ContextID; cmsUInt32Number ICCVersion; } cmsTagTypeHandler; @@ -486,6 +502,39 @@ typedef struct { } cmsPluginMultiProcessElement; + +// Data kept in "Element" member of cmsStage + +// Curves +typedef struct { + cmsUInt32Number nCurves; + cmsToneCurve** TheCurves; + +} _cmsStageToneCurvesData; + +// Matrix +typedef struct { + cmsFloat64Number* Double; // floating point for the matrix + cmsFloat64Number* Offset; // The offset + +} _cmsStageMatrixData; + +// CLUT +typedef struct { + + union { // Can have only one of both representations at same time + cmsUInt16Number* T; // Points to the table 16 bits table + cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table + + } Tab; + + cmsInterpParams* Params; + cmsUInt32Number nEntries; + cmsBool HasFloatValues; + +} _cmsStageCLutData; + + //---------------------------------------------------------------------------------------------------------- // Optimization. Using this plug-in, additional optimization strategies may be implemented. // The function should return TRUE if any optimization is done on the LUT, this terminates @@ -496,9 +545,6 @@ typedef void (* _cmsOPTeval16Fn)(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* Data); -typedef void (* _cmsOPTfreeDataFn)(cmsContext ContextID, void* Data); -typedef void* (* _cmsOPTdupDataFn)(cmsContext ContextID, const void* Data); - typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, cmsUInt32Number Intent, @@ -512,8 +558,8 @@ typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, _cmsOPTeval16Fn Eval16, void* PrivateData, - _cmsOPTfreeDataFn FreePrivateDataFn, - _cmsOPTdupDataFn DupPrivateDataFn); + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn); typedef struct { cmsPluginBase base; @@ -524,6 +570,62 @@ typedef struct { } cmsPluginOptimization; //---------------------------------------------------------------------------------------------------------- +// Full xform +typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); + +typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* xform, + void** UserData, + _cmsFreeUserDataFn* FreePrivateDataFn, + cmsPipeline** Lut, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + + +// Retrieve user data as specified by the factory +CMSAPI void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn); +CMSAPI void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo); + + +// Retrieve formatters +CMSAPI void CMSEXPORT _cmsGetTransformFormatters16 (struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput); +CMSAPI void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput); + +typedef struct { + cmsPluginBase base; + + // Transform entry point + _cmsTransformFactory Factory; + +} cmsPluginTransform; + +//---------------------------------------------------------------------------------------------------------- +// Mutex + +typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID); +typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx); + +typedef struct { + cmsPluginBase base; + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} cmsPluginMutex; + +CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID); +CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); +CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx); +CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx); + #ifndef CMS_USE_CPP_API # ifdef __cplusplus diff --git a/thirdparty/liblcms2/src/cmscam02.c b/thirdparty/liblcms2/src/cmscam02.c index 08eea16a..9d874aa2 100644 --- a/thirdparty/liblcms2/src/cmscam02.c +++ b/thirdparty/liblcms2/src/cmscam02.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -31,7 +31,7 @@ // ---------- Implementation -------------------------------------------- typedef struct { - + cmsFloat64Number XYZ[3]; cmsFloat64Number RGB[3]; cmsFloat64Number RGBc[3]; @@ -41,55 +41,55 @@ typedef struct { cmsFloat64Number abC[2]; cmsFloat64Number abs[2]; cmsFloat64Number abM[2]; - + } CAM02COLOR; typedef struct { - + CAM02COLOR adoptedWhite; cmsFloat64Number LA, Yb; cmsFloat64Number F, c, Nc; cmsUInt32Number surround; cmsFloat64Number n, Nbb, Ncb, z, FL, D; - - cmsContext ContextID; + + cmsContext ContextID; } cmsCIECAM02; static -cmsFloat64Number compute_n(cmsCIECAM02* pMod) +cmsFloat64Number compute_n(cmsCIECAM02* pMod) { return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]); } static -cmsFloat64Number compute_z(cmsCIECAM02* pMod) +cmsFloat64Number compute_z(cmsCIECAM02* pMod) { return (1.48 + pow(pMod -> n, 0.5)); } static -cmsFloat64Number computeNbb(cmsCIECAM02* pMod) +cmsFloat64Number computeNbb(cmsCIECAM02* pMod) { return (0.725 * pow((1.0 / pMod -> n), 0.2)); } static -cmsFloat64Number computeFL(cmsCIECAM02* pMod) +cmsFloat64Number computeFL(cmsCIECAM02* pMod) { cmsFloat64Number k, FL; - + k = 1.0 / ((5.0 * pMod->LA) + 1.0); FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 * (pow((1.0 - pow(k, 4.0)), 2.0)) * (pow((5.0 * pMod->LA), (1.0 / 3.0))); - + return FL; } -static -cmsFloat64Number computeD(cmsCIECAM02* pMod) +static +cmsFloat64Number computeD(cmsCIECAM02* pMod) { cmsFloat64Number D; @@ -100,17 +100,17 @@ cmsFloat64Number computeD(cmsCIECAM02* pMod) static -CAM02COLOR XYZtoCAT02(CAM02COLOR clr) +CAM02COLOR XYZtoCAT02(CAM02COLOR clr) { clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624); clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061); clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834); - + return clr; } static -CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) { cmsUInt32Number i; @@ -120,15 +120,15 @@ CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) (1.0 - pMod->D)) * clr.RGB[i]; } - return clr; + return clr; } static -CAM02COLOR CAT02toHPE(CAM02COLOR clr) +CAM02COLOR CAT02toHPE(CAM02COLOR clr) { cmsFloat64Number M[9]; - + M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628)); M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698)); M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326)); @@ -138,16 +138,16 @@ CAM02COLOR CAT02toHPE(CAM02COLOR clr) M[6] =(-0.009628); M[7] =(-0.005698); M[8] =( 1.015326); - + clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]); clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]); clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]); - + return clr; } static -CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) +CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) { cmsUInt32Number i; cmsFloat64Number temp; @@ -163,21 +163,21 @@ CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; } } - - clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + + + clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; return clr; } static -CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) { cmsFloat64Number a, b, temp, e, t, r2d, d2r; a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0); b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0; - + r2d = (180.0 / 3.141592654); if (a == 0) { if (b == 0) clr.h = 0; @@ -194,11 +194,11 @@ CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) temp = b / a; clr.h = (r2d * atan(temp)) + 180; } - + d2r = (3.141592654 / 180.0); - e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * - (cos((clr.h * d2r + 2.0)) + 3.8); - + e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * + (cos((clr.h * d2r + 2.0)) + 3.8); + if (clr.h < 20.14) { temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8); clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp; @@ -219,15 +219,15 @@ CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8); clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); } - - clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), + + clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), (pMod->c * pMod->z)); clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) * (pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25); - + t = (e * pow(((a * a) + (b * b)), 0.5)) / - (clr.RGBpa[0] + clr.RGBpa[1] + + (clr.RGBpa[0] + clr.RGBpa[1] + ((21.0 / 20.0) * clr.RGBpa[2])); clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) * @@ -235,34 +235,34 @@ CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) clr.M = clr.C * pow(pMod->FL, 0.25); clr.s = 100.0 * pow((clr.M / clr.Q), 0.5); - + return clr; } static -CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) { - + cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r; d2r = 3.141592654 / 180.0; - + t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) * - (pow((1.64 - pow(0.29, pMod->n)), 0.73)))), + (pow((1.64 - pow(0.29, pMod->n)), 0.73)))), (1.0 / 0.9) ); e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * (cos((clr.h * d2r + 2.0)) + 3.8); - + clr.A = pMod->adoptedWhite.A * pow( (clr.J / 100.0), (1.0 / (pMod->c * pMod->z))); - + p1 = e / t; p2 = (clr.A / pMod->Nbb) + 0.305; p3 = 21.0 / 20.0; - + hr = clr.h * d2r; - + if (fabs(sin(hr)) >= fabs(cos(hr))) { p4 = p1 / sin(hr); clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / @@ -279,17 +279,17 @@ CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) (sin(hr) / cos(hr))); clr.b = clr.a * (sin(hr) / cos(hr)); } - - clr.RGBpa[0] = ((460.0 / 1403.0) * p2) + + + clr.RGBpa[0] = ((460.0 / 1403.0) * p2) + ((451.0 / 1403.0) * clr.a) + ((288.0 / 1403.0) * clr.b); - clr.RGBpa[1] = ((460.0 / 1403.0) * p2) - + clr.RGBpa[1] = ((460.0 / 1403.0) * p2) - ((891.0 / 1403.0) * clr.a) - ((261.0 / 1403.0) * clr.b); clr.RGBpa[2] = ((460.0 / 1403.0) * p2) - ((220.0 / 1403.0) * clr.a) - ((6300.0 / 1403.0) * clr.b); - + return clr; } @@ -298,7 +298,7 @@ CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod) { cmsUInt32Number i; cmsFloat64Number c1; - + for (i = 0; i < 3; i++) { if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1; else c1 = 1; @@ -307,15 +307,15 @@ CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod) (400.0 - fabs(clr.RGBpa[i] - 0.1))), (1.0 / 0.42)); } - + return clr; } static -CAM02COLOR HPEtoCAT02(CAM02COLOR clr) +CAM02COLOR HPEtoCAT02(CAM02COLOR clr) { cmsFloat64Number M[9]; - + M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950)); M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054)); M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624); @@ -325,7 +325,7 @@ CAM02COLOR HPEtoCAT02(CAM02COLOR clr) M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; - + clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]); @@ -334,10 +334,10 @@ CAM02COLOR HPEtoCAT02(CAM02COLOR clr) static -CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) { cmsUInt32Number i; - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) { clr.RGB[i] = clr.RGBc[i] / ((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D); } @@ -346,82 +346,82 @@ CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) static -CAM02COLOR CAT02toXYZ(CAM02COLOR clr) +CAM02COLOR CAT02toXYZ(CAM02COLOR clr) { clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745); clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098); clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326); - + return clr; } cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC) { - cmsCIECAM02* lpMod; + cmsCIECAM02* lpMod; - _cmsAssert(pVC != NULL); + _cmsAssert(pVC != NULL); - if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { - return NULL; - } + if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { + return NULL; + } - lpMod ->ContextID = ContextID; + lpMod ->ContextID = ContextID; - lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; - lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; - lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; + lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; + lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; + lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; - lpMod -> LA = pVC ->La; - lpMod -> Yb = pVC ->Yb; - lpMod -> D = pVC ->D_value; - lpMod -> surround = pVC ->surround; + lpMod -> LA = pVC ->La; + lpMod -> Yb = pVC ->Yb; + lpMod -> D = pVC ->D_value; + lpMod -> surround = pVC ->surround; - switch (lpMod -> surround) { + switch (lpMod -> surround) { - case CUTSHEET_SURROUND: - lpMod->F = 0.8; - lpMod->c = 0.41; - lpMod->Nc = 0.8; - break; + case CUTSHEET_SURROUND: + lpMod->F = 0.8; + lpMod->c = 0.41; + lpMod->Nc = 0.8; + break; - case DARK_SURROUND: - lpMod -> F = 0.8; - lpMod -> c = 0.525; - lpMod -> Nc = 0.8; - break; + case DARK_SURROUND: + lpMod -> F = 0.8; + lpMod -> c = 0.525; + lpMod -> Nc = 0.8; + break; - case DIM_SURROUND: - lpMod -> F = 0.9; - lpMod -> c = 0.59; - lpMod -> Nc = 0.95; - break; + case DIM_SURROUND: + lpMod -> F = 0.9; + lpMod -> c = 0.59; + lpMod -> Nc = 0.95; + break; - default: - // Average surround - lpMod -> F = 1.0; - lpMod -> c = 0.69; - lpMod -> Nc = 1.0; - } + default: + // Average surround + lpMod -> F = 1.0; + lpMod -> c = 0.69; + lpMod -> Nc = 1.0; + } - lpMod -> n = compute_n(lpMod); - lpMod -> z = compute_z(lpMod); - lpMod -> Nbb = computeNbb(lpMod); - lpMod -> FL = computeFL(lpMod); + lpMod -> n = compute_n(lpMod); + lpMod -> z = compute_z(lpMod); + lpMod -> Nbb = computeNbb(lpMod); + lpMod -> FL = computeFL(lpMod); - if (lpMod -> D == D_CALCULATE) { - lpMod -> D = computeD(lpMod); - } + if (lpMod -> D == D_CALCULATE) { + lpMod -> D = computeD(lpMod); + } - lpMod -> Ncb = lpMod -> Nbb; + lpMod -> Ncb = lpMod -> Nbb; - lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); - lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); - lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); - lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); + lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); + lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); - return (cmsHANDLE) lpMod; + return (cmsHANDLE) lpMod; } @@ -429,32 +429,34 @@ void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel) { cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - if (lpMod) _cmsFree(lpMod ->ContextID, lpMod); + if (lpMod) _cmsFree(lpMod ->ContextID, lpMod); } void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut) -{ +{ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - _cmsAssert(lpMod != NULL); - _cmsAssert(pIn != NULL); - _cmsAssert(pOut != NULL); + + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + memset(&clr, 0, sizeof(clr)); clr.XYZ[0] = pIn ->X; clr.XYZ[1] = pIn ->Y; clr.XYZ[2] = pIn ->Z; - + clr = XYZtoCAT02(clr); clr = ChromaticAdaptation(clr, lpMod); clr = CAT02toHPE(clr); clr = NonlinearCompression(clr, lpMod); clr = ComputeCorrelates(clr, lpMod); - + pOut ->J = clr.J; pOut ->C = clr.C; - pOut ->h = clr.h; + pOut ->h = clr.h; } void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut) @@ -462,22 +464,23 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - _cmsAssert(lpMod != NULL); - _cmsAssert(pIn != NULL); - _cmsAssert(pOut != NULL); + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + memset(&clr, 0, sizeof(clr)); clr.J = pIn -> J; clr.C = pIn -> C; clr.h = pIn -> h; - + clr = InverseCorrelates(clr, lpMod); clr = InverseNonlinearity(clr, lpMod); clr = HPEtoCAT02(clr); clr = InverseChromaticAdaptation(clr, lpMod); clr = CAT02toXYZ(clr); - + pOut ->X = clr.XYZ[0]; pOut ->Y = clr.XYZ[1]; pOut ->Z = clr.XYZ[2]; } - diff --git a/thirdparty/liblcms2/src/cmscgats.c b/thirdparty/liblcms2/src/cmscgats.c index d41c15a2..099b07bb 100644 --- a/thirdparty/liblcms2/src/cmscgats.c +++ b/thirdparty/liblcms2/src/cmscgats.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -30,8 +30,8 @@ // IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- -#define MAXID 128 // Max lenght of identifier -#define MAXSTR 1024 // Max lenght of string +#define MAXID 128 // Max length of identifier +#define MAXSTR 1024 // Max length of string #define MAXTABLES 255 // Max Number of tables in a single stream #define MAXINCLUDE 20 // Max number of nested includes @@ -44,8 +44,9 @@ # define DIR_CHAR '/' #endif + // Symbols -typedef enum { +typedef enum { SNONE, SINUM, // Integer @@ -71,10 +72,10 @@ typedef enum { // How to write the value -typedef enum { +typedef enum { WRITE_UNCOOKED, - WRITE_STRINGIFY, + WRITE_STRINGIFY, WRITE_HEXADECIMAL, WRITE_BINARY, WRITE_PAIR @@ -108,19 +109,21 @@ typedef struct _SubAllocator { cmsUInt8Number* Block; cmsUInt32Number BlockSize; cmsUInt32Number Used; - + } SUBALLOCATOR; // Table. Each individual table can hold properties and rows & cols typedef struct _Table { - + + char SheetType[MAXSTR]; // The first row of the IT8 (the type) + int nSamples, nPatches; // Cols, Rows int SampleID; // Pos of ID - + KEYVALUE* HeaderList; // The properties - + char** DataFormat; // The binary stream descriptor - char** Data; // The binary stream + char** Data; // The binary stream } TABLE; @@ -130,10 +133,9 @@ typedef struct _FileContext { FILE* Stream; // File stream or NULL if holded in memory } FILECTX; -// This struct hold all information about an open IT8 handler. +// This struct hold all information about an open IT8 handler. typedef struct { - char SheetType[MAXSTR]; // The first row of the IT8 (the type) cmsUInt32Number TablesCount; // How many tables in this stream cmsUInt32Number nTable; // The actual table @@ -147,7 +149,7 @@ typedef struct { // Parser state machine SYMBOL sy; // Current symbol int ch; // Current character - + int inum; // integer value cmsFloat64Number dnum; // real value char id[MAXID]; // identifier @@ -156,10 +158,10 @@ typedef struct { // Allowed keywords & datasets. They have visibility on whole stream KEYVALUE* ValidKeywords; KEYVALUE* ValidSampleID; - + char* Source; // Points to loc. being parsed int lineno; // line counter for error reporting - + FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed int IncludeSP; // Include Stack Pointer @@ -198,7 +200,7 @@ typedef struct { // The keyword->symbol translation table. Sorting is required. static const KEYWORD TabKeys[] = { - + {"$INCLUDE", SINCLUDE}, // This is an extension! {".INCLUDE", SINCLUDE}, // This is an extension! @@ -259,31 +261,31 @@ static PROPERTY PredefinedProperties[] = { // below properties are new in recent specs: - {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated - // along with details of the geometry and the aperture size and shape. For example, - // for transmission measurements it is important to identify 0/diffuse, diffuse/0, - // opal or integrating sphere, etc. For reflection it is important to identify 0/45, + {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated + // along with details of the geometry and the aperture size and shape. For example, + // for transmission measurements it is important to identify 0/diffuse, diffuse/0, + // opal or integrating sphere, etc. For reflection it is important to identify 0/45, // 45/0, sphere (specular included or excluded), etc. - {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to + {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to // denote the use of filters such as none, D65, Red, Green or Blue. - {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed // values are {"yes”, “white”, “none” or “na”. - {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the - // calculation of various data parameters (2 degree and 10 degree), CIE standard + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard // illuminant functions used in the calculation of various data parameters (e.g., D50, - // D65, etc.), density status response, etc. If used there shall be at least one - // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute + // D65, etc.), density status response, etc. If used there shall be at least one + // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute // in the set shall be {"name" and shall identify the particular parameter used. - // The second shall be {"value" and shall provide the value associated with that name. - // For ASCII data, a string containing the Name and Value attribute pairs shall follow - // the weighting function keyword. A semi-colon separates attribute pairs from each + // The second shall be {"value" and shall provide the value associated with that name. + // For ASCII data, a string containing the Name and Value attribute pairs shall follow + // the weighting function keyword. A semi-colon separates attribute pairs from each // other and within the attribute the name and value are separated by a comma. - {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name - // of the calculation, parameter is the name of the parameter used in the calculation + {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name + // of the calculation, parameter is the name of the parameter used in the calculation // and value is the value of the parameter. {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. @@ -301,7 +303,7 @@ static PROPERTY PredefinedProperties[] = { // Predefined sample types on dataset static const char* PredefinedSampleID[] = { "SAMPLE_ID", // Identifies sample that data represents - "STRING", // Identifies label, or other non-machine readable value. + "STRING", // Identifies label, or other non-machine readable value. // Value must begin and end with a " symbol "CMYK_C", // Cyan component of CMYK data expressed as a percentage @@ -349,31 +351,31 @@ static const char* PredefinedSampleID[] = { #define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) -//Forward declaration of some internal functions +//Forward declaration of some internal functions static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); -// Checks if c is a separator +// Checks whatever c is a separator static cmsBool isseparator(int c) { - return (c == ' ') || (c == '\t') || (c == '\r'); + return (c == ' ') || (c == '\t') ; } -// Checks whatever if c is a valid identifier char -static +// Checks whatever c is a valid identifier char +static cmsBool ismiddle(int c) { return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); } -// Checks whatsever if c is a valid identifier middle char. +// Checks whatsever c is a valid identifier middle char. static cmsBool isidchar(int c) { return isalnum(c) || ismiddle(c); } -// Checks whatsever if c is a valid identifier first char. +// Checks whatsever c is a valid identifier first char. static cmsBool isfirstidchar(int c) { @@ -388,7 +390,7 @@ cmsBool isabsolutepath(const char *path) if(path == NULL) return FALSE; - if (path[0] == 0) + if (path[0] == 0) return FALSE; strncpy(ThreeChars, path, 3); @@ -404,9 +406,10 @@ cmsBool isabsolutepath(const char *path) return FALSE; } + // Makes a file path based on a given reference path // NOTE: this function doesn't check if the path exists or even if it's legal -static +static cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen) { char *tail; @@ -420,8 +423,8 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe return TRUE; } - // No, search for last - strncpy(buffer, basePath, MaxLen); + // No, search for last + strncpy(buffer, basePath, MaxLen); buffer[MaxLen-1] = 0; tail = strrchr(buffer, DIR_CHAR); @@ -431,9 +434,9 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe if (len >= MaxLen) return FALSE; // No need to assure zero terminator over here - strncpy(tail + 1, relPath, MaxLen - len); + strncpy(tail + 1, relPath, MaxLen - len); - return TRUE; + return TRUE; } @@ -441,7 +444,7 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe static const char* NoMeta(const char* str) { - if (strchr(str, '%') != NULL) + if (strchr(str, '%') != NULL) return "**** CORRUPTED FORMAT STRING ***"; return str; @@ -492,7 +495,7 @@ void NextCh(cmsIT8* it8) } else it8 ->ch = 0; // EOF - } + } } else { it8->ch = *it8->Source; @@ -545,7 +548,7 @@ void ReadReal(cmsIT8* it8, int inum) if (it8->ch == '.') { // Decimal point cmsFloat64Number frac = 0.0; // fraction - int prec = 0; // precision + int prec = 0; // precision NextCh(it8); // Eats dec. point @@ -592,6 +595,84 @@ void ReadReal(cmsIT8* it8, int inum) } } +// Parses a float number +// This can not call directly atof because it uses locale dependant +// parsing, while CCMX files always use . as decimal separator +static +cmsFloat64Number ParseFloatNumber(const char *Buffer) +{ + cmsFloat64Number dnum = 0.0; + int sign = 1; + + // keep safe + if (Buffer == NULL) return 0.0; + + if (*Buffer == '-' || *Buffer == '+') { + + sign = (*Buffer == '-') ? -1 : 1; + Buffer++; + } + + + while (*Buffer && isdigit((int) *Buffer)) { + + dnum = dnum * 10.0 + (*Buffer - '0'); + if (*Buffer) Buffer++; + } + + if (*Buffer == '.') { + + cmsFloat64Number frac = 0.0; // fraction + int prec = 0; // precission + + if (*Buffer) Buffer++; + + while (*Buffer && isdigit((int) *Buffer)) { + + frac = frac * 10.0 + (*Buffer - '0'); + prec++; + if (*Buffer) Buffer++; + } + + dnum = dnum + (frac / xpow10(prec)); + } + + // Exponent, example 34.00E+20 + if (*Buffer && toupper(*Buffer) == 'E') { + + int e; + int sgn; + + if (*Buffer) Buffer++; + sgn = 1; + + if (*Buffer == '-') { + + sgn = -1; + if (*Buffer) Buffer++; + } + else + if (*Buffer == '+') { + + sgn = +1; + if (*Buffer) Buffer++; + } + + e = 0; + while (*Buffer && isdigit((int) *Buffer)) { + + if ((cmsFloat64Number) e * 10L < INT_MAX) + e = e * 10 + (*Buffer - '0'); + + if (*Buffer) Buffer++; + } + + e = sgn*e; + dnum = dnum * xpow10(e); + } + + return sign * dnum; +} // Reads next symbol @@ -604,92 +685,92 @@ void InSymbol(cmsIT8* it8) int sng; do { - + while (isseparator(it8->ch)) NextCh(it8); - + if (isfirstidchar(it8->ch)) { // Identifier - + k = 0; idptr = it8->id; - + do { - + if (++k < MAXID) *idptr++ = (char) it8->ch; - + NextCh(it8); - + } while (isidchar(it8->ch)); - + *idptr = '\0'; - - + + key = BinSrchKey(it8->id); if (key == SNONE) it8->sy = SIDENT; else it8->sy = key; - + } else // Is a number? if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+') { int sign = 1; - + if (it8->ch == '-') { sign = -1; NextCh(it8); } - + it8->inum = 0; it8->sy = SINUM; - + if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary) - + NextCh(it8); if (toupper(it8->ch) == 'X') { int j; - + NextCh(it8); while (isxdigit(it8->ch)) { it8->ch = toupper(it8->ch); if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10; else j = it8->ch - '0'; - + if ((long) it8->inum * 16L > (long) INT_MAX) { SynError(it8, "Invalid hexadecimal number"); return; } - + it8->inum = it8->inum * 16 + j; NextCh(it8); } return; } - + if (toupper(it8->ch) == 'B') { // Binary - + int j; - + NextCh(it8); while (it8->ch == '0' || it8->ch == '1') { j = it8->ch - '0'; - + if ((long) it8->inum * 2L > (long) INT_MAX) { SynError(it8, "Invalid binary number"); return; } - + it8->inum = it8->inum * 2 + j; NextCh(it8); } return; } } - + while (isdigit(it8->ch)) { @@ -699,19 +780,19 @@ void InSymbol(cmsIT8* it8) it8->dnum *= sign; return; } - + it8->inum = it8->inum * 10 + (it8->ch - '0'); NextCh(it8); } - + if (it8->ch == '.') { - + ReadReal(it8, it8->inum); it8->sy = SDNUM; it8->dnum *= sign; return; } - + it8 -> inum *= sign; // Special case. Numbers followed by letters are taken as identifiers @@ -730,18 +811,18 @@ void InSymbol(cmsIT8* it8) k = (int) strlen(it8 ->id); idptr = it8 ->id + k; do { - + if (++k < MAXID) *idptr++ = (char) it8->ch; - + NextCh(it8); - + } while (isidchar(it8->ch)); - - *idptr = '\0'; + + *idptr = '\0'; it8->sy = SIDENT; } return; - + } else switch ((int) it8->ch) { @@ -756,24 +837,32 @@ void InSymbol(cmsIT8* it8) case -1: it8->sy = SEOF; break; - - - // Next line + + + // Next line + case '\r': + NextCh(it8); + if (it8 ->ch == '\n') + NextCh(it8); + it8->sy = SEOLN; + it8->lineno++; + break; + case '\n': NextCh(it8); it8->sy = SEOLN; it8->lineno++; break; - + // Comment case '#': NextCh(it8); - while (it8->ch && it8->ch != '\n') + while (it8->ch && it8->ch != '\n' && it8->ch != '\r') NextCh(it8); - + it8->sy = SCOMMENT; break; - + // String. case '\'': case '\"': @@ -781,28 +870,28 @@ void InSymbol(cmsIT8* it8) sng = it8->ch; k = 0; NextCh(it8); - + while (k < MAXSTR && it8->ch != sng) { - + if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; - else { + else { *idptr++ = (char) it8->ch; NextCh(it8); k++; } } - + it8->sy = SSTRING; *idptr = '\0'; NextCh(it8); break; - - + + default: - SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); - return; + SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); + return; } - + } while (it8->sy == SCOMMENT); // Handle the include special token @@ -828,8 +917,8 @@ void InSymbol(cmsIT8* it8) // TODO: how to manage out-of-memory conditions? } - if (BuildAbsolutePath(it8->str, - it8->FileStack[it8->IncludeSP]->FileName, + if (BuildAbsolutePath(it8->str, + it8->FileStack[it8->IncludeSP]->FileName, FileNest->FileName, cmsMAX_PATH-1) == FALSE) { SynError(it8, "File path too long"); return; @@ -844,9 +933,9 @@ void InSymbol(cmsIT8* it8) it8->IncludeSP++; it8 ->ch = ' '; - InSymbol(it8); + InSymbol(it8); } - + } // Checks end of line separator @@ -886,12 +975,15 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error { switch (it8->sy) { - case SIDENT: strncpy(Buffer, it8->id, max); + case SEOLN: // Empty value + Buffer[0]=0; + break; + case SIDENT: strncpy(Buffer, it8->id, max); Buffer[max-1]=0; break; case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; - case SSTRING: strncpy(Buffer, it8->str, max); + case SSTRING: strncpy(Buffer, it8->str, max); Buffer[max-1] = 0; break; @@ -908,12 +1000,12 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error static TABLE* GetTable(cmsIT8* it8) -{ +{ if ((it8 -> nTable >= it8 ->TablesCount)) { SynError(it8, "Table %d out of sequence", it8 -> nTable); return it8 -> Tab; - } + } return it8 ->Tab + it8 ->nTable; } @@ -943,7 +1035,7 @@ void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8) } if (it8->MemoryBlock) - _cmsFree(it8 ->ContextID, it8->MemoryBlock); + _cmsFree(it8 ->ContextID, it8->MemoryBlock); _cmsFree(it8 ->ContextID, it8); } @@ -982,7 +1074,7 @@ void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; cmsUInt8Number* ptr; - size = _cmsALIGNLONG(size); + size = _cmsALIGNMEM(size); if (size > Free) { @@ -998,12 +1090,12 @@ void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) it8 ->Allocator.Used = 0; it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize); } - + ptr = it8 ->Allocator.Block + it8 ->Allocator.Used; it8 ->Allocator.Used += size; return (void*) ptr; - + } @@ -1019,7 +1111,7 @@ char *AllocString(cmsIT8* it8, const char* str) if (ptr) strncpy (ptr, str, Size-1); return ptr; -} +} // Searches through linked list @@ -1035,9 +1127,9 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV if (*Key != '#') { // Comments are ignored if (cmsstrcasecmp(Key, p->Keyword) == 0) - break; - } + break; } + } if (p == NULL) return FALSE; @@ -1047,11 +1139,13 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV for (; p != NULL; p = p->NextSubkey) { + if (p ->Subkey == NULL) continue; + if (LastPtr) *LastPtr = p; if (cmsstrcasecmp(Subkey, p->Subkey) == 0) - return TRUE; - } + return TRUE; + } return FALSE; } @@ -1066,13 +1160,13 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S KEYVALUE* last; - // Check if property is already in list + // Check if property is already in list if (IsAvailableOnList(*Head, Key, Subkey, &p)) { // This may work for editing properties - // return SynError(it8, "duplicate key <%s>", Key); + // return SynError(it8, "duplicate key <%s>", Key); } else { @@ -1082,7 +1176,7 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); if (p == NULL) { - SynError(it8, "AddToList: out of memory"); + SynError(it8, "AddToList: out of memory"); return NULL; } @@ -1097,13 +1191,13 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S else { if (Subkey != NULL && last != NULL) { - + last->NextSubkey = p; // If Subkey is not null, then last is the last property with the same key, // but not necessarily is the last property in the list, so we need to move // to the actual list end - while (last->Next != NULL) + while (last->Next != NULL) last = last->Next; } @@ -1151,7 +1245,7 @@ void AllocTable(cmsIT8* it8) t->HeaderList = NULL; t->DataFormat = NULL; t->Data = NULL; - + it8 ->TablesCount++; } @@ -1174,7 +1268,7 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) it8 ->nTable = nTable; - return nTable; + return (cmsInt32Number) nTable; } @@ -1183,22 +1277,22 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) { cmsIT8* it8; - int i; + cmsUInt32Number i; it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); if (it8 == NULL) return NULL; AllocTable(it8); - + it8->MemoryBlock = NULL; it8->MemorySink = NULL; - + it8 ->nTable = 0; it8->ContextID = ContextID; it8->Allocator.Used = 0; it8->Allocator.Block = NULL; - it8->Allocator.BlockSize = 0; + it8->Allocator.BlockSize = 0; it8->ValidKeywords = NULL; it8->ValidSampleID = NULL; @@ -1214,10 +1308,10 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8 -> lineno = 1; strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); - strcpy(it8->SheetType, "CGATS.17"); + cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); // Initialize predefined properties & data - + for (i=0; i < NUMPREDEFINEDPROPS; i++) AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); @@ -1231,18 +1325,15 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) { - cmsIT8* it8 = (cmsIT8*) hIT8; - - return it8 ->SheetType; - + return GetTable((cmsIT8*) hIT8)->SheetType; } cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) { - cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t = GetTable((cmsIT8*) hIT8); - strncpy(it8 ->SheetType, Type, MAXSTR-1); - it8 ->SheetType[MAXSTR-1] = 0; + strncpy(t ->SheetType, Type, MAXSTR-1); + t ->SheetType[MAXSTR-1] = 0; return TRUE; } @@ -1256,8 +1347,6 @@ cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; } - - // Sets a property cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val) { @@ -1269,31 +1358,30 @@ cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const ch return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; } - cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val) { cmsIT8* it8 = (cmsIT8*) hIT8; char Buffer[1024]; - + sprintf(Buffer, it8->DoubleFormatter, Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; } cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val) { cmsIT8* it8 = (cmsIT8*) hIT8; char Buffer[1024]; - - sprintf(Buffer, "%d", Val); - return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; + sprintf(Buffer, "%u", Val); + + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; } cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer) { - cmsIT8* it8 = (cmsIT8*) hIT8; - + cmsIT8* it8 = (cmsIT8*) hIT8; + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; } @@ -1322,8 +1410,9 @@ cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cPro { const char *v = cmsIT8GetProperty(hIT8, cProp); - if (v) return atof(v); - else return 0.0; + if (v == NULL) return 0.0; + + return ParseFloatNumber(v); } const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) @@ -1355,7 +1444,7 @@ void AllocateDataFormat(cmsIT8* it8) t -> nSamples = 10; } - t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *)); + t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *)); if (t->DataFormat == NULL) { SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); @@ -1386,8 +1475,8 @@ cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) SynError(it8, "More than NUMBER_OF_FIELDS fields."); return FALSE; } - - if (t->DataFormat) { + + if (t->DataFormat) { t->DataFormat[n] = AllocString(it8, label); } @@ -1411,7 +1500,7 @@ void AllocateDataSet(cmsIT8* it8) t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*)); + t-> Data = (char**)AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * ((cmsUInt32Number) t->nPatches + 1) *sizeof (char*)); if (t->Data == NULL) { SynError(it8, "AllocateDataSet: Unable to allocate data array"); @@ -1425,7 +1514,7 @@ char* GetData(cmsIT8* it8, int nSet, int nField) TABLE* t = GetTable(it8); int nSamples = t -> nSamples; int nPatches = t -> nPatches; - + if (nSet >= nPatches || nField >= nSamples) return NULL; @@ -1445,14 +1534,14 @@ cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) if (nSet > t -> nPatches || nSet < 0) { - return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); + return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); } if (nField > t ->nSamples || nField < 0) { return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples); - + } - + t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val); return TRUE; } @@ -1467,37 +1556,37 @@ void WriteStr(SAVESTREAM* f, const char *str) { cmsUInt32Number len; - if (str == NULL) + if (str == NULL) str = " "; - - // Lenghth to write + + // Length to write len = (cmsUInt32Number) strlen(str); f ->Used += len; - + if (f ->stream) { // Should I write it to a file? if (fwrite(str, 1, len, f->stream) != len) { cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser"); return; - } - + } + } else { // Or to a memory block? - + if (f ->Base) { // Am I just counting the bytes? - + if (f ->Used > f ->Max) { cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser"); return; } - + memmove(f ->Ptr, str, len); f->Ptr += len; } - - } + + } } @@ -1524,24 +1613,27 @@ void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) KEYVALUE* p; TABLE* t = GetTable(it8); - + // Writes the type + WriteStr(fp, t->SheetType); + WriteStr(fp, "\n"); + for (p = t->HeaderList; (p != NULL); p = p->Next) { if (*p ->Keyword == '#') { char* Pt; - + WriteStr(fp, "#\n# "); for (Pt = p ->Value; *Pt; Pt++) { - Writef(fp, "%c", *Pt); + Writef(fp, "%c", *Pt); if (*Pt == '\n') { WriteStr(fp, "# "); } } - + WriteStr(fp, "\n#\n"); continue; } @@ -1564,7 +1656,7 @@ void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) switch (p ->WriteAs) { case WRITE_UNCOOKED: - Writef(fp, "\t%s", p ->Value); + Writef(fp, "\t%s", p ->Value); break; case WRITE_STRINGIFY: @@ -1663,7 +1755,7 @@ void WriteData(SAVESTREAM* fp, cmsIT8* it8) // Saves whole file cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) { - SAVESTREAM sd; + SAVESTREAM sd; cmsUInt32Number i; cmsIT8* it8 = (cmsIT8*) hIT8; @@ -1671,9 +1763,7 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) sd.stream = fopen(cFileName, "wt"); if (!sd.stream) return FALSE; - - WriteStr(&sd, it8->SheetType); - WriteStr(&sd, "\n"); + for (i=0; i < it8 ->TablesCount; i++) { cmsIT8SetTable(hIT8, i); @@ -1681,7 +1771,7 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) WriteDataFormat(&sd, it8); WriteData(&sd, it8); } - + if (fclose(sd.stream) != 0) return FALSE; return TRUE; @@ -1691,7 +1781,7 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) // Saves to memory cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded) { - SAVESTREAM sd; + SAVESTREAM sd; cmsUInt32Number i; cmsIT8* it8 = (cmsIT8*) hIT8; @@ -1703,25 +1793,23 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* sd.Used = 0; - if (sd.Base) + if (sd.Base) sd.Max = *BytesNeeded; // Write to memory? - else + else sd.Max = 0; // Just counting the needed bytes - - WriteStr(&sd, it8->SheetType); - WriteStr(&sd, "\n"); + for (i=0; i < it8 ->TablesCount; i++) { - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); + cmsIT8SetTable(hIT8, i); + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); } - + sd.Used++; // The \0 at the very end if (sd.Base) - sd.Ptr = 0; + *sd.Ptr = 0; *BytesNeeded = sd.Used; @@ -1734,7 +1822,7 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* static cmsBool DataFormatSection(cmsIT8* it8) { - int iField = 0; + int iField = 0; TABLE* t = GetTable(it8); InSymbol(it8); // Eats "BEGIN_DATA_FORMAT" @@ -1744,15 +1832,15 @@ cmsBool DataFormatSection(cmsIT8* it8) it8->sy != SEOLN && it8->sy != SEOF && it8->sy != SSYNERROR) { - + if (it8->sy != SIDENT) { - - return SynError(it8, "Sample type expected"); + + return SynError(it8, "Sample type expected"); } - + if (!SetDataFormat(it8, iField, it8->id)) return FALSE; iField++; - + InSymbol(it8); SkipEOLN(it8); } @@ -1764,7 +1852,7 @@ cmsBool DataFormatSection(cmsIT8* it8) if (iField != t ->nSamples) { SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField); - + } return TRUE; @@ -1791,7 +1879,7 @@ cmsBool DataSection (cmsIT8* it8) if (iField >= t -> nSamples) { iField = 0; iSet++; - + } if (it8->sy != SEND_DATA && it8->sy != SEOF) { @@ -1803,16 +1891,16 @@ cmsBool DataSection (cmsIT8* it8) return FALSE; iField++; - + InSymbol(it8); - SkipEOLN(it8); + SkipEOLN(it8); } } SkipEOLN(it8); Skip(it8, SEND_DATA); SkipEOLN(it8); - + // Check for data completion. if ((iSet+1) != t -> nPatches) @@ -1841,7 +1929,7 @@ cmsBool HeaderSection(cmsIT8* it8) case SKEYWORD: InSymbol(it8); - if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; InSymbol(it8); break; @@ -1849,7 +1937,7 @@ cmsBool HeaderSection(cmsIT8* it8) case SDATA_FORMAT_ID: InSymbol(it8); - if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; if (!AddAvailableSampleID(it8, Buffer)) return FALSE; InSymbol(it8); break; @@ -1858,10 +1946,10 @@ cmsBool HeaderSection(cmsIT8* it8) case SIDENT: strncpy(VarName, it8->id, MAXID-1); VarName[MAXID-1] = 0; - + if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { -#ifdef CMS_STRICT_CGATS +#ifdef CMS_STRICT_CGATS return SynError(it8, "Undefined keyword '%s'", VarName); #else Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); @@ -1873,7 +1961,7 @@ cmsBool HeaderSection(cmsIT8* it8) if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; if(Key->WriteAs != WRITE_PAIR) { - AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, + AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); } else { @@ -1886,7 +1974,7 @@ cmsBool HeaderSection(cmsIT8* it8) for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) { char *Value, *temp; - + // identify token pair boundary Nextkey = (char*) strchr(Subkey, ';'); if(Nextkey) @@ -1903,7 +1991,7 @@ cmsBool HeaderSection(cmsIT8* it8) // gobble any space at the right temp = Value + strlen(Value) - 1; - while(*temp == ' ') *temp-- = '\0'; + while(*temp == ' ') *temp-- = '\0'; // trim the strings from the left Subkey += strspn(Subkey, " "); @@ -1914,11 +2002,11 @@ cmsBool HeaderSection(cmsIT8* it8) AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); } } - + InSymbol(it8); break; - + case SEOLN: break; default: @@ -1934,27 +2022,34 @@ cmsBool HeaderSection(cmsIT8* it8) static -cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) +void ReadType(cmsIT8* it8, char* SheetTypePtr) { - char* SheetTypePtr = it8 ->SheetType; - - if (nosheet == 0) { - // First line is a very special case. while (isseparator(it8->ch)) NextCh(it8); - + while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { *SheetTypePtr++= (char) it8 ->ch; NextCh(it8); } - } *SheetTypePtr = 0; +} + + +static +cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) +{ + char* SheetTypePtr = it8 ->Tab[0].SheetType; + + if (nosheet == 0) { + ReadType(it8, SheetTypePtr); + } + InSymbol(it8); - + SkipEOLN(it8); while (it8-> sy != SEOF && @@ -1969,11 +2064,44 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) case SBEGIN_DATA: if (!DataSection(it8)) return FALSE; - + if (it8 -> sy != SEOF) { AllocTable(it8); it8 ->nTable = it8 ->TablesCount - 1; + + // Read sheet type if present. We only support identifier and string. + // is a type string + // anything else, is not a type string + if (nosheet == 0) { + + if (it8 ->sy == SIDENT) { + + // May be a type sheet or may be a prop value statement. We cannot use insymbol in + // this special case... + while (isseparator(it8->ch)) + NextCh(it8); + + // If a newline is found, then this is a type string + if (it8 ->ch == '\n' || it8->ch == '\r') { + + cmsIT8SetSheetType(it8, it8 ->id); + InSymbol(it8); + } + else + { + // It is not. Just continue + cmsIT8SetSheetType(it8, ""); + } + } + else + // Validate quoted strings + if (it8 ->sy == SSTRING) { + cmsIT8SetSheetType(it8, it8 ->str); + InSymbol(it8); + } + } + } break; @@ -2007,7 +2135,7 @@ void CookPointers(cmsIT8* it8) TABLE* t = it8 ->Tab + j; t -> SampleID = 0; - it8 ->nTable = j; + it8 ->nTable = j; for (idField = 0; idField < t -> nSamples; idField++) { @@ -2022,41 +2150,41 @@ void CookPointers(cmsIT8* it8) if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - t -> SampleID = idField; - - for (i=0; i < t -> nPatches; i++) { + t -> SampleID = idField; + + for (i=0; i < t -> nPatches; i++) { char *Data = GetData(it8, i, idField); if (Data) { char Buffer[256]; - + strncpy(Buffer, Data, 255); Buffer[255] = 0; - + if (strlen(Buffer) <= strlen(Data)) strcpy(Data, Buffer); else SetData(it8, i, idField, Buffer); } - } - + } + } // "LABEL" is an extension. It keeps references to forward tables - + if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) { - + // Search for table references... for (i=0; i < t -> nPatches; i++) { char *Label = GetData(it8, i, idField); - - if (Label) { - + + if (Label) { + cmsUInt32Number k; - // This is the label, search for a table containing + // This is the label, search for a table containing // this property for (k=0; k < it8 ->TablesCount; k++) { @@ -2070,10 +2198,10 @@ void CookPointers(cmsIT8* it8) char Buffer[256]; char *Type = p ->Value; - int nTable = k; + int nTable = (int) k; snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); - + SetData(it8, i, idField, Buffer); } } @@ -2094,14 +2222,14 @@ void CookPointers(cmsIT8* it8) // Try to infere if the file is a CGATS/IT8 file at all. Read first line // that should be something like some printable characters plus a \n - +// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line? static int IsMyBlock(cmsUInt8Number* Buffer, int n) { - int cols = 1, space = 0, quot = 0; + int words = 1, space = 0, quot = 0; int i; - if (n < 10) return FALSE; // Too small + if (n < 10) return 0; // Too small if (n > 132) n = 132; @@ -2112,7 +2240,7 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n) { case '\n': case '\r': - return quot == 1 || cols > 2 ? 0 : cols; + return ((quot == 1) || (words > 2)) ? 0 : words; case '\t': case ' ': if(!quot && !space) @@ -2124,14 +2252,13 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n) default: if (Buffer[i] < 32) return 0; if (Buffer[i] > 127) return 0; - cols += space; + words += space; space = 0; break; } } - return FALSE; - + return 0; } @@ -2150,8 +2277,8 @@ cmsBool IsMyFile(const char* FileName) Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp); - if (fclose(fp) != 0) - return FALSE; + if (fclose(fp) != 0) + return FALSE; Ptr[Size] = '\0'; @@ -2163,16 +2290,16 @@ cmsBool IsMyFile(const char* FileName) cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len) { - cmsHANDLE hIT8; + cmsHANDLE hIT8; cmsIT8* it8; - int type; + int type; - _cmsAssert(Ptr != NULL); - _cmsAssert(len != 0); + _cmsAssert(Ptr != NULL); + _cmsAssert(len != 0); type = IsMyBlock((cmsUInt8Number*)Ptr, len); if (type == 0) return NULL; - + hIT8 = cmsIT8Alloc(ContextID); if (!hIT8) return NULL; @@ -2185,10 +2312,10 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt3 strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1); it8-> Source = it8 -> MemoryBlock; - if (!ParseIT8(it8, type-1)) { - - cmsIT8Free(hIT8); - return FALSE; + if (!ParseIT8(it8, type-1)) { + + cmsIT8Free(hIT8); + return FALSE; } CookPointers(it8); @@ -2206,45 +2333,45 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt3 cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName) { - cmsHANDLE hIT8; + cmsHANDLE hIT8; cmsIT8* it8; - int type; - - _cmsAssert(cFileName != NULL); + int type; - type = IsMyFile(cFileName); + _cmsAssert(cFileName != NULL); + + type = IsMyFile(cFileName); if (type == 0) return NULL; hIT8 = cmsIT8Alloc(ContextID); - it8 = (cmsIT8*) hIT8; + it8 = (cmsIT8*) hIT8; if (!hIT8) return NULL; it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); - if (!it8 ->FileStack[0]->Stream) { + if (!it8 ->FileStack[0]->Stream) { cmsIT8Free(hIT8); return NULL; } - - strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); + + strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0; - if (!ParseIT8(it8, type-1)) { - + if (!ParseIT8(it8, type-1)) { + fclose(it8 ->FileStack[0]->Stream); - cmsIT8Free(hIT8); - return NULL; + cmsIT8Free(hIT8); + return NULL; } CookPointers(it8); it8 ->nTable = 0; - if (fclose(it8 ->FileStack[0]->Stream)!= 0) { - cmsIT8Free(hIT8); - return NULL; - } + if (fclose(it8 ->FileStack[0]->Stream)!= 0) { + cmsIT8Free(hIT8); + return NULL; + } return hIT8; @@ -2252,16 +2379,16 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileN int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames) { - cmsIT8* it8 = (cmsIT8*) hIT8; - TABLE* t; + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); - t = GetTable(it8); + t = GetTable(it8); - if (SampleNames) - *SampleNames = t -> DataFormat; - return t -> nSamples; + if (SampleNames) + *SampleNames = t -> DataFormat; + return t -> nSamples; } @@ -2272,10 +2399,10 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN cmsUInt32Number n; char **Props; TABLE* t; - - _cmsAssert(hIT8 != NULL); - t = GetTable(it8); + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); // Pass#1 - count properties @@ -2304,11 +2431,11 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cP cmsUInt32Number n; const char **Props; TABLE* t; - - _cmsAssert(hIT8 != NULL); + + _cmsAssert(hIT8 != NULL); - t = GetTable(it8); + t = GetTable(it8); if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { *SubpropertyNames = 0; @@ -2347,7 +2474,7 @@ int LocatePatch(cmsIT8* it8, const char* cPatch) for (i=0; i < t-> nPatches; i++) { data = GetData(it8, i, t->SampleID); - + if (data != NULL) { if (cmsstrcasecmp(data, cPatch) == 0) @@ -2355,7 +2482,7 @@ int LocatePatch(cmsIT8* it8, const char* cPatch) } } - // SynError(it8, "Couldn't find patch '%s'\n", cPatch); + // SynError(it8, "Couldn't find patch '%s'\n", cPatch); return -1; } @@ -2371,7 +2498,7 @@ int LocateEmptyPatch(cmsIT8* it8) data = GetData(it8, i, t->SampleID); - if (data == NULL) + if (data == NULL) return i; } @@ -2392,7 +2519,7 @@ int LocateSample(cmsIT8* it8, const char* cSample) if (cmsstrcasecmp(fld, cSample) == 0) return i; } - + return -1; } @@ -2402,7 +2529,7 @@ int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample) { cmsIT8* it8 = (cmsIT8*) hIT8; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); return LocateSample(it8, cSample); } @@ -2413,7 +2540,7 @@ const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col) { cmsIT8* it8 = (cmsIT8*) hIT8; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); return GetData(it8, row, col); } @@ -2424,24 +2551,20 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int c const char* Buffer; Buffer = cmsIT8GetDataRowCol(hIT8, row, col); - - if (Buffer) { - return atof(Buffer); - - } else - return 0; + if (Buffer == NULL) return 0.0; + return ParseFloatNumber(Buffer); } cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val) { cmsIT8* it8 = (cmsIT8*) hIT8; - - _cmsAssert(hIT8 != NULL); - return SetData(it8, row, col, Val); + _cmsAssert(hIT8 != NULL); + + return SetData(it8, row, col, Val); } @@ -2450,29 +2573,29 @@ cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFl cmsIT8* it8 = (cmsIT8*) hIT8; char Buff[256]; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); sprintf(Buff, it8->DoubleFormatter, Val); - - return SetData(it8, row, col, Buff); + + return SetData(it8, row, col, Buff); } -const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) +const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) { cmsIT8* it8 = (cmsIT8*) hIT8; int iField, iSet; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); iField = LocateSample(it8, cSample); - if (iField < 0) { + if (iField < 0) { return NULL; } iSet = LocatePatch(it8, cPatch); - if (iSet < 0) { + if (iSet < 0) { return NULL; } @@ -2485,15 +2608,8 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* Buffer; Buffer = cmsIT8GetData(it8, cPatch, cSample); - - if (Buffer) { - return atof(Buffer); - - } else { - - return 0; - } + return ParseFloatNumber(Buffer); } @@ -2503,14 +2619,14 @@ cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cmsIT8* it8 = (cmsIT8*) hIT8; int iField, iSet; TABLE* t; - - _cmsAssert(hIT8 != NULL); - t = GetTable(it8); + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); iField = LocateSample(it8, cSample); - if (iField < 0) + if (iField < 0) return FALSE; if (t-> nPatches == 0) { @@ -2524,7 +2640,7 @@ cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* iSet = LocateEmptyPatch(it8); if (iSet < 0) { - return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); + return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); } iField = t -> SampleID; @@ -2541,56 +2657,56 @@ cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, - const char* cSample, - cmsFloat64Number Val) + const char* cSample, + cmsFloat64Number Val) { - cmsIT8* it8 = (cmsIT8*) hIT8; - char Buff[256]; + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buff[256]; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); - snprintf(Buff, 255, it8->DoubleFormatter, Val); - return cmsIT8SetData(hIT8, cPatch, cSample, Buff); + snprintf(Buff, 255, it8->DoubleFormatter, Val); + return cmsIT8SetData(hIT8, cPatch, cSample, Buff); } // Buffer should get MAXSTR at least const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer) { - cmsIT8* it8 = (cmsIT8*) hIT8; - TABLE* t; - char* Data; + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; + char* Data; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); - t = GetTable(it8); - Data = GetData(it8, nPatch, t->SampleID); + t = GetTable(it8); + Data = GetData(it8, nPatch, t->SampleID); - if (!Data) return NULL; - if (!buffer) return Data; + if (!Data) return NULL; + if (!buffer) return Data; - strncpy(buffer, Data, MAXSTR-1); - buffer[MAXSTR-1] = 0; - return buffer; + strncpy(buffer, Data, MAXSTR-1); + buffer[MAXSTR-1] = 0; + return buffer; } int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch) { - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); return LocatePatch((cmsIT8*)hIT8, cPatch); } cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8) { - cmsIT8* it8 = (cmsIT8*) hIT8; + cmsIT8* it8 = (cmsIT8*) hIT8; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); - return it8 ->TablesCount; + return it8 ->TablesCount; } -// This handles the "LABEL" extension. +// This handles the "LABEL" extension. // Label, nTable, Type int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType) @@ -2598,21 +2714,21 @@ int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char const char* cLabelFld; char Type[256], Label[256]; int nTable; - + _cmsAssert(hIT8 != NULL); if (cField != NULL && *cField == 0) cField = "LABEL"; - if (cField == NULL) + if (cField == NULL) cField = "LABEL"; - cLabelFld = cmsIT8GetData(hIT8, cSet, cField); + cLabelFld = cmsIT8GetData(hIT8, cSet, cField); if (!cLabelFld) return -1; - + if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) return -1; - + if (ExpectedType != NULL && *ExpectedType == 0) ExpectedType = NULL; @@ -2621,23 +2737,23 @@ int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1; } - return cmsIT8SetTable(hIT8, nTable); + return cmsIT8SetTable(hIT8, nTable); } cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample) { - cmsIT8* it8 = (cmsIT8*) hIT8; - int pos; + cmsIT8* it8 = (cmsIT8*) hIT8; + int pos; - _cmsAssert(hIT8 != NULL); + _cmsAssert(hIT8 != NULL); - pos = LocateSample(it8, cSample); - if(pos == -1) - return FALSE; + pos = LocateSample(it8, cSample); + if(pos == -1) + return FALSE; - it8->Tab[it8->nTable].SampleID = pos; - return TRUE; + it8->Tab[it8->nTable].SampleID = pos; + return TRUE; } @@ -2650,6 +2766,8 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) if (Formatter == NULL) strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); else - strcpy(it8->DoubleFormatter, Formatter); + strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter)); + + it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } diff --git a/thirdparty/liblcms2/src/cmscnvrt.c b/thirdparty/liblcms2/src/cmscnvrt.c index 8dadc875..1a93e83f 100644 --- a/thirdparty/liblcms2/src/cmscnvrt.c +++ b/thirdparty/liblcms2/src/cmscnvrt.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -27,26 +27,26 @@ #include "lcms2_internal.h" -// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point +// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point // compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS // after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1) -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); - + //--------------------------------------------------------------------------------- -// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. +// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. // Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric -static -cmsPipeline* DefaultICCintents(cmsContext ContextID, +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -56,10 +56,10 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, // This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile // to do the trick (no devicelinks allowed at that position) static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -69,10 +69,10 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile // to do the trick (no devicelinks allowed at that position) static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -92,7 +92,7 @@ typedef struct _cms_intents_list { // Built-in intents -static cmsIntentsList DefaultIntents[] = { +static cmsIntentsList DefaultIntents[] = { { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] }, { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] }, @@ -103,35 +103,88 @@ static cmsIntentsList DefaultIntents[] = { { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] }, { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] }, { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] }, - { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } + { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } }; // A pointer to the begining of the list -static cmsIntentsList *Intents = DefaultIntents; +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + // Search the list for a suitable intent. Returns NULL if not found -static -cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +static +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; - for (pt = Intents; pt != NULL; pt = pt -> Next) + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; } -// Black point compensation. Implemented as a linear scaling in XYZ. Black points +// Black point compensation. Implemented as a linear scaling in XYZ. Black points // should come relative to the white point. Fills an matrix/offset element m // which is organized as a 4x4 matrix. static -void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, +void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, const cmsCIEXYZ* BlackPointOut, cmsMAT3* m, cmsVEC3* off) -{ +{ cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz; - + // Now we need to compute a matrix plus an offset m and of such of // [m]*bpin + off = bpout // [m]*D50 + off = D50 @@ -164,17 +217,21 @@ void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, static cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) { - // Convert D50 across CHAD to get the absolute white point - cmsVEC3 d, s; - cmsCIEXYZ Dest; - cmsCIExyY DestChromaticity; - cmsFloat64Number TempK; + // Convert D50 across inverse CHAD to get the absolute white point + cmsVEC3 d, s; + cmsCIEXYZ Dest; + cmsCIExyY DestChromaticity; + cmsFloat64Number TempK; + cmsMAT3 m1, m2; + + m1 = *Chad; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; s.n[VX] = cmsD50_XYZ() -> X; s.n[VY] = cmsD50_XYZ() -> Y; s.n[VZ] = cmsD50_XYZ() -> Z; - _cmsMAT3eval(&d, Chad, &s); + _cmsMAT3eval(&d, &m2, &s); Dest.X = d.n[VX]; Dest.Y = d.n[VY]; @@ -190,33 +247,32 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) // Compute a CHAD based on a given temperature static -void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) + void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) { cmsCIEXYZ White; cmsCIExyY ChromaticityOfWhite; - - cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); - cmsxyY2XYZ(&White, &ChromaticityOfWhite); - _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White); + cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); + cmsxyY2XYZ(&White, &ChromaticityOfWhite); + _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); } // Join scalings to obtain relative input to absolute and then to relative output. // Result is stored in a 3x3 matrix static cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, - const cmsCIEXYZ* WhitePointIn, + const cmsCIEXYZ* WhitePointIn, const cmsMAT3* ChromaticAdaptationMatrixIn, const cmsCIEXYZ* WhitePointOut, const cmsMAT3* ChromaticAdaptationMatrixOut, cmsMAT3* m) { - cmsMAT3 Scale, m1, m2, m3; + cmsMAT3 Scale, m1, m2, m3, m4; // Adaptation state if (AdaptationState == 1.0) { - // Observer is fully adapted. Keep chromatic adaptation. + // Observer is fully adapted. Keep chromatic adaptation. // That is the standard V4 behaviour _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); @@ -230,23 +286,32 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); - m1 = *ChromaticAdaptationMatrixIn; - if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; - _cmsMAT3per(&m3, &m2, &Scale); - // m3 holds CHAD from input white to D50 times abs. col. scaling if (AdaptationState == 0.0) { + m1 = *ChromaticAdaptationMatrixOut; + _cmsMAT3per(&m2, &m1, &Scale); + // m2 holds CHAD from output white to D50 times abs. col. scaling + // Observer is not adapted, undo the chromatic adaptation - _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut); + _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut); + + m3 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; + _cmsMAT3per(m, &m2, &m4); } else { cmsMAT3 MixedCHAD; cmsFloat64Number TempSrc, TempDest, Temp; - TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); // K for source white - TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white + m1 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; + _cmsMAT3per(&m3, &m2, &Scale); + // m3 holds CHAD from input white to D50 times abs. col. scaling + + TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); + TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong @@ -256,9 +321,9 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, return TRUE; } - Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest; + Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc; - // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD + // Get a CHAD from whatever output temperature to D50. This replaces output CHAD Temp2CHAD(&MixedCHAD, Temp); _cmsMAT3per(m, &m3, &MixedCHAD); @@ -276,12 +341,12 @@ cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) cmsFloat64Number diff = 0; cmsMAT3 Ident; int i; - + if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer if (m == NULL && off != NULL) return FALSE; // This is an internal error _cmsMAT3identity(&Ident); - + for (i=0; i < 3*3; i++) diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]); @@ -295,10 +360,10 @@ cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) // Compute the conversion layer static -cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], - cmsUInt32Number Intent, - cmsBool BPC, - cmsFloat64Number AdaptationState, +cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], + cmsUInt32Number Intent, + cmsBool BPC, + cmsFloat64Number AdaptationState, cmsMAT3* m, cmsVEC3* off) { @@ -312,7 +377,7 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) { cmsCIEXYZ WhitePointIn, WhitePointOut; - cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; + cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); @@ -320,8 +385,8 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); - if (!ComputeAbsoluteIntent(AdaptationState, - &WhitePointIn, &ChromaticAdaptationMatrixIn, + if (!ComputeAbsoluteIntent(AdaptationState, + &WhitePointIn, &ChromaticAdaptationMatrixIn, &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE; } @@ -333,24 +398,24 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], cmsCIEXYZ BlackPointIn, BlackPointOut; cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); - cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); + cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); // If black points are equal, then do nothing if (BlackPointIn.X != BlackPointOut.X || BlackPointIn.Y != BlackPointOut.Y || - BlackPointIn.Z != BlackPointOut.Z) + BlackPointIn.Z != BlackPointOut.Z) ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off); } } // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0, // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so - // we have first to convert from encoded to XYZ and then convert back to encoded. + // we have first to convert from encoded to XYZ and then convert back to encoded. // y = Mx + Off // x = x'c // y = M x'c + Off // y = y'c; y' = y / c - // y' = (Mx'c + Off) /c = Mx' + (Off / c) + // y' = (Mx'c + Off) /c = Mx' + (Off / c) for (k=0; k < 3; k++) { off ->n[k] /= MAX_ENCODEABLE_XYZ; @@ -360,7 +425,7 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], } -// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space +// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space static cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off) { @@ -370,57 +435,61 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo // Handle PCS mismatches. A specialized stage is added to the LUT in such case switch (InPCS) { - case cmsSigXYZData: // Input profile operates in XYZ + case cmsSigXYZData: // Input profile operates in XYZ - switch (OutPCS) { + switch (OutPCS) { - case cmsSigXYZData: // XYZ -> XYZ - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; + case cmsSigXYZData: // XYZ -> XYZ + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; - case cmsSigLabData: // XYZ -> Lab - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - break; + case cmsSigLabData: // XYZ -> Lab + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; + break; - default: - return FALSE; // Colorspace mismatch - } - break; + default: + return FALSE; // Colorspace mismatch + } + break; + case cmsSigLabData: // Input profile operates in Lab - case cmsSigLabData: // Input profile operates in Lab + switch (OutPCS) { - switch (OutPCS) { + case cmsSigXYZData: // Lab -> XYZ - case cmsSigXYZData: // Lab -> XYZ + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID))) + return FALSE; + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; + case cmsSigLabData: // Lab -> Lab - case cmsSigLabData: // Lab -> Lab - - if (!IsEmptyLayer(m, off)) { - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - } - break; - - default: - return FALSE; // Mismatch + if (!IsEmptyLayer(m, off)) { + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) || + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) || + !cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; } break; - - // On colorspaces other than PCS, check for same space default: - if (InPCS != OutPCS) return FALSE; - break; + return FALSE; // Mismatch + } + break; + + // On colorspaces other than PCS, check for same space + default: + if (InPCS != OutPCS) return FALSE; + break; } return TRUE; @@ -434,6 +503,10 @@ cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature // If they are same, they are compatible. if (a == b) return TRUE; + // Check for MCH4 substitution of CMYK + if ((a == cmsSig4colorData) && (b == cmsSigCmykData)) return TRUE; + if ((a == cmsSigCmykData) && (b == cmsSig4colorData)) return TRUE; + // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other. if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE; if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE; @@ -444,30 +517,31 @@ cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature // Default handler for ICC-style intents static -cmsPipeline* DefaultICCintents(cmsContext ContextID, +cmsPipeline* DefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) { - cmsPipeline* Lut, *Result; + cmsPipeline* Lut = NULL; + cmsPipeline* Result; cmsHPROFILE hProfile; cmsMAT3 m; cmsVEC3 off; - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; cmsProfileClassSignature ClassSig; cmsUInt32Number i, Intent; - // For safety - if (nProfiles == 0) return NULL; + // For safety + if (nProfiles == 0) return NULL; // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined' Result = cmsPipelineAlloc(ContextID, 0, 0); if (Result == NULL) return NULL; - CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); + CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); for (i=0; i < nProfiles; i++) { @@ -476,16 +550,16 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, hProfile = hProfiles[i]; ClassSig = cmsGetDeviceClass(hProfile); lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass ); - + // First profile is used as input unless devicelink or abstract - if ((i == 0) && !lIsDeviceLink) { - lIsInput = TRUE; - } - else { - // Else use profile in the input direction if current space is not PCS + if ((i == 0) && !lIsDeviceLink) { + lIsInput = TRUE; + } + else { + // Else use profile in the input direction if current space is not PCS lIsInput = (CurrentColorSpace != cmsSigXYZData) && (CurrentColorSpace != cmsSigLabData); - } + } Intent = TheIntents[i]; @@ -506,9 +580,9 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, goto Error; } - // If devicelink is found, then no custom intent is allowed and we can - // read the LUT to be applied. Settings don't apply here. - if (lIsDeviceLink) { + // If devicelink is found, then no custom intent is allowed and we can + // read the LUT to be applied. Settings don't apply here. + if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) { // Get the involved LUT from the profile Lut = _cmsReadDevicelinkLUT(hProfile, Intent); @@ -522,7 +596,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, _cmsMAT3identity(&m); _cmsVEC3init(&off, 0, 0, 0); } - + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; @@ -531,13 +605,13 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, if (lIsInput) { // Input direction means non-pcs connection, so proceed like devicelinks - Lut = _cmsReadInputLUT(hProfile, Intent); + Lut = _cmsReadInputLUT(hProfile, Intent); if (Lut == NULL) goto Error; } else { // Output direction means PCS connection. Intent may apply here - Lut = _cmsReadOutputLUT(hProfile, Intent); + Lut = _cmsReadOutputLUT(hProfile, Intent); if (Lut == NULL) goto Error; @@ -548,17 +622,21 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, } // Concatenate to the output LUT - cmsPipelineCat(Result, Lut); - cmsPipelineFree(Lut); + if (!cmsPipelineCat(Result, Lut)) + goto Error; + + cmsPipelineFree(Lut); + Lut = NULL; // Update current space - CurrentColorSpace = ColorSpaceOut; + CurrentColorSpace = ColorSpaceOut; } return Result; Error: + if (Lut != NULL) cmsPipelineFree(Lut); if (Result != NULL) cmsPipelineFree(Result); return NULL; @@ -567,10 +645,10 @@ Error: // Wrapper for DLL calling convention -cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, +cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -587,7 +665,7 @@ int TranslateNonICCIntents(int Intent) switch (Intent) { case INTENT_PRESERVE_K_ONLY_PERCEPTUAL: case INTENT_PRESERVE_K_PLANE_PERCEPTUAL: - return INTENT_PERCEPTUAL; + return INTENT_PERCEPTUAL; case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC: case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC: @@ -632,10 +710,10 @@ int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register // This is the entry for black-preserving K-only intents, which are non-ICC static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -651,12 +729,12 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, if (nProfiles < 1 || nProfiles > 255) return NULL; // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); // Check for non-cmyk profiles if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); memset(&bp, 0, sizeof(bp)); @@ -666,43 +744,44 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, if (Result == NULL) return NULL; // Create a LUT holding normal ICC transform - bp.cmyk2cmyk = DefaultICCintents(ContextID, + bp.cmyk2cmyk = DefaultICCintents(ContextID, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); if (bp.cmyk2cmyk == NULL) goto Error; - + // Now, compute the tone curve - bp.KTone = _cmsBuildKToneCurve(ContextID, - 4096, + bp.KTone = _cmsBuildKToneCurve(ContextID, + 4096, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); - + if (bp.KTone == NULL) goto Error; - + // How many gridpoints are we going to use? nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - + // Create the CLUT. 16 bits CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); if (CLUT == NULL) goto Error; // This is the one and only MPE in this LUT - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Error; // Sample it. We cannot afford pre/post linearization this time. - if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) + if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) goto Error; - + // Get rid of xform and tone curve cmsPipelineFree(bp.cmyk2cmyk); cmsFreeToneCurve(bp.KTone); @@ -729,9 +808,9 @@ typedef struct { cmsPipeline* LabK2cmyk; // The output profile cmsFloat64Number MaxError; - cmsHTRANSFORM hRoundTrip; + cmsHTRANSFORM hRoundTrip; cmsFloat64Number MaxTAC; - + } PreserveKPlaneParams; @@ -742,18 +821,18 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt { int i; cmsFloat32Number Inf[4], Outf[4]; - cmsFloat32Number LabK[4]; + cmsFloat32Number LabK[4]; cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; cmsCIELab ColorimetricLab, BlackPreservingLab; PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; - + // Convert from 16 bits to floating point - for (i=0; i < 4; i++) + for (i=0; i < 4; i++) Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); // Get the K across Tone curve LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); - + // If going across black only, keep black only if (In[0] == 0 && In[1] == 0 && In[2] == 0) { @@ -761,28 +840,28 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); return TRUE; } - - // Try the original transform, - cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); - + + // Try the original transform, + cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); + // Store a copy of the floating point result into 16-bit - for (i=0; i < 4; i++) + for (i=0; i < 4; i++) Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); // Maybe K is already ok (mostly on K=0) if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) { return TRUE; } - + // K differ, mesure and keep Lab measurement for further usage // this is done in relative colorimetric intent cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); - + // Is not black only and the transform doesn't keep black. // Obtain the Lab of output CMYK. After that we have Lab + K cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); - // Obtain the corresponding CMY using reverse interpolation + // Obtain the corresponding CMY using reverse interpolation // (K is fixed in LabK[3]) if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { @@ -793,10 +872,10 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt // Make sure to pass thru K (which now is fixed) Outf[3] = LabK[3]; - - // Apply TAC if needed + + // Apply TAC if needed SumCMY = Outf[0] + Outf[1] + Outf[2]; - SumCMYK = SumCMY + Outf[3]; + SumCMYK = SumCMY + Outf[3]; if (SumCMYK > bp ->MaxTAC) { @@ -813,9 +892,9 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); // Estimate the error (this goes 16 bits to Lab DBL) - cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); - Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); - if (Error > bp -> MaxError) + cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); + Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); + if (Error > bp -> MaxError) bp->MaxError = Error; return TRUE; @@ -823,10 +902,10 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt // This is the entry for black-plane preserving, which are non-ICC static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -835,26 +914,27 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsPipeline* Result = NULL; cmsUInt32Number ICCIntents[256]; cmsStage* CLUT; - cmsUInt32Number i, nGridPoints; + cmsUInt32Number i, nGridPoints; cmsHPROFILE hLab; // Sanity check if (nProfiles < 1 || nProfiles > 255) return NULL; // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); // Check for non-cmyk profiles if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData || + cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass)) return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); // Allocate an empty LUT for holding the result Result = cmsPipelineAlloc(ContextID, 4, 4); if (Result == NULL) return NULL; - + memset(&bp, 0, sizeof(bp)); // We need the input LUT of the last profile, assuming this one is responsible of @@ -864,38 +944,43 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // Get total area coverage (in 0..1 domain) bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0; + if (bp.MaxTAC <= 0) goto Cleanup; + // Create a LUT holding normal ICC transform bp.cmyk2cmyk = DefaultICCintents(ContextID, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); + if (bp.cmyk2cmyk == NULL) goto Cleanup; // Now the tone curve bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles, - ICCIntents, - hProfiles, - BPC, + ICCIntents, + hProfiles, + BPC, AdaptationStates, dwFlags); - + if (bp.KTone == NULL) goto Cleanup; // To measure the output, Last profile to Lab hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, + bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if ( bp.hProofOutput == NULL) goto Cleanup; // Same as anterior, but lab in the 0..1 range - bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, - FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), - INTENT_RELATIVE_COLORIMETRIC, + bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, + FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if (bp.cmyk2Lab == NULL) goto Cleanup; cmsCloseProfile(hLab); // Error estimation (for debug only) @@ -904,21 +989,22 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // How many gridpoints are we going to use? nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); if (CLUT == NULL) goto Cleanup; - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Cleanup; cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); Cleanup: if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk); - if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); + if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput); - - if (bp.KTone) cmsFreeToneCurve(bp.KTone); + + if (bp.KTone) cmsFreeToneCurve(bp.KTone); if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk); return Result; @@ -927,12 +1013,12 @@ Cleanup: // Link routines ------------------------------------------------------------------------------------------------------ // Chain several profiles into a single LUT. It just checks the parameters and then calls the handler -// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the +// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the // rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable. -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -948,9 +1034,9 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, for (i=0; i < nProfiles; i++) { - // Check if black point is really needed or allowed. Note that + // Check if black point is really needed or allowed. Note that // following Adobe's document: - // BPC does not apply to devicelink profiles, nor to abs colorimetric, + // BPC does not apply to devicelink profiles, nor to abs colorimetric, // and applies always on V4 perceptual and saturation. if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC) @@ -961,7 +1047,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // Force BPC for V4 profiles in perceptual and saturation if (cmsGetProfileVersion(hProfiles[i]) >= 4.0) BPC[i] = TRUE; - } + } } // Search for a handler. The first intent in the chain defines the handler. That would @@ -969,11 +1055,11 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // this case would present some issues if the custom intent tries to do things like // preserve primaries. This solution is not perfect, but works well on most cases. - Intent = SearchIntent(TheIntents[0]); - if (Intent == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); - return NULL; - } + Intent = SearchIntent(ContextID, TheIntents[0]); + if (Intent == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); + return NULL; + } // Call the handler return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); @@ -981,58 +1067,75 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // ------------------------------------------------------------------------------------------------- -// Get information about available intents. nMax is the maximum space for the supplied "Codes" -// and "Descriptions" the function returns the total number of intents, which may be greater +// Get information about available intents. nMax is the maximum space for the supplied "Codes" +// and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; - for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { - if (Codes != NULL) + if (Codes != NULL) Codes[nIntents] = pt ->Intent; - if (Descriptions != NULL) + if (Descriptions != NULL) Descriptions[nIntents] = pt ->Description; } nIntents++; } + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } return nIntents; } -// The plug-in registration. User can add new intents or override default routines -cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + +// The plug-in registration. User can add new intents or override default routines +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) +{ + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; - // Do we have to reset the intents? + // Do we have to reset the custom intents? if (Data == NULL) { - - Intents = DefaultIntents; - return TRUE; + + ctx->Intents = NULL; + return TRUE; } - fl = SearchIntent(Plugin ->Intent); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; - if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - } fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, 255); - fl ->Description[255] = 0; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; - fl ->Next = Intents; - Intents = fl; + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; return TRUE; } diff --git a/thirdparty/liblcms2/src/cmserr.c b/thirdparty/liblcms2/src/cmserr.c index 55f03580..29516db4 100644 --- a/thirdparty/liblcms2/src/cmserr.c +++ b/thirdparty/liblcms2/src/cmserr.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -31,30 +31,31 @@ // compare two strings ignoring case int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) { - register const unsigned char *us1 = (const unsigned char *)s1, - *us2 = (const unsigned char *)s2; + register const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; - while (toupper(*us1) == toupper(*us2++)) - if (*us1++ == '\0') - return (0); - return (toupper(*us1) - toupper(*--us2)); + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return 0; + + return (toupper(*us1) - toupper(*--us2)); } // long int because C99 specifies ftell in such way (7.19.9.2) long int CMSEXPORT cmsfilelength(FILE* f) { - long int p , n; + long int p , n; - p = ftell(f); // register current file position + p = ftell(f); // register current file position - if (fseek(f, 0, SEEK_END) != 0) { - return -1; - } + if (fseek(f, 0, SEEK_END) != 0) { + return -1; + } n = ftell(f); - fseek(f, p, SEEK_SET); // file position restored + fseek(f, p, SEEK_SET); // file position restored - return n; + return n; } @@ -62,23 +63,22 @@ long int CMSEXPORT cmsfilelength(FILE* f) // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to -// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms -// would never need. +// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) // User may override this behaviour by using a memory plug-in, which basically replaces -// the default memory management functions. In this case, no check is performed and it -// is up to the plug-in writter to keep in the safe side. There are only three functions -// required to be implemented: malloc, realloc and free, although the user may want to +// the default memory management functions. In this case, no check is performed and it +// is up to the plug-in writter to keep in the safe side. There are only three functions +// required to be implemented: malloc, realloc and free, although the user may want to // replace the optional mallocZero, calloc and dup as well. -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // ********************************************************************************* -// This is the default memory allocation function. It does a very coarse +// This is the default memory allocation function. It does a very coarse // check of amout of memory, just to prevent exploits static void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) @@ -109,13 +109,13 @@ void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) // free(NULL) is defined a no-op by C99, therefore it is safe to // avoid the check, but it is here just in case... - if (Ptr) free(Ptr); + if (Ptr) free(Ptr); cmsUNUSED_PARAMETER(ContextID); } -// The default realloc function. Again it check for exploits. If Ptr is NULL, -// realloc behaves the same way as malloc and allocates a new block of size bytes. +// The default realloc function. Again it checks for exploits. If Ptr is NULL, +// realloc behaves the same way as malloc and allocates a new block of size bytes. static void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { @@ -139,13 +139,13 @@ void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Nu if (Total == 0) return NULL; // Safe check for overflow. - if (num >= UINT_MAX / size) return NULL; + if (num >= UINT_MAX / size) return NULL; // Check for overflow if (Total < num || Total < size) { return NULL; } - + if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb return _cmsMallocZero(ContextID, Total); @@ -156,7 +156,7 @@ static void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) { void* mem; - + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb mem = _cmsMalloc(ContextID, size); @@ -167,95 +167,149 @@ void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number si return mem; } -// Pointers to malloc and _cmsFree functions in current environment -static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn; -static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn; -static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn; -static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn; -static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn; -static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn; + +// Pointers to memory manager functions in Context0 +_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, + _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn + }; + + +// Reset and duplicate memory manager +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate + ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); + } + else { + + // To reset it, we use the default allocators, which cannot be overriden + ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; + } +} + +// Auxiliar to fill memory management functions from plugin (or context 0 defaults) +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) +{ + if (Plugin == NULL) { + + memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); + } + else { + + ptr ->MallocPtr = Plugin -> MallocPtr; + ptr ->FreePtr = Plugin -> FreePtr; + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults + ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; + ptr ->CallocPtr = _cmsCallocDefaultFn; + ptr ->DupPtr = _cmsDupDefaultFn; + + if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; + + } +} + // Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) { - cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + _cmsMemPluginChunkType* ptr; - // NULL forces to reset to defaults + // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. + // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the + // context internal data should be malloce'd by using those functions. if (Data == NULL) { - MallocPtr = _cmsMallocDefaultFn; - MallocZeroPtr= _cmsMallocZeroDefaultFn; - FreePtr = _cmsFreeDefaultFn; - ReallocPtr = _cmsReallocDefaultFn; - CallocPtr = _cmsCallocDefaultFn; - DupPtr = _cmsDupDefaultFn; + struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; + + // Return to the default allocators + if (ContextID != NULL) { + ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; + } return TRUE; } - // Check for required callbacks - if (Plugin -> MallocPtr == NULL || + // Check for required callbacks + if (Plugin -> MallocPtr == NULL || Plugin -> FreePtr == NULL || - Plugin -> ReallocPtr == NULL) return FALSE; + Plugin -> ReallocPtr == NULL) return FALSE; // Set replacement functions - MallocPtr = Plugin -> MallocPtr; - FreePtr = Plugin -> FreePtr; - ReallocPtr = Plugin -> ReallocPtr; - - if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr; + ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + if (ptr == NULL) + return FALSE; + _cmsInstallAllocFunctions(Plugin, ptr); return TRUE; } // Generic allocate void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) { - return MallocPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->MallocPtr(ContextID, size); } // Generic allocate & zero void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { - return MallocZeroPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->MallocZeroPtr(ContextID, size); } // Generic calloc void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) { - return CallocPtr(ContextID, num, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->CallocPtr(ContextID, num, size); } // Generic reallocate void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { - return ReallocPtr(ContextID, Ptr, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->ReallocPtr(ContextID, Ptr, size); } // Generic free memory void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { - if (Ptr != NULL) FreePtr(ContextID, Ptr); + if (Ptr != NULL) { + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + ptr ->FreePtr(ContextID, Ptr); + } } // Generic block duplication void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { - return DupPtr(ContextID, Org, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->DupPtr(ContextID, Org, size); } // ******************************************************************************************** // Sub allocation takes care of many pointers of small size. The memory allocated in // this way have be freed at once. Next function allocates a single chunk for linked list -// I prefer this method over realloc due to the big inpact on xput realloc may have if -// memory is being swapped to disk. This approach is safer (although thats not true on any platform) +// I prefer this method over realloc due to the big inpact on xput realloc may have if +// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) static _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) { _cmsSubAllocator_chunk* chunk; + // 20K by default + if (Initial == 0) + Initial = 20*1024; + // Create the container chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); if (chunk == NULL) return NULL; @@ -269,10 +323,6 @@ _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32N return NULL; } - // 20K by default - if (Initial == 0) - Initial = 20*1024; - chunk ->BlockSize = Initial; chunk ->Used = 0; chunk ->next = NULL; @@ -325,9 +375,9 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; cmsUInt8Number* ptr; - size = _cmsALIGNLONG(size); + size = _cmsALIGNMEM(size); - // Check for memory. If there is no room, allocate a new chunk of double memory size. + // Check for memory. If there is no room, allocate a new chunk of double memory size. if (size > Free) { _cmsSubAllocator_chunk* chunk; @@ -344,20 +394,40 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) sub ->h = chunk; } - + ptr = sub -> h ->Block + sub -> h ->Used; sub -> h -> Used += size; return (void*) ptr; } +// Duplicate in pool +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) +{ + void *NewPtr; + + // Dup of null pointer is also NULL + if (ptr == NULL) + return NULL; + + NewPtr = _cmsSubAlloc(s, size); + + if (ptr != NULL && NewPtr != NULL) { + memcpy(NewPtr, ptr, size); + } + + return NewPtr; +} + + + // Error logging ****************************************************************** // There is no error handling at all. When a funtion fails, it returns proper value. // For example, all create functions does return NULL on failure. Other return FALSE // It may be interesting, for the developer, to know why the function is failing. // for that reason, lcms2 does offer a logging function. This function does recive -// a ENGLISH string with some clues on what is going wrong. You can show this +// a ENGLISH string with some clues on what is going wrong. You can show this // info to the end user, or just create some sort of log. // The logging function should NOT terminate the program, as this obviously can leave // resources. It is the programmer's responsability to check each function return code @@ -372,8 +442,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) // This is our default log error static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); -// The current handler in actual environment -static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction; +// Context0 storage, which is global +_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; + +// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value +// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; + void* from; + + if (src != NULL) { + from = src ->chunks[Logger]; + } + else { + from = &LogErrorChunk; + } + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); +} // The default error logger does nothing. static @@ -381,34 +469,50 @@ void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorC { // fprintf(stderr, "[lcms]: %s\n", Text); // fflush(stderr); - + cmsUNUSED_PARAMETER(ContextID); cmsUNUSED_PARAMETER(ErrorCode); - cmsUNUSED_PARAMETER(Text); + cmsUNUSED_PARAMETER(Text); } -// Change log error +// Change log error, context based +void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) +{ + _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + + if (lhg != NULL) { + + if (Fn == NULL) + lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; + else + lhg -> LogErrorHandler = Fn; + } +} + +// Change log error, legacy void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) { - if (Fn == NULL) - LogErrorHandler = DefaultLogErrorHandlerFunction; - else - LogErrorHandler = Fn; + cmsSetLogErrorHandlerTHR(NULL, Fn); } -// Log an error +// Log an error // ErrorText is a text holding an english description of error. void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) { va_list args; char Buffer[MAX_ERROR_MESSAGE_LEN]; + _cmsLogErrorChunkType* lhg; + va_start(args, ErrorText); vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); - va_end(args); + va_end(args); - // Call handler - LogErrorHandler(ContextID, ErrorCode, Buffer); + // Check for the context, if specified go there. If not, go for the global + lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + if (lhg ->LogErrorHandler) { + lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); + } } // Utility function to print signatures @@ -419,10 +523,132 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig) // Convert to big endian be = _cmsAdjustEndianess32((cmsUInt32Number) sig); - // Move chars + // Move chars memmove(String, &be, 4); // Make sure of terminator String[4] = 0; } +//-------------------------------------------------------------------------------------------------- + + +static +void* defMtxCreate(cmsContext id) +{ + _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); + _cmsInitMutexPrimitive(ptr_mutex); + return (void*) ptr_mutex; +} + +static +void defMtxDestroy(cmsContext id, void* mtx) +{ + _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); + _cmsFree(id, mtx); +} + +static +cmsBool defMtxLock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; +} + +static +void defMtxUnlock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + _cmsUnlockPrimitive((_cmsMutex *) mtx); +} + + + +// Pointers to memory manager functions in Context0 +_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + void* from; + + if (src != NULL) { + from = src ->chunks[MutexPlugin]; + } + else { + from = &MutexChunk; + } + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); +} + +// Register new ways to transform +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; + _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (Data == NULL) { + + // No lock routines + ctx->CreateMutexPtr = NULL; + ctx->DestroyMutexPtr = NULL; + ctx->LockMutexPtr = NULL; + ctx ->UnlockMutexPtr = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || + Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; + + + ctx->CreateMutexPtr = Plugin->CreateMutexPtr; + ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; + ctx ->LockMutexPtr = Plugin ->LockMutexPtr; + ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; + + // All is ok + return TRUE; +} + +// Generic Mutex fns +void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->CreateMutexPtr == NULL) return NULL; + + return ptr ->CreateMutexPtr(ContextID); +} + +void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->DestroyMutexPtr != NULL) { + + ptr ->DestroyMutexPtr(ContextID, mtx); + } +} + +cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->LockMutexPtr == NULL) return TRUE; + + return ptr ->LockMutexPtr(ContextID, mtx); +} + +void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->UnlockMutexPtr != NULL) { + + ptr ->UnlockMutexPtr(ContextID, mtx); + } +} diff --git a/thirdparty/liblcms2/src/cmsgamma.c b/thirdparty/liblcms2/src/cmsgamma.c index db156c75..78691668 100644 --- a/thirdparty/liblcms2/src/cmsgamma.c +++ b/thirdparty/liblcms2/src/cmsgamma.c @@ -1,42 +1,42 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2013 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- // #include "lcms2_internal.h" -// Tone curves are powerful constructs that can contain curves specified in diverse ways. +// Tone curves are powerful constructs that can contain curves specified in diverse ways. // The curve is stored in segments, where each segment can be sampled or specified by parameters. -// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation, -// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes, -// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function, +// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation, +// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes, +// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function, // the plug-in should provide the type id, how many parameters each type has, and a pointer to -// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will -// be called with the type id as a negative value, and a sampled version of the reversed curve +// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will +// be called with the type id as a negative value, and a sampled version of the reversed curve // will be built. // ----------------------------------------------------------------- Implementation -// Maxim number of nodes +// Maxim number of nodes #define MAX_NODES_IN_CURVE 4097 #define MINUS_INF (-1E22F) #define PLUS_INF (+1E22F) @@ -53,12 +53,11 @@ typedef struct _cmsParametricCurvesCollection_st { } _cmsParametricCurvesCollection; - -// This is the default (built-in) evaluator +// This is the default (built-in) evaluator static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); // The built-in list -static _cmsParametricCurvesCollection DefaultCurves = { +static _cmsParametricCurvesCollection DefaultCurves = { 9, // # of curve types { 1, 2, 3, 4, 5, 6, 7, 8, 108 }, // Parametric curve ID { 1, 3, 4, 5, 7, 4, 5, 5, 1 }, // Parameters by type @@ -66,22 +65,77 @@ static _cmsParametricCurvesCollection DefaultCurves = { NULL // Next in chain }; +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginCurvesList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsCurvesPluginChunkType newHead = { NULL }; + _cmsParametricCurvesCollection* entry; + _cmsParametricCurvesCollection* Anterior = NULL; + _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->ParametricCurves; + entry != NULL; + entry = entry ->Next) { + + _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.ParametricCurves == NULL) + newHead.ParametricCurves = newEntry; + } + + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); +} + +// The allocator have to follow the chain +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Copy all linked list + DupPluginCurvesList(ctx, src); + } + else { + static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); + } +} + + // The linked list head -static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; +_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; // As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; _cmsParametricCurvesCollection* fl; - + if (Data == NULL) { - - ParametricCurves = &DefaultCurves; + + ctx -> ParametricCurves = NULL; return TRUE; } - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection)); + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -97,8 +151,8 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); // Keep linked list - fl ->Next = ParametricCurves; - ParametricCurves = fl; + fl ->Next = ctx->ParametricCurves; + ctx->ParametricCurves = fl; // All is ok return TRUE; @@ -120,17 +174,29 @@ int IsInSet(int Type, _cmsParametricCurvesCollection* c) // Search for the collection which contains a specific type static -_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) +_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) { _cmsParametricCurvesCollection* c; int Position; + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); - for (c = ParametricCurves; c != NULL; c = c ->Next) { + for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { Position = IsInSet(Type, c); if (Position != -1) { - if (index != NULL) + if (index != NULL) + *index = Position; + return c; + } + } + // If none found, revert for defaults + for (c = &DefaultCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) *index = Position; return c; } @@ -139,12 +205,12 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) return NULL; } -// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case +// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case // no optimation curve is computed. nSegments may also be zero in the inverse case, where only the // optimization curve is given. Both features simultaneously is an error static -cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries, - cmsInt32Number nSegments, const cmsCurveSegment* Segments, +cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries, + cmsInt32Number nSegments, const cmsCurveSegment* Segments, const cmsUInt16Number* Values) { cmsToneCurve* p; @@ -179,7 +245,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr } p -> nSegments = nSegments; - + // This 16-bit table contains a limited precision representation of the whole curve and is kept for // increasing xput on certain operations. if (nEntries <= 0) { @@ -189,13 +255,13 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number)); if (p ->Table16 == NULL) goto Error; } - + p -> nEntries = nEntries; - + // Initialize members if requested if (Values != NULL && (nEntries > 0)) { - for (i=0; i < nEntries; i++) + for (i=0; i < nEntries; i++) p ->Table16[i] = Values[i]; } @@ -222,14 +288,15 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr p ->Segments[i].SampledPoints = NULL; - c = GetParametricCurveByType(Segments[i].Type, NULL); + c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); if (c != NULL) p ->Evals[i] = c ->Evaluator; } } - + p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); - return p; + if (p->InterpParams != NULL) + return p; Error: if (p -> Segments) _cmsFree(ContextID, p ->Segments); @@ -248,18 +315,28 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu switch (Type) { - // X = Y ^ Gamma + // X = Y ^ Gamma case 1: - if (R < 0) - Val = 0; + if (R < 0) { + + if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) + Val = R; + else + Val = 0; + } else Val = pow(R, Params[0]); break; // Type 1 Reversed: X = Y ^1/gamma case -1: - if (R < 0) - Val = 0; + if (R < 0) { + + if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) + Val = R; + else + Val = 0; + } else Val = pow(R, 1/Params[0]); break; @@ -285,14 +362,14 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // Type 2 Reversed // X = (Y ^1/g - b) / a - case -2: + case -2: if (R < 0) Val = 0; else Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; if (Val < 0) - Val = 0; + Val = 0; break; @@ -306,7 +383,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu if (R >= disc) { - e = Params[1]*R + Params[2]; + e = Params[1]*R + Params[2]; if (e > 0) Val = pow(e, Params[0]) + Params[3]; @@ -320,15 +397,15 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // Type 3 reversed // X=((Y-c)^1/g - b)/a | (Y>=c) - // X=-b/a | (Y= Params[3]) { - + e = R - Params[3]; if (e > 0) Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1]; - else + else Val = 0; } else { @@ -384,8 +461,8 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu if (e > 0) Val = pow(e, Params[0]) + Params[5]; else - Val = 0; - } + Val = Params[5]; + } else Val = R*Params[3] + Params[6]; break; @@ -400,7 +477,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu if (R >= disc) { e = R - Params[5]; - if (e < 0) + if (e < 0) Val = 0; else Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; @@ -413,46 +490,46 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf // Type 6 is basically identical to type 5 without d - + // Y = (a * X + b) ^ Gamma + c - case 6: + case 6: e = Params[1]*R + Params[2]; - if (e < 0) - Val = 0; - else + if (e < 0) + Val = Params[3]; + else Val = pow(e, Params[0]) + Params[3]; break; - // ((Y - c) ^1/Gamma - b) / a + // ((Y - c) ^1/Gamma - b) / a case -6: e = R - Params[3]; if (e < 0) Val = 0; - else + else Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1]; break; // Y = a * log (b * X^Gamma + c) + d - case 7: + case 7: e = Params[2] * pow(R, Params[0]) + Params[3]; if (e <= 0) - Val = 0; + Val = Params[4]; else Val = Params[1]*log10(e) + Params[4]; break; // (Y - d) / a = log(b * X ^Gamma + c) // pow(10, (Y-d) / a) = b * X ^Gamma + c - // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X + // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X case -7: Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]); break; - //Y = a * b^(c*X+d) + e + //Y = a * b^(c*X+d) + e case 8: Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]); break; @@ -461,14 +538,14 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // Y = (log((y-e) / a) / log(b) - d ) / c // a=0, b=1, c=2, d=3, e=4, case -8: - + disc = R - Params[4]; if (disc < 0) Val = 0; - else - Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2]; + else + Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2]; break; - // S-Shaped: (1 - (1-x)^1/g)^1/g + // S-Shaped: (1 - (1-x)^1/g)^1/g case 108: Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]); break; @@ -491,7 +568,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu } // Evaluate a segmented funtion for a single value. Return -1 if no valid segment found . -// If fn type is 0, perform an interpolation on the table +// If fn type is 0, perform an interpolation on the table static cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) { @@ -505,14 +582,14 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) // Type == 0 means segment is sampled if (g ->Segments[i].Type == 0) { - cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0); + cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0) / (g ->Segments[i].x1 - g ->Segments[i].x0); cmsFloat32Number Out; // Setup the table (TODO: clean that) - g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints; + g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints; g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]); - + return Out; } else @@ -523,6 +600,19 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) return MINUS_INF; } +// Access to estimated low-res table +cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + return t ->nEntries; +} + +const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + return t ->Table16; +} + // Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the // floating point description empty. @@ -540,17 +630,17 @@ int EntriesByGamma(cmsFloat64Number Gamma) // Create a segmented gamma, fill the table -cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, +cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsInt32Number nSegments, const cmsCurveSegment Segments[]) { int i; cmsFloat64Number R, Val; cmsToneCurve* g; int nGridPoints = 4096; - + _cmsAssert(Segments != NULL); - // Optimizatin for identity curves. + // Optimizatin for identity curves. if (nSegments == 1 && Segments[0].Type == 1) { nGridPoints = EntriesByGamma(Segments[0].Params[0]); @@ -577,28 +667,41 @@ cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, // Use a segmented curve to store the floating point table cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) { - cmsCurveSegment Seg[2]; + cmsCurveSegment Seg[3]; - // Initialize segmented curve part up to 0 - Seg[0].x0 = -1; + // A segmented tone curve should have function segments in the first and last positions + // Initialize segmented curve part up to 0 to constant value = samples[0] + Seg[0].x0 = MINUS_INF; Seg[0].x1 = 0; Seg[0].Type = 6; Seg[0].Params[0] = 1; Seg[0].Params[1] = 0; Seg[0].Params[2] = 0; - Seg[0].Params[3] = 0; + Seg[0].Params[3] = values[0]; Seg[0].Params[4] = 0; - // From zero to any + // From zero to 1 Seg[1].x0 = 0; - Seg[1].x1 = 1.0; + Seg[1].x1 = 1.0; Seg[1].Type = 0; Seg[1].nGridPoints = nEntries; Seg[1].SampledPoints = (cmsFloat32Number*) values; - return cmsBuildSegmentedToneCurve(ContextID, 2, Seg); + // Final segment is constant = lastsample + Seg[2].x0 = 1.0; + Seg[2].x1 = PLUS_INF; + Seg[2].Type = 6; + + Seg[2].Params[0] = 1; + Seg[2].Params[1] = 0; + Seg[2].Params[2] = 0; + Seg[2].Params[3] = values[nEntries-1]; + Seg[2].Params[4] = 0; + + + return cmsBuildSegmentedToneCurve(ContextID, 3, Seg); } // Parametric curves @@ -611,12 +714,12 @@ cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt cmsCurveSegment Seg0; int Pos = 0; cmsUInt32Number size; - _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos); + _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); _cmsAssert(Params != NULL); if (c == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); return NULL; } @@ -645,27 +748,27 @@ cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gam void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) { cmsContext ContextID; - + if (Curve == NULL) return; ContextID = Curve ->InterpParams->ContextID; _cmsFreeInterpParams(Curve ->InterpParams); - + if (Curve -> Table16) _cmsFree(ContextID, Curve ->Table16); if (Curve ->Segments) { cmsUInt32Number i; - + for (i=0; i < Curve ->nSegments; i++) { if (Curve ->Segments[i].SampledPoints) { _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); } - if (Curve ->SegInterp[i] != 0) + if (Curve ->SegInterp[i] != 0) _cmsFreeInterpParams(Curve->SegInterp[i]); } @@ -695,18 +798,18 @@ void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) // Duplicate a gamma table cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) -{ +{ if (In == NULL) return NULL; return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); } // Joins two curves for X and Y. Curves should be monotonic. -// We want to get +// We want to get // -// y = Y^-1(X(t)) +// y = Y^-1(X(t)) // -cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, +cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nResultingPoints) { @@ -725,7 +828,7 @@ cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number)); if (Res == NULL) goto Error; - + //Iterate for (i=0; i < nResultingPoints; i++) { @@ -736,7 +839,7 @@ cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, // Allocate space for output out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res); - + Error: if (Res != NULL) _cmsFree(ContextID, Res); @@ -747,25 +850,25 @@ Error: -// Get the surrounding nodes. This is tricky on non-monotonic tables +// Get the surrounding nodes. This is tricky on non-monotonic tables static int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p) -{ +{ int i; int y0, y1; - + // A 1 point table is not allowed if (p -> Domain[0] < 1) return -1; - // Let's see if ascending or descending. + // Let's see if ascending or descending. if (LutTable[0] < LutTable[p ->Domain[0]]) { // Table is overall ascending for (i=p->Domain[0]-1; i >=0; --i) { - y0 = LutTable[i]; + y0 = LutTable[i]; y1 = LutTable[i+1]; - + if (y0 <= y1) { // Increasing if (In >= y0 && In <= y1) return i; } @@ -779,7 +882,7 @@ int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const str // Table is overall descending for (i=0; i < (int) p -> Domain[0]; i++) { - y0 = LutTable[i]; + y0 = LutTable[i]; y1 = LutTable[i+1]; if (y0 <= y1) { // Increasing @@ -802,18 +905,21 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2; int i, j; int Ascending; - + _cmsAssert(InCurve != NULL); // Try to reverse it analytically whatever possible - if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) { + + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && + /* InCurve -> Segments[0].Type <= 5 */ + GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { - return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, - -(InCurve -> Segments[0].Type), + return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, + -(InCurve -> Segments[0].Type), InCurve -> Segments[0].Params); } - // Nope, reverse the table. + // Nope, reverse the table. out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL); if (out == NULL) return NULL; @@ -826,18 +932,18 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1); - // Find interval in which y is within. + // Find interval in which y is within. j = GetInterval(y, InCurve->Table16, InCurve->InterpParams); if (j >= 0) { // Get limits of interval - x1 = InCurve ->Table16[j]; + x1 = InCurve ->Table16[j]; x2 = InCurve ->Table16[j+1]; y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1); y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1); - + // If collapsed, then use any if (x1 == x2) { @@ -846,12 +952,12 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con } else { - // Interpolate + // Interpolate a = (y2 - y1) / (x2 - x1); b = y2 - a * x2; } } - + out ->Table16[i] = _cmsQuickSaturateWord(a* y + b); } @@ -887,7 +993,7 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[] c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); - + if (c != NULL && d != NULL && e != NULL) { @@ -899,7 +1005,7 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[] c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2]; e[2] = lambda / d[2]; z[2] = w[2] * y[2] - c[1] * z[1]; - + for (i = 3; i < m - 1; i++) { i1 = i - 1; i2 = i - 2; d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; @@ -907,18 +1013,18 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[] e[i] = lambda / d[i]; z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2]; } - + i1 = m - 2; i2 = m - 3; - + d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1]; z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2]; i1 = m - 1; i2 = m - 2; - + d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m]; z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m]; - + for (i = m - 2; 1<= i; i--) z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2]; @@ -933,7 +1039,7 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[] return st; } -// Smooths a curve sampled at regular intervals. +// Smooths a curve sampled at regular intervals. cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda) { cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE]; @@ -941,7 +1047,7 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda if (Tab == NULL) return FALSE; - if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do + if (cmsIsToneCurveLinear(Tab)) return TRUE; // Nothing to do nItems = Tab -> nEntries; @@ -968,11 +1074,20 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda if (z[i] == 0.) Zeros++; if (z[i] >= 65535.) Poles++; - if (z[i] < z[i-1]) return FALSE; // Non-Monotonic + if (z[i] < z[i-1]) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic."); + return FALSE; + } } - if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros - if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles + if (Zeros > (nItems / 3)) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros."); + return FALSE; + } + if (Poles > (nItems / 3)) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles."); + return FALSE; + } // Seems ok for (i=0; i < nItems; i++) { @@ -1008,20 +1123,42 @@ cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t) { int n; int i, last; + cmsBool lDescending; _cmsAssert(t != NULL); - n = t ->nEntries; - last = t ->Table16[n-1]; + // Degenerated curves are monotonic? Ok, let's pass them + n = t ->nEntries; + if (n < 2) return TRUE; - for (i = n-2; i >= 0; --i) { + // Curve direction + lDescending = cmsIsToneCurveDescending(t); - if (t ->Table16[i] > last) + if (lDescending) { - return FALSE; - else - last = t ->Table16[i]; + last = t ->Table16[0]; + for (i = 1; i < n; i++) { + + if (t ->Table16[i] - last > 2) // We allow some ripple + return FALSE; + else + last = t ->Table16[i]; + + } + } + else { + + last = t ->Table16[n-1]; + + for (i = n-2; i >= 0; --i) { + + if (t ->Table16[i] - last > 2) + return FALSE; + else + last = t ->Table16[i]; + + } } return TRUE; @@ -1061,10 +1198,10 @@ cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsF if (Curve ->nSegments == 0) { cmsUInt16Number In, Out; - + In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0); Out = cmsEvalToneCurve16(Curve, In); - + return (cmsFloat32Number) (Out / 65535.0); } @@ -1084,21 +1221,21 @@ cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt1 // Least squares fitting. -// A mathematical procedure for finding the best-fitting curve to a given set of points by -// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. -// The sum of the squares of the offsets is used instead of the offset absolute values because -// this allows the residuals to be treated as a continuous differentiable quantity. +// A mathematical procedure for finding the best-fitting curve to a given set of points by +// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. +// The sum of the squares of the offsets is used instead of the offset absolute values because +// this allows the residuals to be treated as a continuous differentiable quantity. // // y = f(x) = x ^ g // // R = (yi - (xi^g)) // R2 = (yi - (xi^g))2 // SUM R2 = SUM (yi - (xi^g))2 -// -// dR2/dg = -2 SUM x^g log(x)(y - x^g) -// solving for dR2/dg = 0 -// -// g = 1/n * SUM(log(y) / log(x)) +// +// dR2/dg = -2 SUM x^g log(x)(y - x^g) +// solving for dR2/dg = 0 +// +// g = 1/n * SUM(log(y) / log(x)) cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision) { @@ -1110,13 +1247,13 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num sum = sum2 = n = 0; - // Excluding endpoints + // Excluding endpoints for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) { x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1); y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x); - // Avoid 7% on lower part to prevent + // Avoid 7% on lower part to prevent // artifacts due to linear ramps if (y > 0. && y < 1. && x > 0.07) { diff --git a/thirdparty/liblcms2/src/cmsgmt.c b/thirdparty/liblcms2/src/cmsgmt.c index c2f3a9a5..09427650 100644 --- a/thirdparty/liblcms2/src/cmsgmt.c +++ b/thirdparty/liblcms2/src/cmsgmt.c @@ -1,591 +1,590 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//--------------------------------------------------------------------------------- -// - -#include "lcms2_internal.h" - - -// Auxiliar: append a Lab identity after the given sequence of profiles -// and return the transform. Lab profile is closed, rest of profiles are kept open. -cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsHTRANSFORM xform; - cmsHPROFILE hLab; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - cmsUInt32Number i; - - // This is a rather big number and there is no need of dynamic memory - // since we are adding a profile, 254 + 1 = 255 and this is the limit - if (nProfiles > 254) return NULL; - - // The output space - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - // Create a copy of parameters - for (i=0; i < nProfiles; i++) { - - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Place Lab identity at chain's end. - ProfileList[nProfiles] = hLab; - BPCList[nProfiles] = 0; - AdaptationList[nProfiles] = 1.0; - IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; - - // Create the transform - xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, - BPCList, - IntentList, - AdaptationList, - NULL, 0, - InputFormat, - OutputFormat, - dwFlags); - - cmsCloseProfile(hLab); - - return xform; -} - - -// Compute K -> L* relationship. Flags may include black point compensation. In this case, -// the relationship is assumed from the profile with BPC to a black point zero. -static -cmsToneCurve* ComputeKToLstar(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve* out = NULL; - cmsUInt32Number i; - cmsHTRANSFORM xform; - cmsCIELab Lab; - cmsFloat32Number cmyk[4]; - cmsFloat32Number* SampledPoints; - - xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (xform == NULL) return NULL; - - SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); - if (SampledPoints == NULL) goto Error; - - for (i=0; i < nPoints; i++) { - - cmyk[0] = 0; - cmyk[1] = 0; - cmyk[2] = 0; - cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); - - cmsDoTransform(xform, cmyk, &Lab, 1); - SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation - } - - out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); - -Error: - - cmsDeleteTransform(xform); - if (SampledPoints) _cmsFree(ContextID, SampledPoints); - - return out; -} - - -// Compute Black tone curve on a CMYK -> CMYK transform. This is done by -// using the proof direction on both profiles to find K->L* relationship -// then joining both curves. dwFlags may include black point compensation. -cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve *in, *out, *KTone; - - // Make sure CMYK -> CMYK - if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; - - - // Make sure last is an output profile - if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; - - // Create individual curves. BPC works also as each K to L* is - // computed as a BPC to zero black point in case of L* - in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (in == NULL) return NULL; - - out = ComputeKToLstar(ContextID, nPoints, 1, - Intents + (nProfiles - 1), - hProfiles + (nProfiles - 1), - BPC + (nProfiles - 1), - AdaptationStates + (nProfiles - 1), - dwFlags); - if (out == NULL) { - cmsFreeToneCurve(in); - return NULL; - } - - // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but - // since this is used on black-preserving LUTs, we are not loosing accuracy in any case - KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); - - // Get rid of components - cmsFreeToneCurve(in); cmsFreeToneCurve(out); - - // Something went wrong... - if (KTone == NULL) return NULL; - - // Make sure it is monotonic - if (!cmsIsToneCurveMonotonic(KTone)) { - - cmsFreeToneCurve(KTone); - return NULL; - } - - return KTone; -} - - -// Gamut LUT Creation ----------------------------------------------------------------------------------------- - -// Used by gamut & softproofing - -typedef struct { - - cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL - cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back - cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut - - } GAMUTCHAIN; - -// This sampler does compute gamut boundaries by comparing original -// values with a transform going back and forth. Values above ERR_THERESHOLD -// of maximum are considered out of gamut. - -#define ERR_THERESHOLD 5 - - -static -int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; - cmsCIELab LabIn1, LabOut1; - cmsCIELab LabIn2, LabOut2; - cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; - cmsFloat64Number dE1, dE2, ErrorRatio; - - // Assume in-gamut by default. - dE1 = 0.; - dE2 = 0; - ErrorRatio = 1.0; - - // Convert input to Lab - if (t -> hInput != NULL) - cmsDoTransform(t -> hInput, In, &LabIn1, 1); - - // converts from PCS to colorant. This always - // does return in-gamut values, - cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); - - // Now, do the inverse, from colorant to PCS. - cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); - - memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); - - // Try again, but this time taking Check as input - cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); - cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); - - // Take difference of direct value - dE1 = cmsDeltaE(&LabIn1, &LabOut1); - - // Take difference of converted value - dE2 = cmsDeltaE(&LabIn2, &LabOut2); - - - // if dE1 is small and dE2 is small, value is likely to be in gamut - if (dE1 < t->Thereshold && dE2 < t->Thereshold) - Out[0] = 0; - else { - - // if dE1 is small and dE2 is big, undefined. Assume in gamut - if (dE1 < t->Thereshold && dE2 > t->Thereshold) - Out[0] = 0; - else - // dE1 is big and dE2 is small, clearly out of gamut - if (dE1 > t->Thereshold && dE2 < t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); - else { - - // dE1 is big and dE2 is also big, could be due to perceptual mapping - // so take error ratio - if (dE2 == 0.0) - ErrorRatio = dE1; - else - ErrorRatio = dE1 / dE2; - - if (ErrorRatio > t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); - else - Out[0] = 0; - } - } - - - return TRUE; -} - -// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs -// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE -// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. -// -// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, -// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. - -cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number nGamutPCSposition, - cmsHPROFILE hGamut) -{ - cmsHPROFILE hLab; - cmsPipeline* Gamut; - cmsStage* CLUT; - cmsUInt32Number dwFormat; - GAMUTCHAIN Chain; - int nChannels, nGridpoints; - cmsColorSpaceSignature ColorSpace; - cmsUInt32Number i; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - - memset(&Chain, 0, sizeof(GAMUTCHAIN)); - - - if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); - return NULL; - } - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - - // The figure of merit. On matrix-shaper profiles, should be almost zero as - // the conversion is pretty exact. On LUT based profiles, different resolutions - // of input and output CLUT may result in differences. - - if (cmsIsMatrixShaper(hGamut)) { - - Chain.Thereshold = 1.0; - } - else { - Chain.Thereshold = ERR_THERESHOLD; - } - - - // Create a copy of parameters - for (i=0; i < nGamutPCSposition; i++) { - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Fill Lab identity - ProfileList[nGamutPCSposition] = hLab; - BPCList[nGamutPCSposition] = 0; - AdaptationList[nGamutPCSposition] = 1.0; - Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; - - - ColorSpace = cmsGetColorSpace(hGamut); - - nChannels = cmsChannelsOf(ColorSpace); - nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - - // 16 bits to Lab double - Chain.hInput = cmsCreateExtendedTransform(ContextID, - nGamutPCSposition + 1, - ProfileList, - BPCList, - Intents, - AdaptationList, - NULL, 0, - dwFormat, TYPE_Lab_DBL, - cmsFLAGS_NOCACHE); - - - // Does create the forward step. Lab double to device - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - Chain.hForward = cmsCreateTransformTHR(ContextID, - hLab, TYPE_Lab_DBL, - hGamut, dwFormat, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - // Does create the backwards step - Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, - hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - - // All ok? - if (Chain.hForward && Chain.hReverse) { - - // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing - // dE when doing a transform back and forth on the colorimetric intent. - - Gamut = cmsPipelineAlloc(ContextID, 3, 1); - - if (Gamut != NULL) { - - CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); - cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); - - cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); - } - } - else - Gamut = NULL; // Didn't work... - - // Free all needed stuff. - if (Chain.hInput) cmsDeleteTransform(Chain.hInput); - if (Chain.hForward) cmsDeleteTransform(Chain.hForward); - if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); - if (hLab) cmsCloseProfile(hLab); - - // And return computed hull - return Gamut; -} - -// Total Area Coverage estimation ---------------------------------------------------------------- - -typedef struct { - cmsUInt32Number nOutputChans; - cmsHTRANSFORM hRoundTrip; - cmsFloat32Number MaxTAC; - cmsFloat32Number MaxInput[cmsMAXCHANNELS]; - -} cmsTACestimator; - - -// This callback just accounts the maximum ink dropped in the given node. It does not populate any -// memory, as the destination table is NULL. Its only purpose it to know the global maximum. -static -int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) -{ - cmsTACestimator* bp = (cmsTACestimator*) Cargo; - cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; - cmsUInt32Number i; - cmsFloat32Number Sum; - - - // Evaluate the xform - cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); - - // All all amounts of ink - for (Sum=0, i=0; i < bp ->nOutputChans; i++) - Sum += RoundTrip[i]; - - // If above maximum, keep track of input values - if (Sum > bp ->MaxTAC) { - - bp ->MaxTAC = Sum; - - for (i=0; i < bp ->nOutputChans; i++) { - bp ->MaxInput[i] = In[i]; - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(Out); -} - - -// Detect Total area coverage of the profile -cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) -{ - cmsTACestimator bp; - cmsUInt32Number dwFormatter; - cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; - cmsHPROFILE hLab; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - // TAC only works on output profiles - if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { - return 0; - } - - // Create a fake formatter for result - dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); - - bp.nOutputChans = T_CHANNELS(dwFormatter); - bp.MaxTAC = 0; // Initial TAC is 0 - - // for safety - if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return 0; - // Setup a roundtrip on perceptual intent in output profile for TAC estimation - bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, - hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); - - cmsCloseProfile(hLab); - if (bp.hRoundTrip == NULL) return 0; - - // For L* we only need black and white. For C* we need many points - GridPoints[0] = 6; - GridPoints[1] = 74; - GridPoints[2] = 74; - - - if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { - bp.MaxTAC = 0; - } - - cmsDeleteTransform(bp.hRoundTrip); - - // Results in % - return bp.MaxTAC; -} - - -// Carefully, clamp on CIELab space. - -cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, - double amax, double amin, - double bmax, double bmin) -{ - - // Whole Luma surface to zero - - if (Lab -> L < 0) { - - Lab-> L = Lab->a = Lab-> b = 0.0; - return FALSE; - } - - // Clamp white, DISCARD HIGHLIGHTS. This is done - // in such way because icc spec doesn't allow the - // use of L>100 as a highlight means. - - if (Lab->L > 100) - Lab -> L = 100; - - // Check out gamut prism, on a, b faces - - if (Lab -> a < amin || Lab->a > amax|| - Lab -> b < bmin || Lab->b > bmax) { - - cmsCIELCh LCh; - double h, slope; - - // Falls outside a, b limits. Transports to LCh space, - // and then do the clipping - - - if (Lab -> a == 0.0) { // Is hue exactly 90? - - // atan will not work, so clamp here - Lab -> b = Lab->b < 0 ? bmin : bmax; - return TRUE; - } - - cmsLab2LCh(&LCh, Lab); - - slope = Lab -> b / Lab -> a; - h = LCh.h; - - // There are 4 zones - - if ((h >= 0. && h < 45.) || - (h >= 315 && h <= 360.)) { - - // clip by amax - Lab -> a = amax; - Lab -> b = amax * slope; - } - else - if (h >= 45. && h < 135.) - { - // clip by bmax - Lab -> b = bmax; - Lab -> a = bmax / slope; - } - else - if (h >= 135. && h < 225.) { - // clip by amin - Lab -> a = amin; - Lab -> b = amin * slope; - - } - else - if (h >= 225. && h < 315.) { - // clip by bmin - Lab -> b = bmin; - Lab -> a = bmin / slope; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); - return FALSE; - } - - } - - return TRUE; -} +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2012 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Auxiliar: append a Lab identity after the given sequence of profiles +// and return the transform. Lab profile is closed, rest of profiles are kept open. +cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hLab; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + cmsUInt32Number i; + + // This is a rather big number and there is no need of dynamic memory + // since we are adding a profile, 254 + 1 = 255 and this is the limit + if (nProfiles > 254) return NULL; + + // The output space + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + // Create a copy of parameters + for (i=0; i < nProfiles; i++) { + + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Place Lab identity at chain's end. + ProfileList[nProfiles] = hLab; + BPCList[nProfiles] = 0; + AdaptationList[nProfiles] = 1.0; + IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; + + // Create the transform + xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + InputFormat, + OutputFormat, + dwFlags); + + cmsCloseProfile(hLab); + + return xform; +} + + +// Compute K -> L* relationship. Flags may include black point compensation. In this case, +// the relationship is assumed from the profile with BPC to a black point zero. +static +cmsToneCurve* ComputeKToLstar(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve* out = NULL; + cmsUInt32Number i; + cmsHTRANSFORM xform; + cmsCIELab Lab; + cmsFloat32Number cmyk[4]; + cmsFloat32Number* SampledPoints; + + xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (xform == NULL) return NULL; + + SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); + if (SampledPoints == NULL) goto Error; + + for (i=0; i < nPoints; i++) { + + cmyk[0] = 0; + cmyk[1] = 0; + cmyk[2] = 0; + cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); + + cmsDoTransform(xform, cmyk, &Lab, 1); + SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation + } + + out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); + +Error: + + cmsDeleteTransform(xform); + if (SampledPoints) _cmsFree(ContextID, SampledPoints); + + return out; +} + + +// Compute Black tone curve on a CMYK -> CMYK transform. This is done by +// using the proof direction on both profiles to find K->L* relationship +// then joining both curves. dwFlags may include black point compensation. +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve *in, *out, *KTone; + + // Make sure CMYK -> CMYK + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; + + + // Make sure last is an output profile + if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; + + // Create individual curves. BPC works also as each K to L* is + // computed as a BPC to zero black point in case of L* + in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (in == NULL) return NULL; + + out = ComputeKToLstar(ContextID, nPoints, 1, + Intents + (nProfiles - 1), + &hProfiles [nProfiles - 1], + BPC + (nProfiles - 1), + AdaptationStates + (nProfiles - 1), + dwFlags); + if (out == NULL) { + cmsFreeToneCurve(in); + return NULL; + } + + // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but + // since this is used on black-preserving LUTs, we are not loosing accuracy in any case + KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); + + // Get rid of components + cmsFreeToneCurve(in); cmsFreeToneCurve(out); + + // Something went wrong... + if (KTone == NULL) return NULL; + + // Make sure it is monotonic + if (!cmsIsToneCurveMonotonic(KTone)) { + cmsFreeToneCurve(KTone); + return NULL; + } + + return KTone; +} + + +// Gamut LUT Creation ----------------------------------------------------------------------------------------- + +// Used by gamut & softproofing + +typedef struct { + + cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL + cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back + cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut + + } GAMUTCHAIN; + +// This sampler does compute gamut boundaries by comparing original +// values with a transform going back and forth. Values above ERR_THERESHOLD +// of maximum are considered out of gamut. + +#define ERR_THERESHOLD 5 + + +static +int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) +{ + GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; + cmsCIELab LabIn1, LabOut1; + cmsCIELab LabIn2, LabOut2; + cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; + cmsFloat64Number dE1, dE2, ErrorRatio; + + // Assume in-gamut by default. + ErrorRatio = 1.0; + + // Convert input to Lab + cmsDoTransform(t -> hInput, In, &LabIn1, 1); + + // converts from PCS to colorant. This always + // does return in-gamut values, + cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); + + // Now, do the inverse, from colorant to PCS. + cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); + + memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); + + // Try again, but this time taking Check as input + cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); + cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); + + // Take difference of direct value + dE1 = cmsDeltaE(&LabIn1, &LabOut1); + + // Take difference of converted value + dE2 = cmsDeltaE(&LabIn2, &LabOut2); + + + // if dE1 is small and dE2 is small, value is likely to be in gamut + if (dE1 < t->Thereshold && dE2 < t->Thereshold) + Out[0] = 0; + else { + + // if dE1 is small and dE2 is big, undefined. Assume in gamut + if (dE1 < t->Thereshold && dE2 > t->Thereshold) + Out[0] = 0; + else + // dE1 is big and dE2 is small, clearly out of gamut + if (dE1 > t->Thereshold && dE2 < t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); + else { + + // dE1 is big and dE2 is also big, could be due to perceptual mapping + // so take error ratio + if (dE2 == 0.0) + ErrorRatio = dE1; + else + ErrorRatio = dE1 / dE2; + + if (ErrorRatio > t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); + else + Out[0] = 0; + } + } + + + return TRUE; +} + +// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs +// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE +// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. +// +// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, +// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. + +cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number nGamutPCSposition, + cmsHPROFILE hGamut) +{ + cmsHPROFILE hLab; + cmsPipeline* Gamut; + cmsStage* CLUT; + cmsUInt32Number dwFormat; + GAMUTCHAIN Chain; + int nChannels, nGridpoints; + cmsColorSpaceSignature ColorSpace; + cmsUInt32Number i; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + + memset(&Chain, 0, sizeof(GAMUTCHAIN)); + + + if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); + return NULL; + } + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + + // The figure of merit. On matrix-shaper profiles, should be almost zero as + // the conversion is pretty exact. On LUT based profiles, different resolutions + // of input and output CLUT may result in differences. + + if (cmsIsMatrixShaper(hGamut)) { + + Chain.Thereshold = 1.0; + } + else { + Chain.Thereshold = ERR_THERESHOLD; + } + + + // Create a copy of parameters + for (i=0; i < nGamutPCSposition; i++) { + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Fill Lab identity + ProfileList[nGamutPCSposition] = hLab; + BPCList[nGamutPCSposition] = 0; + AdaptationList[nGamutPCSposition] = 1.0; + IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; + + + ColorSpace = cmsGetColorSpace(hGamut); + + nChannels = cmsChannelsOf(ColorSpace); + nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + + // 16 bits to Lab double + Chain.hInput = cmsCreateExtendedTransform(ContextID, + nGamutPCSposition + 1, + ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + dwFormat, TYPE_Lab_DBL, + cmsFLAGS_NOCACHE); + + + // Does create the forward step. Lab double to device + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + Chain.hForward = cmsCreateTransformTHR(ContextID, + hLab, TYPE_Lab_DBL, + hGamut, dwFormat, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + // Does create the backwards step + Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, + hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + + // All ok? + if (Chain.hInput && Chain.hForward && Chain.hReverse) { + + // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing + // dE when doing a transform back and forth on the colorimetric intent. + + Gamut = cmsPipelineAlloc(ContextID, 3, 1); + if (Gamut != NULL) { + + CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); + if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) { + cmsPipelineFree(Gamut); + Gamut = NULL; + } + else { + cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + } + } + } + else + Gamut = NULL; // Didn't work... + + // Free all needed stuff. + if (Chain.hInput) cmsDeleteTransform(Chain.hInput); + if (Chain.hForward) cmsDeleteTransform(Chain.hForward); + if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); + if (hLab) cmsCloseProfile(hLab); + + // And return computed hull + return Gamut; +} + +// Total Area Coverage estimation ---------------------------------------------------------------- + +typedef struct { + cmsUInt32Number nOutputChans; + cmsHTRANSFORM hRoundTrip; + cmsFloat32Number MaxTAC; + cmsFloat32Number MaxInput[cmsMAXCHANNELS]; + +} cmsTACestimator; + + +// This callback just accounts the maximum ink dropped in the given node. It does not populate any +// memory, as the destination table is NULL. Its only purpose it to know the global maximum. +static +int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) +{ + cmsTACestimator* bp = (cmsTACestimator*) Cargo; + cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; + cmsUInt32Number i; + cmsFloat32Number Sum; + + + // Evaluate the xform + cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); + + // All all amounts of ink + for (Sum=0, i=0; i < bp ->nOutputChans; i++) + Sum += RoundTrip[i]; + + // If above maximum, keep track of input values + if (Sum > bp ->MaxTAC) { + + bp ->MaxTAC = Sum; + + for (i=0; i < bp ->nOutputChans; i++) { + bp ->MaxInput[i] = In[i]; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(Out); +} + + +// Detect Total area coverage of the profile +cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) +{ + cmsTACestimator bp; + cmsUInt32Number dwFormatter; + cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; + cmsHPROFILE hLab; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // TAC only works on output profiles + if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { + return 0; + } + + // Create a fake formatter for result + dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); + + bp.nOutputChans = T_CHANNELS(dwFormatter); + bp.MaxTAC = 0; // Initial TAC is 0 + + // for safety + if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return 0; + // Setup a roundtrip on perceptual intent in output profile for TAC estimation + bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, + hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); + + cmsCloseProfile(hLab); + if (bp.hRoundTrip == NULL) return 0; + + // For L* we only need black and white. For C* we need many points + GridPoints[0] = 6; + GridPoints[1] = 74; + GridPoints[2] = 74; + + + if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { + bp.MaxTAC = 0; + } + + cmsDeleteTransform(bp.hRoundTrip); + + // Results in % + return bp.MaxTAC; +} + + +// Carefully, clamp on CIELab space. + +cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, + double amax, double amin, + double bmax, double bmin) +{ + + // Whole Luma surface to zero + + if (Lab -> L < 0) { + + Lab-> L = Lab->a = Lab-> b = 0.0; + return FALSE; + } + + // Clamp white, DISCARD HIGHLIGHTS. This is done + // in such way because icc spec doesn't allow the + // use of L>100 as a highlight means. + + if (Lab->L > 100) + Lab -> L = 100; + + // Check out gamut prism, on a, b faces + + if (Lab -> a < amin || Lab->a > amax|| + Lab -> b < bmin || Lab->b > bmax) { + + cmsCIELCh LCh; + double h, slope; + + // Falls outside a, b limits. Transports to LCh space, + // and then do the clipping + + + if (Lab -> a == 0.0) { // Is hue exactly 90? + + // atan will not work, so clamp here + Lab -> b = Lab->b < 0 ? bmin : bmax; + return TRUE; + } + + cmsLab2LCh(&LCh, Lab); + + slope = Lab -> b / Lab -> a; + h = LCh.h; + + // There are 4 zones + + if ((h >= 0. && h < 45.) || + (h >= 315 && h <= 360.)) { + + // clip by amax + Lab -> a = amax; + Lab -> b = amax * slope; + } + else + if (h >= 45. && h < 135.) + { + // clip by bmax + Lab -> b = bmax; + Lab -> a = bmax / slope; + } + else + if (h >= 135. && h < 225.) { + // clip by amin + Lab -> a = amin; + Lab -> b = amin * slope; + + } + else + if (h >= 225. && h < 315.) { + // clip by bmin + Lab -> b = bmin; + Lab -> a = bmin / slope; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); + return FALSE; + } + + } + + return TRUE; +} diff --git a/thirdparty/liblcms2/src/cmshalf.c b/thirdparty/liblcms2/src/cmshalf.c new file mode 100644 index 00000000..204dee96 --- /dev/null +++ b/thirdparty/liblcms2/src/cmshalf.c @@ -0,0 +1,535 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2012 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// +#include "lcms2_internal.h" + +#ifndef CMS_NO_HALF_SUPPORT + +// This code is inspired in the paper "Fast Half Float Conversions" +// by Jeroen van der Zijp + +static cmsUInt32Number Mantissa[2048] = { + +0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34a00000, +0x34c00000, 0x34e00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, +0x35400000, 0x35500000, 0x35600000, 0x35700000, 0x35800000, 0x35880000, +0x35900000, 0x35980000, 0x35a00000, 0x35a80000, 0x35b00000, 0x35b80000, +0x35c00000, 0x35c80000, 0x35d00000, 0x35d80000, 0x35e00000, 0x35e80000, +0x35f00000, 0x35f80000, 0x36000000, 0x36040000, 0x36080000, 0x360c0000, +0x36100000, 0x36140000, 0x36180000, 0x361c0000, 0x36200000, 0x36240000, +0x36280000, 0x362c0000, 0x36300000, 0x36340000, 0x36380000, 0x363c0000, +0x36400000, 0x36440000, 0x36480000, 0x364c0000, 0x36500000, 0x36540000, +0x36580000, 0x365c0000, 0x36600000, 0x36640000, 0x36680000, 0x366c0000, +0x36700000, 0x36740000, 0x36780000, 0x367c0000, 0x36800000, 0x36820000, +0x36840000, 0x36860000, 0x36880000, 0x368a0000, 0x368c0000, 0x368e0000, +0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369a0000, +0x369c0000, 0x369e0000, 0x36a00000, 0x36a20000, 0x36a40000, 0x36a60000, +0x36a80000, 0x36aa0000, 0x36ac0000, 0x36ae0000, 0x36b00000, 0x36b20000, +0x36b40000, 0x36b60000, 0x36b80000, 0x36ba0000, 0x36bc0000, 0x36be0000, +0x36c00000, 0x36c20000, 0x36c40000, 0x36c60000, 0x36c80000, 0x36ca0000, +0x36cc0000, 0x36ce0000, 0x36d00000, 0x36d20000, 0x36d40000, 0x36d60000, +0x36d80000, 0x36da0000, 0x36dc0000, 0x36de0000, 0x36e00000, 0x36e20000, +0x36e40000, 0x36e60000, 0x36e80000, 0x36ea0000, 0x36ec0000, 0x36ee0000, +0x36f00000, 0x36f20000, 0x36f40000, 0x36f60000, 0x36f80000, 0x36fa0000, +0x36fc0000, 0x36fe0000, 0x37000000, 0x37010000, 0x37020000, 0x37030000, +0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, +0x370a0000, 0x370b0000, 0x370c0000, 0x370d0000, 0x370e0000, 0x370f0000, +0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, +0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371a0000, 0x371b0000, +0x371c0000, 0x371d0000, 0x371e0000, 0x371f0000, 0x37200000, 0x37210000, +0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, +0x37280000, 0x37290000, 0x372a0000, 0x372b0000, 0x372c0000, 0x372d0000, +0x372e0000, 0x372f0000, 0x37300000, 0x37310000, 0x37320000, 0x37330000, +0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, +0x373a0000, 0x373b0000, 0x373c0000, 0x373d0000, 0x373e0000, 0x373f0000, +0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, +0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374a0000, 0x374b0000, +0x374c0000, 0x374d0000, 0x374e0000, 0x374f0000, 0x37500000, 0x37510000, +0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, +0x37580000, 0x37590000, 0x375a0000, 0x375b0000, 0x375c0000, 0x375d0000, +0x375e0000, 0x375f0000, 0x37600000, 0x37610000, 0x37620000, 0x37630000, +0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, +0x376a0000, 0x376b0000, 0x376c0000, 0x376d0000, 0x376e0000, 0x376f0000, +0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, +0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377a0000, 0x377b0000, +0x377c0000, 0x377d0000, 0x377e0000, 0x377f0000, 0x37800000, 0x37808000, +0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, +0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, +0x37870000, 0x37878000, 0x37880000, 0x37888000, 0x37890000, 0x37898000, +0x378a0000, 0x378a8000, 0x378b0000, 0x378b8000, 0x378c0000, 0x378c8000, +0x378d0000, 0x378d8000, 0x378e0000, 0x378e8000, 0x378f0000, 0x378f8000, +0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, +0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, +0x37960000, 0x37968000, 0x37970000, 0x37978000, 0x37980000, 0x37988000, +0x37990000, 0x37998000, 0x379a0000, 0x379a8000, 0x379b0000, 0x379b8000, +0x379c0000, 0x379c8000, 0x379d0000, 0x379d8000, 0x379e0000, 0x379e8000, +0x379f0000, 0x379f8000, 0x37a00000, 0x37a08000, 0x37a10000, 0x37a18000, +0x37a20000, 0x37a28000, 0x37a30000, 0x37a38000, 0x37a40000, 0x37a48000, +0x37a50000, 0x37a58000, 0x37a60000, 0x37a68000, 0x37a70000, 0x37a78000, +0x37a80000, 0x37a88000, 0x37a90000, 0x37a98000, 0x37aa0000, 0x37aa8000, +0x37ab0000, 0x37ab8000, 0x37ac0000, 0x37ac8000, 0x37ad0000, 0x37ad8000, +0x37ae0000, 0x37ae8000, 0x37af0000, 0x37af8000, 0x37b00000, 0x37b08000, +0x37b10000, 0x37b18000, 0x37b20000, 0x37b28000, 0x37b30000, 0x37b38000, +0x37b40000, 0x37b48000, 0x37b50000, 0x37b58000, 0x37b60000, 0x37b68000, +0x37b70000, 0x37b78000, 0x37b80000, 0x37b88000, 0x37b90000, 0x37b98000, +0x37ba0000, 0x37ba8000, 0x37bb0000, 0x37bb8000, 0x37bc0000, 0x37bc8000, +0x37bd0000, 0x37bd8000, 0x37be0000, 0x37be8000, 0x37bf0000, 0x37bf8000, +0x37c00000, 0x37c08000, 0x37c10000, 0x37c18000, 0x37c20000, 0x37c28000, +0x37c30000, 0x37c38000, 0x37c40000, 0x37c48000, 0x37c50000, 0x37c58000, +0x37c60000, 0x37c68000, 0x37c70000, 0x37c78000, 0x37c80000, 0x37c88000, +0x37c90000, 0x37c98000, 0x37ca0000, 0x37ca8000, 0x37cb0000, 0x37cb8000, +0x37cc0000, 0x37cc8000, 0x37cd0000, 0x37cd8000, 0x37ce0000, 0x37ce8000, +0x37cf0000, 0x37cf8000, 0x37d00000, 0x37d08000, 0x37d10000, 0x37d18000, +0x37d20000, 0x37d28000, 0x37d30000, 0x37d38000, 0x37d40000, 0x37d48000, +0x37d50000, 0x37d58000, 0x37d60000, 0x37d68000, 0x37d70000, 0x37d78000, +0x37d80000, 0x37d88000, 0x37d90000, 0x37d98000, 0x37da0000, 0x37da8000, +0x37db0000, 0x37db8000, 0x37dc0000, 0x37dc8000, 0x37dd0000, 0x37dd8000, +0x37de0000, 0x37de8000, 0x37df0000, 0x37df8000, 0x37e00000, 0x37e08000, +0x37e10000, 0x37e18000, 0x37e20000, 0x37e28000, 0x37e30000, 0x37e38000, +0x37e40000, 0x37e48000, 0x37e50000, 0x37e58000, 0x37e60000, 0x37e68000, +0x37e70000, 0x37e78000, 0x37e80000, 0x37e88000, 0x37e90000, 0x37e98000, +0x37ea0000, 0x37ea8000, 0x37eb0000, 0x37eb8000, 0x37ec0000, 0x37ec8000, +0x37ed0000, 0x37ed8000, 0x37ee0000, 0x37ee8000, 0x37ef0000, 0x37ef8000, +0x37f00000, 0x37f08000, 0x37f10000, 0x37f18000, 0x37f20000, 0x37f28000, +0x37f30000, 0x37f38000, 0x37f40000, 0x37f48000, 0x37f50000, 0x37f58000, +0x37f60000, 0x37f68000, 0x37f70000, 0x37f78000, 0x37f80000, 0x37f88000, +0x37f90000, 0x37f98000, 0x37fa0000, 0x37fa8000, 0x37fb0000, 0x37fb8000, +0x37fc0000, 0x37fc8000, 0x37fd0000, 0x37fd8000, 0x37fe0000, 0x37fe8000, +0x37ff0000, 0x37ff8000, 0x38000000, 0x38004000, 0x38008000, 0x3800c000, +0x38010000, 0x38014000, 0x38018000, 0x3801c000, 0x38020000, 0x38024000, +0x38028000, 0x3802c000, 0x38030000, 0x38034000, 0x38038000, 0x3803c000, +0x38040000, 0x38044000, 0x38048000, 0x3804c000, 0x38050000, 0x38054000, +0x38058000, 0x3805c000, 0x38060000, 0x38064000, 0x38068000, 0x3806c000, +0x38070000, 0x38074000, 0x38078000, 0x3807c000, 0x38080000, 0x38084000, +0x38088000, 0x3808c000, 0x38090000, 0x38094000, 0x38098000, 0x3809c000, +0x380a0000, 0x380a4000, 0x380a8000, 0x380ac000, 0x380b0000, 0x380b4000, +0x380b8000, 0x380bc000, 0x380c0000, 0x380c4000, 0x380c8000, 0x380cc000, +0x380d0000, 0x380d4000, 0x380d8000, 0x380dc000, 0x380e0000, 0x380e4000, +0x380e8000, 0x380ec000, 0x380f0000, 0x380f4000, 0x380f8000, 0x380fc000, +0x38100000, 0x38104000, 0x38108000, 0x3810c000, 0x38110000, 0x38114000, +0x38118000, 0x3811c000, 0x38120000, 0x38124000, 0x38128000, 0x3812c000, +0x38130000, 0x38134000, 0x38138000, 0x3813c000, 0x38140000, 0x38144000, +0x38148000, 0x3814c000, 0x38150000, 0x38154000, 0x38158000, 0x3815c000, +0x38160000, 0x38164000, 0x38168000, 0x3816c000, 0x38170000, 0x38174000, +0x38178000, 0x3817c000, 0x38180000, 0x38184000, 0x38188000, 0x3818c000, +0x38190000, 0x38194000, 0x38198000, 0x3819c000, 0x381a0000, 0x381a4000, +0x381a8000, 0x381ac000, 0x381b0000, 0x381b4000, 0x381b8000, 0x381bc000, +0x381c0000, 0x381c4000, 0x381c8000, 0x381cc000, 0x381d0000, 0x381d4000, +0x381d8000, 0x381dc000, 0x381e0000, 0x381e4000, 0x381e8000, 0x381ec000, +0x381f0000, 0x381f4000, 0x381f8000, 0x381fc000, 0x38200000, 0x38204000, +0x38208000, 0x3820c000, 0x38210000, 0x38214000, 0x38218000, 0x3821c000, +0x38220000, 0x38224000, 0x38228000, 0x3822c000, 0x38230000, 0x38234000, +0x38238000, 0x3823c000, 0x38240000, 0x38244000, 0x38248000, 0x3824c000, +0x38250000, 0x38254000, 0x38258000, 0x3825c000, 0x38260000, 0x38264000, +0x38268000, 0x3826c000, 0x38270000, 0x38274000, 0x38278000, 0x3827c000, +0x38280000, 0x38284000, 0x38288000, 0x3828c000, 0x38290000, 0x38294000, +0x38298000, 0x3829c000, 0x382a0000, 0x382a4000, 0x382a8000, 0x382ac000, +0x382b0000, 0x382b4000, 0x382b8000, 0x382bc000, 0x382c0000, 0x382c4000, +0x382c8000, 0x382cc000, 0x382d0000, 0x382d4000, 0x382d8000, 0x382dc000, +0x382e0000, 0x382e4000, 0x382e8000, 0x382ec000, 0x382f0000, 0x382f4000, +0x382f8000, 0x382fc000, 0x38300000, 0x38304000, 0x38308000, 0x3830c000, +0x38310000, 0x38314000, 0x38318000, 0x3831c000, 0x38320000, 0x38324000, +0x38328000, 0x3832c000, 0x38330000, 0x38334000, 0x38338000, 0x3833c000, +0x38340000, 0x38344000, 0x38348000, 0x3834c000, 0x38350000, 0x38354000, +0x38358000, 0x3835c000, 0x38360000, 0x38364000, 0x38368000, 0x3836c000, +0x38370000, 0x38374000, 0x38378000, 0x3837c000, 0x38380000, 0x38384000, +0x38388000, 0x3838c000, 0x38390000, 0x38394000, 0x38398000, 0x3839c000, +0x383a0000, 0x383a4000, 0x383a8000, 0x383ac000, 0x383b0000, 0x383b4000, +0x383b8000, 0x383bc000, 0x383c0000, 0x383c4000, 0x383c8000, 0x383cc000, +0x383d0000, 0x383d4000, 0x383d8000, 0x383dc000, 0x383e0000, 0x383e4000, +0x383e8000, 0x383ec000, 0x383f0000, 0x383f4000, 0x383f8000, 0x383fc000, +0x38400000, 0x38404000, 0x38408000, 0x3840c000, 0x38410000, 0x38414000, +0x38418000, 0x3841c000, 0x38420000, 0x38424000, 0x38428000, 0x3842c000, +0x38430000, 0x38434000, 0x38438000, 0x3843c000, 0x38440000, 0x38444000, +0x38448000, 0x3844c000, 0x38450000, 0x38454000, 0x38458000, 0x3845c000, +0x38460000, 0x38464000, 0x38468000, 0x3846c000, 0x38470000, 0x38474000, +0x38478000, 0x3847c000, 0x38480000, 0x38484000, 0x38488000, 0x3848c000, +0x38490000, 0x38494000, 0x38498000, 0x3849c000, 0x384a0000, 0x384a4000, +0x384a8000, 0x384ac000, 0x384b0000, 0x384b4000, 0x384b8000, 0x384bc000, +0x384c0000, 0x384c4000, 0x384c8000, 0x384cc000, 0x384d0000, 0x384d4000, +0x384d8000, 0x384dc000, 0x384e0000, 0x384e4000, 0x384e8000, 0x384ec000, +0x384f0000, 0x384f4000, 0x384f8000, 0x384fc000, 0x38500000, 0x38504000, +0x38508000, 0x3850c000, 0x38510000, 0x38514000, 0x38518000, 0x3851c000, +0x38520000, 0x38524000, 0x38528000, 0x3852c000, 0x38530000, 0x38534000, +0x38538000, 0x3853c000, 0x38540000, 0x38544000, 0x38548000, 0x3854c000, +0x38550000, 0x38554000, 0x38558000, 0x3855c000, 0x38560000, 0x38564000, +0x38568000, 0x3856c000, 0x38570000, 0x38574000, 0x38578000, 0x3857c000, +0x38580000, 0x38584000, 0x38588000, 0x3858c000, 0x38590000, 0x38594000, +0x38598000, 0x3859c000, 0x385a0000, 0x385a4000, 0x385a8000, 0x385ac000, +0x385b0000, 0x385b4000, 0x385b8000, 0x385bc000, 0x385c0000, 0x385c4000, +0x385c8000, 0x385cc000, 0x385d0000, 0x385d4000, 0x385d8000, 0x385dc000, +0x385e0000, 0x385e4000, 0x385e8000, 0x385ec000, 0x385f0000, 0x385f4000, +0x385f8000, 0x385fc000, 0x38600000, 0x38604000, 0x38608000, 0x3860c000, +0x38610000, 0x38614000, 0x38618000, 0x3861c000, 0x38620000, 0x38624000, +0x38628000, 0x3862c000, 0x38630000, 0x38634000, 0x38638000, 0x3863c000, +0x38640000, 0x38644000, 0x38648000, 0x3864c000, 0x38650000, 0x38654000, +0x38658000, 0x3865c000, 0x38660000, 0x38664000, 0x38668000, 0x3866c000, +0x38670000, 0x38674000, 0x38678000, 0x3867c000, 0x38680000, 0x38684000, +0x38688000, 0x3868c000, 0x38690000, 0x38694000, 0x38698000, 0x3869c000, +0x386a0000, 0x386a4000, 0x386a8000, 0x386ac000, 0x386b0000, 0x386b4000, +0x386b8000, 0x386bc000, 0x386c0000, 0x386c4000, 0x386c8000, 0x386cc000, +0x386d0000, 0x386d4000, 0x386d8000, 0x386dc000, 0x386e0000, 0x386e4000, +0x386e8000, 0x386ec000, 0x386f0000, 0x386f4000, 0x386f8000, 0x386fc000, +0x38700000, 0x38704000, 0x38708000, 0x3870c000, 0x38710000, 0x38714000, +0x38718000, 0x3871c000, 0x38720000, 0x38724000, 0x38728000, 0x3872c000, +0x38730000, 0x38734000, 0x38738000, 0x3873c000, 0x38740000, 0x38744000, +0x38748000, 0x3874c000, 0x38750000, 0x38754000, 0x38758000, 0x3875c000, +0x38760000, 0x38764000, 0x38768000, 0x3876c000, 0x38770000, 0x38774000, +0x38778000, 0x3877c000, 0x38780000, 0x38784000, 0x38788000, 0x3878c000, +0x38790000, 0x38794000, 0x38798000, 0x3879c000, 0x387a0000, 0x387a4000, +0x387a8000, 0x387ac000, 0x387b0000, 0x387b4000, 0x387b8000, 0x387bc000, +0x387c0000, 0x387c4000, 0x387c8000, 0x387cc000, 0x387d0000, 0x387d4000, +0x387d8000, 0x387dc000, 0x387e0000, 0x387e4000, 0x387e8000, 0x387ec000, +0x387f0000, 0x387f4000, 0x387f8000, 0x387fc000, 0x38000000, 0x38002000, +0x38004000, 0x38006000, 0x38008000, 0x3800a000, 0x3800c000, 0x3800e000, +0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801a000, +0x3801c000, 0x3801e000, 0x38020000, 0x38022000, 0x38024000, 0x38026000, +0x38028000, 0x3802a000, 0x3802c000, 0x3802e000, 0x38030000, 0x38032000, +0x38034000, 0x38036000, 0x38038000, 0x3803a000, 0x3803c000, 0x3803e000, +0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804a000, +0x3804c000, 0x3804e000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, +0x38058000, 0x3805a000, 0x3805c000, 0x3805e000, 0x38060000, 0x38062000, +0x38064000, 0x38066000, 0x38068000, 0x3806a000, 0x3806c000, 0x3806e000, +0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807a000, +0x3807c000, 0x3807e000, 0x38080000, 0x38082000, 0x38084000, 0x38086000, +0x38088000, 0x3808a000, 0x3808c000, 0x3808e000, 0x38090000, 0x38092000, +0x38094000, 0x38096000, 0x38098000, 0x3809a000, 0x3809c000, 0x3809e000, +0x380a0000, 0x380a2000, 0x380a4000, 0x380a6000, 0x380a8000, 0x380aa000, +0x380ac000, 0x380ae000, 0x380b0000, 0x380b2000, 0x380b4000, 0x380b6000, +0x380b8000, 0x380ba000, 0x380bc000, 0x380be000, 0x380c0000, 0x380c2000, +0x380c4000, 0x380c6000, 0x380c8000, 0x380ca000, 0x380cc000, 0x380ce000, +0x380d0000, 0x380d2000, 0x380d4000, 0x380d6000, 0x380d8000, 0x380da000, +0x380dc000, 0x380de000, 0x380e0000, 0x380e2000, 0x380e4000, 0x380e6000, +0x380e8000, 0x380ea000, 0x380ec000, 0x380ee000, 0x380f0000, 0x380f2000, +0x380f4000, 0x380f6000, 0x380f8000, 0x380fa000, 0x380fc000, 0x380fe000, +0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810a000, +0x3810c000, 0x3810e000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, +0x38118000, 0x3811a000, 0x3811c000, 0x3811e000, 0x38120000, 0x38122000, +0x38124000, 0x38126000, 0x38128000, 0x3812a000, 0x3812c000, 0x3812e000, +0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813a000, +0x3813c000, 0x3813e000, 0x38140000, 0x38142000, 0x38144000, 0x38146000, +0x38148000, 0x3814a000, 0x3814c000, 0x3814e000, 0x38150000, 0x38152000, +0x38154000, 0x38156000, 0x38158000, 0x3815a000, 0x3815c000, 0x3815e000, +0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816a000, +0x3816c000, 0x3816e000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, +0x38178000, 0x3817a000, 0x3817c000, 0x3817e000, 0x38180000, 0x38182000, +0x38184000, 0x38186000, 0x38188000, 0x3818a000, 0x3818c000, 0x3818e000, +0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819a000, +0x3819c000, 0x3819e000, 0x381a0000, 0x381a2000, 0x381a4000, 0x381a6000, +0x381a8000, 0x381aa000, 0x381ac000, 0x381ae000, 0x381b0000, 0x381b2000, +0x381b4000, 0x381b6000, 0x381b8000, 0x381ba000, 0x381bc000, 0x381be000, +0x381c0000, 0x381c2000, 0x381c4000, 0x381c6000, 0x381c8000, 0x381ca000, +0x381cc000, 0x381ce000, 0x381d0000, 0x381d2000, 0x381d4000, 0x381d6000, +0x381d8000, 0x381da000, 0x381dc000, 0x381de000, 0x381e0000, 0x381e2000, +0x381e4000, 0x381e6000, 0x381e8000, 0x381ea000, 0x381ec000, 0x381ee000, +0x381f0000, 0x381f2000, 0x381f4000, 0x381f6000, 0x381f8000, 0x381fa000, +0x381fc000, 0x381fe000, 0x38200000, 0x38202000, 0x38204000, 0x38206000, +0x38208000, 0x3820a000, 0x3820c000, 0x3820e000, 0x38210000, 0x38212000, +0x38214000, 0x38216000, 0x38218000, 0x3821a000, 0x3821c000, 0x3821e000, +0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822a000, +0x3822c000, 0x3822e000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, +0x38238000, 0x3823a000, 0x3823c000, 0x3823e000, 0x38240000, 0x38242000, +0x38244000, 0x38246000, 0x38248000, 0x3824a000, 0x3824c000, 0x3824e000, +0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825a000, +0x3825c000, 0x3825e000, 0x38260000, 0x38262000, 0x38264000, 0x38266000, +0x38268000, 0x3826a000, 0x3826c000, 0x3826e000, 0x38270000, 0x38272000, +0x38274000, 0x38276000, 0x38278000, 0x3827a000, 0x3827c000, 0x3827e000, +0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828a000, +0x3828c000, 0x3828e000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, +0x38298000, 0x3829a000, 0x3829c000, 0x3829e000, 0x382a0000, 0x382a2000, +0x382a4000, 0x382a6000, 0x382a8000, 0x382aa000, 0x382ac000, 0x382ae000, +0x382b0000, 0x382b2000, 0x382b4000, 0x382b6000, 0x382b8000, 0x382ba000, +0x382bc000, 0x382be000, 0x382c0000, 0x382c2000, 0x382c4000, 0x382c6000, +0x382c8000, 0x382ca000, 0x382cc000, 0x382ce000, 0x382d0000, 0x382d2000, +0x382d4000, 0x382d6000, 0x382d8000, 0x382da000, 0x382dc000, 0x382de000, +0x382e0000, 0x382e2000, 0x382e4000, 0x382e6000, 0x382e8000, 0x382ea000, +0x382ec000, 0x382ee000, 0x382f0000, 0x382f2000, 0x382f4000, 0x382f6000, +0x382f8000, 0x382fa000, 0x382fc000, 0x382fe000, 0x38300000, 0x38302000, +0x38304000, 0x38306000, 0x38308000, 0x3830a000, 0x3830c000, 0x3830e000, +0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831a000, +0x3831c000, 0x3831e000, 0x38320000, 0x38322000, 0x38324000, 0x38326000, +0x38328000, 0x3832a000, 0x3832c000, 0x3832e000, 0x38330000, 0x38332000, +0x38334000, 0x38336000, 0x38338000, 0x3833a000, 0x3833c000, 0x3833e000, +0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834a000, +0x3834c000, 0x3834e000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, +0x38358000, 0x3835a000, 0x3835c000, 0x3835e000, 0x38360000, 0x38362000, +0x38364000, 0x38366000, 0x38368000, 0x3836a000, 0x3836c000, 0x3836e000, +0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837a000, +0x3837c000, 0x3837e000, 0x38380000, 0x38382000, 0x38384000, 0x38386000, +0x38388000, 0x3838a000, 0x3838c000, 0x3838e000, 0x38390000, 0x38392000, +0x38394000, 0x38396000, 0x38398000, 0x3839a000, 0x3839c000, 0x3839e000, +0x383a0000, 0x383a2000, 0x383a4000, 0x383a6000, 0x383a8000, 0x383aa000, +0x383ac000, 0x383ae000, 0x383b0000, 0x383b2000, 0x383b4000, 0x383b6000, +0x383b8000, 0x383ba000, 0x383bc000, 0x383be000, 0x383c0000, 0x383c2000, +0x383c4000, 0x383c6000, 0x383c8000, 0x383ca000, 0x383cc000, 0x383ce000, +0x383d0000, 0x383d2000, 0x383d4000, 0x383d6000, 0x383d8000, 0x383da000, +0x383dc000, 0x383de000, 0x383e0000, 0x383e2000, 0x383e4000, 0x383e6000, +0x383e8000, 0x383ea000, 0x383ec000, 0x383ee000, 0x383f0000, 0x383f2000, +0x383f4000, 0x383f6000, 0x383f8000, 0x383fa000, 0x383fc000, 0x383fe000, +0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840a000, +0x3840c000, 0x3840e000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, +0x38418000, 0x3841a000, 0x3841c000, 0x3841e000, 0x38420000, 0x38422000, +0x38424000, 0x38426000, 0x38428000, 0x3842a000, 0x3842c000, 0x3842e000, +0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843a000, +0x3843c000, 0x3843e000, 0x38440000, 0x38442000, 0x38444000, 0x38446000, +0x38448000, 0x3844a000, 0x3844c000, 0x3844e000, 0x38450000, 0x38452000, +0x38454000, 0x38456000, 0x38458000, 0x3845a000, 0x3845c000, 0x3845e000, +0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846a000, +0x3846c000, 0x3846e000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, +0x38478000, 0x3847a000, 0x3847c000, 0x3847e000, 0x38480000, 0x38482000, +0x38484000, 0x38486000, 0x38488000, 0x3848a000, 0x3848c000, 0x3848e000, +0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849a000, +0x3849c000, 0x3849e000, 0x384a0000, 0x384a2000, 0x384a4000, 0x384a6000, +0x384a8000, 0x384aa000, 0x384ac000, 0x384ae000, 0x384b0000, 0x384b2000, +0x384b4000, 0x384b6000, 0x384b8000, 0x384ba000, 0x384bc000, 0x384be000, +0x384c0000, 0x384c2000, 0x384c4000, 0x384c6000, 0x384c8000, 0x384ca000, +0x384cc000, 0x384ce000, 0x384d0000, 0x384d2000, 0x384d4000, 0x384d6000, +0x384d8000, 0x384da000, 0x384dc000, 0x384de000, 0x384e0000, 0x384e2000, +0x384e4000, 0x384e6000, 0x384e8000, 0x384ea000, 0x384ec000, 0x384ee000, +0x384f0000, 0x384f2000, 0x384f4000, 0x384f6000, 0x384f8000, 0x384fa000, +0x384fc000, 0x384fe000, 0x38500000, 0x38502000, 0x38504000, 0x38506000, +0x38508000, 0x3850a000, 0x3850c000, 0x3850e000, 0x38510000, 0x38512000, +0x38514000, 0x38516000, 0x38518000, 0x3851a000, 0x3851c000, 0x3851e000, +0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852a000, +0x3852c000, 0x3852e000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, +0x38538000, 0x3853a000, 0x3853c000, 0x3853e000, 0x38540000, 0x38542000, +0x38544000, 0x38546000, 0x38548000, 0x3854a000, 0x3854c000, 0x3854e000, +0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855a000, +0x3855c000, 0x3855e000, 0x38560000, 0x38562000, 0x38564000, 0x38566000, +0x38568000, 0x3856a000, 0x3856c000, 0x3856e000, 0x38570000, 0x38572000, +0x38574000, 0x38576000, 0x38578000, 0x3857a000, 0x3857c000, 0x3857e000, +0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858a000, +0x3858c000, 0x3858e000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, +0x38598000, 0x3859a000, 0x3859c000, 0x3859e000, 0x385a0000, 0x385a2000, +0x385a4000, 0x385a6000, 0x385a8000, 0x385aa000, 0x385ac000, 0x385ae000, +0x385b0000, 0x385b2000, 0x385b4000, 0x385b6000, 0x385b8000, 0x385ba000, +0x385bc000, 0x385be000, 0x385c0000, 0x385c2000, 0x385c4000, 0x385c6000, +0x385c8000, 0x385ca000, 0x385cc000, 0x385ce000, 0x385d0000, 0x385d2000, +0x385d4000, 0x385d6000, 0x385d8000, 0x385da000, 0x385dc000, 0x385de000, +0x385e0000, 0x385e2000, 0x385e4000, 0x385e6000, 0x385e8000, 0x385ea000, +0x385ec000, 0x385ee000, 0x385f0000, 0x385f2000, 0x385f4000, 0x385f6000, +0x385f8000, 0x385fa000, 0x385fc000, 0x385fe000, 0x38600000, 0x38602000, +0x38604000, 0x38606000, 0x38608000, 0x3860a000, 0x3860c000, 0x3860e000, +0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861a000, +0x3861c000, 0x3861e000, 0x38620000, 0x38622000, 0x38624000, 0x38626000, +0x38628000, 0x3862a000, 0x3862c000, 0x3862e000, 0x38630000, 0x38632000, +0x38634000, 0x38636000, 0x38638000, 0x3863a000, 0x3863c000, 0x3863e000, +0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864a000, +0x3864c000, 0x3864e000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, +0x38658000, 0x3865a000, 0x3865c000, 0x3865e000, 0x38660000, 0x38662000, +0x38664000, 0x38666000, 0x38668000, 0x3866a000, 0x3866c000, 0x3866e000, +0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867a000, +0x3867c000, 0x3867e000, 0x38680000, 0x38682000, 0x38684000, 0x38686000, +0x38688000, 0x3868a000, 0x3868c000, 0x3868e000, 0x38690000, 0x38692000, +0x38694000, 0x38696000, 0x38698000, 0x3869a000, 0x3869c000, 0x3869e000, +0x386a0000, 0x386a2000, 0x386a4000, 0x386a6000, 0x386a8000, 0x386aa000, +0x386ac000, 0x386ae000, 0x386b0000, 0x386b2000, 0x386b4000, 0x386b6000, +0x386b8000, 0x386ba000, 0x386bc000, 0x386be000, 0x386c0000, 0x386c2000, +0x386c4000, 0x386c6000, 0x386c8000, 0x386ca000, 0x386cc000, 0x386ce000, +0x386d0000, 0x386d2000, 0x386d4000, 0x386d6000, 0x386d8000, 0x386da000, +0x386dc000, 0x386de000, 0x386e0000, 0x386e2000, 0x386e4000, 0x386e6000, +0x386e8000, 0x386ea000, 0x386ec000, 0x386ee000, 0x386f0000, 0x386f2000, +0x386f4000, 0x386f6000, 0x386f8000, 0x386fa000, 0x386fc000, 0x386fe000, +0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870a000, +0x3870c000, 0x3870e000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, +0x38718000, 0x3871a000, 0x3871c000, 0x3871e000, 0x38720000, 0x38722000, +0x38724000, 0x38726000, 0x38728000, 0x3872a000, 0x3872c000, 0x3872e000, +0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873a000, +0x3873c000, 0x3873e000, 0x38740000, 0x38742000, 0x38744000, 0x38746000, +0x38748000, 0x3874a000, 0x3874c000, 0x3874e000, 0x38750000, 0x38752000, +0x38754000, 0x38756000, 0x38758000, 0x3875a000, 0x3875c000, 0x3875e000, +0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876a000, +0x3876c000, 0x3876e000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, +0x38778000, 0x3877a000, 0x3877c000, 0x3877e000, 0x38780000, 0x38782000, +0x38784000, 0x38786000, 0x38788000, 0x3878a000, 0x3878c000, 0x3878e000, +0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879a000, +0x3879c000, 0x3879e000, 0x387a0000, 0x387a2000, 0x387a4000, 0x387a6000, +0x387a8000, 0x387aa000, 0x387ac000, 0x387ae000, 0x387b0000, 0x387b2000, +0x387b4000, 0x387b6000, 0x387b8000, 0x387ba000, 0x387bc000, 0x387be000, +0x387c0000, 0x387c2000, 0x387c4000, 0x387c6000, 0x387c8000, 0x387ca000, +0x387cc000, 0x387ce000, 0x387d0000, 0x387d2000, 0x387d4000, 0x387d6000, +0x387d8000, 0x387da000, 0x387dc000, 0x387de000, 0x387e0000, 0x387e2000, +0x387e4000, 0x387e6000, 0x387e8000, 0x387ea000, 0x387ec000, 0x387ee000, +0x387f0000, 0x387f2000, 0x387f4000, 0x387f6000, 0x387f8000, 0x387fa000, +0x387fc000, 0x387fe000 +}; + +static cmsUInt16Number Offset[64] = { +0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0000, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400 +}; + +static cmsUInt32Number Exponent[64] = { +0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, +0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, +0x06000000, 0x06800000, 0x07000000, 0x07800000, 0x08000000, 0x08800000, +0x09000000, 0x09800000, 0x0a000000, 0x0a800000, 0x0b000000, 0x0b800000, +0x0c000000, 0x0c800000, 0x0d000000, 0x0d800000, 0x0e000000, 0x0e800000, +0x0f000000, 0x47800000, 0x80000000, 0x80800000, 0x81000000, 0x81800000, +0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, +0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000, +0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8a000000, 0x8a800000, +0x8b000000, 0x8b800000, 0x8c000000, 0x8c800000, 0x8d000000, 0x8d800000, +0x8e000000, 0x8e800000, 0x8f000000, 0xc7800000 +}; + +static cmsUInt16Number Base[512] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, +0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, +0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, +0x4800, 0x4c00, 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, +0x7000, 0x7400, 0x7800, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, +0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, +0x8800, 0x8c00, 0x9000, 0x9400, 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, +0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, +0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00 +}; + +static cmsUInt8Number Shift[512] = { +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, +0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0d, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, +0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x0d +}; + +cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h) +{ + union { + cmsFloat32Number flt; + cmsUInt32Number num; + } out; + + int n = h >> 10; + + out.num = Mantissa[ (h & 0x3ff) + Offset[ n ] ] + Exponent[ n ]; + return out.flt; +} + +cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt) +{ + union { + cmsFloat32Number flt; + cmsUInt32Number num; + } in; + + cmsUInt32Number n, j; + + in.flt = flt; + n = in.num; + j = (n >> 23) & 0x1ff; + + return (cmsUInt16Number) ((cmsUInt32Number) Base[ j ] + (( n & 0x007fffff) >> Shift[ j ])); +} + +#endif diff --git a/thirdparty/liblcms2/src/cmsintrp.c b/thirdparty/liblcms2/src/cmsintrp.c index 9aced860..5d5f35d3 100644 --- a/thirdparty/liblcms2/src/cmsintrp.c +++ b/thirdparty/liblcms2/src/cmsintrp.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -33,59 +33,85 @@ static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); // This is the default factory -static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory; +_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + void* from; + + _cmsAssert(ctx != NULL); + + if (src != NULL) { + from = src ->chunks[InterpPlugin]; + } + else { + static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; + + from = &InterpPluginChunk; + } + + _cmsAssert(from != NULL); + ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); +} // Main plug-in entry -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); if (Data == NULL) { - - Interpolators = DefaultInterpolatorsFactory; + + ptr ->Interpolators = NULL; return TRUE; } // Set replacement functions - Interpolators = Plugin ->InterpolatorsFactory; + ptr ->Interpolators = Plugin ->InterpolatorsFactory; return TRUE; } // Set the interpolation method +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) +{ + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) -{ - // Invoke factory, possibly in the Plug-in - p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + p ->Interpolation.Lerp16 = NULL; - // If unsupported by the plug-in, go for the LittleCMS default. + // Invoke factory, possibly in the Plug-in + if (ptr ->Interpolators != NULL) + p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + + // If unsupported by the plug-in, go for the LittleCMS default. // If happens only if an extern plug-in is being used if (p ->Interpolation.Lerp16 == NULL) p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags); // Check for valid interpolator (we just check one member of the union) - if (p ->Interpolation.Lerp16 == NULL) { + if (p ->Interpolation.Lerp16 == NULL) { return FALSE; } + return TRUE; } // This function precalculates as many parameters as possible to speed up the interpolation. cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, - const cmsUInt32Number nSamples[], - int InputChan, int OutputChan, + const cmsUInt32Number nSamples[], + int InputChan, int OutputChan, const void *Table, cmsUInt32Number dwFlags) -{ +{ cmsInterpParams* p; int i; - + // Check for maximum inputs if (InputChan > MAX_INPUT_DIMENSIONS) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); return NULL; } @@ -104,17 +130,17 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, for (i=0; i < InputChan; i++) { p -> nSamples[i] = nSamples[i]; - p -> Domain[i] = nSamples[i] - 1; + p -> Domain[i] = nSamples[i] - 1; } // Compute factors to apply to each component to index the grid array - p -> opta[0] = p -> nOutputs; + p -> opta[0] = p -> nOutputs; for (i=1; i < InputChan; i++) p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; - if (!_cmsSetInterpolationRoutine(p)) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); + if (!_cmsSetInterpolationRoutine(ContextID, p)) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); _cmsFree(ContextID, p); return NULL; } @@ -131,7 +157,7 @@ cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; // Fill the auxiliar array - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Samples[i] = nSamples; // Call the extended function @@ -146,27 +172,27 @@ void _cmsFreeInterpParams(cmsInterpParams* p) } -// Inline fixed point interpolation +// Inline fixed point interpolation cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h) { - cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; - dif = (dif >> 16) + l; + cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; + dif = (dif >> 16) + l; return (cmsUInt16Number) (dif); } // Linear interpolation (Fixed-point optimized) static -void LinLerp1D(register const cmsUInt16Number Value[], - register cmsUInt16Number Output[], +void LinLerp1D(register const cmsUInt16Number Value[], + register cmsUInt16Number Output[], register const cmsInterpParams* p) { - cmsUInt16Number y1, y0; + cmsUInt16Number y1, y0; int cell0, rest; int val3; const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; - // if last value... + // if last value... if (Value[0] == 0xffff) { Output[0] = LutTable[p -> Domain[0]]; @@ -182,15 +208,20 @@ void LinLerp1D(register const cmsUInt16Number Value[], y0 = LutTable[cell0]; y1 = LutTable[cell0+1]; - + Output[0] = LinearInterp(rest, y0, y1); } +// To prevent out of bounds indexing +cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) +{ + return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); +} // Floating-point version of 1D interpolation static -void LinLerp1Dfloat(const cmsFloat32Number Value[], - cmsFloat32Number Output[], +void LinLerp1Dfloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], const cmsInterpParams* p) { cmsFloat32Number y1, y0; @@ -198,13 +229,15 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[], int cell0, cell1; const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + val2 = fclamp(Value[0]); + // if last value... - if (Value[0] == 1.0) { + if (val2 == 1.0) { Output[0] = LutTable[p -> Domain[0]]; return; } - val2 = p -> Domain[0] * Value[0]; + val2 *= p -> Domain[0]; cell0 = (int) floor(val2); cell1 = (int) ceil(val2); @@ -215,15 +248,15 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[], y0 = LutTable[cell0] ; y1 = LutTable[cell1] ; - Output[0] = y0 + (y1 - y0) * rest; + Output[0] = y0 + (y1 - y0) * rest; } -// Eval gray LUT having only one input channel +// Eval gray LUT having only one input channel static -void Eval1Input(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval1Input(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) { cmsS15Fixed16Number fk; @@ -251,32 +284,34 @@ void Eval1Input(register const cmsUInt16Number Input[], -// Eval gray LUT having only one input channel +// Eval gray LUT having only one input channel static -void Eval1InputFloat(const cmsFloat32Number Value[], - cmsFloat32Number Output[], +void Eval1InputFloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], const cmsInterpParams* p) { cmsFloat32Number y1, y0; cmsFloat32Number val2, rest; int cell0, cell1; cmsUInt32Number OutChan; - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + + val2 = fclamp(Value[0]); // if last value... - if (Value[0] == 1.0) { + if (val2 == 1.0) { Output[0] = LutTable[p -> Domain[0]]; return; } - val2 = p -> Domain[0] * Value[0]; + val2 *= p -> Domain[0]; cell0 = (int) floor(val2); cell1 = (int) ceil(val2); // Rest is 16 LSB bits rest = val2 - cell0; - + cell0 *= p -> opta[0]; cell1 *= p -> opta[0]; @@ -285,21 +320,21 @@ void Eval1InputFloat(const cmsFloat32Number Value[], y0 = LutTable[cell0 + OutChan] ; y1 = LutTable[cell1 + OutChan] ; - Output[OutChan] = y0 + (y1 - y0) * rest; + Output[OutChan] = y0 + (y1 - y0) * rest; } } // Bilinear interpolation (16 bits) - cmsFloat32Number version static -void BilinearInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void BilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) { # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) # define DENS(i,j) (LutTable[(i)+(j)+OutChan]) - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; cmsFloat32Number px, py; int x0, y0, X0, Y0, X1, Y1; @@ -308,22 +343,22 @@ void BilinearInterpFloat(const cmsFloat32Number Input[], d00, d01, d10, d11, dx0, dx1, dxy; - + TotalOut = p -> nOutputs; - px = Input[0] * p->Domain[0]; - py = Input[1] * p->Domain[1]; + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; - + X0 = p -> opta[1] * x0; X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]); Y0 = p -> opta[0] * y0; Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]); - + for (OutChan = 0; OutChan < TotalOut; OutChan++) { - + d00 = DENS(X0, Y0); d01 = DENS(X0, Y1); d10 = DENS(X1, Y0); @@ -344,7 +379,7 @@ void BilinearInterpFloat(const cmsFloat32Number Input[], // Bilinear interpolation (16 bits) - optimized version static -void BilinearInterp16(register const cmsUInt16Number Input[], +void BilinearInterp16(register const cmsUInt16Number Input[], register cmsUInt16Number Output[], register const cmsInterpParams* p) @@ -352,7 +387,7 @@ void BilinearInterp16(register const cmsUInt16Number Input[], #define DENS(i,j) (LutTable[(i)+(j)+OutChan]) #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; int OutChan, TotalOut; cmsS15Fixed16Number fx, fy; register int rx, ry; @@ -379,7 +414,7 @@ void BilinearInterp16(register const cmsUInt16Number Input[], Y0 = p -> opta[0] * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]); - + for (OutChan = 0; OutChan < TotalOut; OutChan++) { d00 = DENS(X0, Y0); @@ -403,15 +438,15 @@ void BilinearInterp16(register const cmsUInt16Number Input[], // Trilinear interpolation (16 bits) - cmsFloat32Number version static -void TrilinearInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void TrilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) { # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) # define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; cmsFloat32Number px, py, pz; int x0, y0, z0, X0, Y0, Z0, X1, Y1, Z1; @@ -421,38 +456,27 @@ void TrilinearInterpFloat(const cmsFloat32Number Input[], d100, d101, d110, d111, dx00, dx01, dx10, dx11, dxy0, dxy1, dxyz; - + TotalOut = p -> nOutputs; - + // We need some clipping here - px = Input[0]; - py = Input[1]; - pz = Input[2]; - - if (px < 0) px = 0; - if (px > 1) px = 1; - if (py < 0) py = 0; - if (py > 1) py = 1; - if (pz < 0) pz = 0; - if (pz > 1) pz = 1; - - px *= p->Domain[0]; - py *= p->Domain[1]; - pz *= p->Domain[2]; + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; + pz = fclamp(Input[2]) * p->Domain[2]; x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0; - + X0 = p -> opta[2] * x0; X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]); Y0 = p -> opta[1] * y0; Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); - + Z0 = p -> opta[0] * z0; Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); - + for (OutChan = 0; OutChan < TotalOut; OutChan++) { d000 = DENS(X0, Y0, Z0); @@ -486,7 +510,7 @@ void TrilinearInterpFloat(const cmsFloat32Number Input[], // Trilinear interpolation (16 bits) - optimized version static -void TrilinearInterp16(register const cmsUInt16Number Input[], +void TrilinearInterp16(register const cmsUInt16Number Input[], register cmsUInt16Number Output[], register const cmsInterpParams* p) @@ -494,7 +518,7 @@ void TrilinearInterp16(register const cmsUInt16Number Input[], #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; int OutChan, TotalOut; cmsS15Fixed16Number fx, fy, fz; register int rx, ry, rz; @@ -526,7 +550,7 @@ void TrilinearInterp16(register const cmsUInt16Number Input[], Y0 = p -> opta[1] * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); - + Z0 = p -> opta[0] * z0; Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); @@ -562,14 +586,14 @@ void TrilinearInterp16(register const cmsUInt16Number Input[], } -// Tetrahedral interpolation, using Sakamoto algorithm. +// Tetrahedral interpolation, using Sakamoto algorithm. #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) static -void TetrahedralInterpFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void TetrahedralInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) { - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number px, py, pz; int x0, y0, z0, X0, Y0, Z0, X1, Y1, Z1; @@ -580,20 +604,9 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], TotalOut = p -> nOutputs; // We need some clipping here - px = Input[0]; - py = Input[1]; - pz = Input[2]; - - if (px < 0) px = 0; - if (px > 1) px = 1; - if (py < 0) py = 0; - if (py > 1) py = 1; - if (pz < 0) pz = 0; - if (pz > 1) pz = 1; - - px *= p->Domain[0]; - py *= p->Domain[1]; - pz *= p->Domain[2]; + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; + pz = fclamp(Input[2]) * p->Domain[2]; x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0); y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0); @@ -605,10 +618,10 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], Y0 = p -> opta[1] * y0; Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]); - + Z0 = p -> opta[0] * z0; Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]); - + for (OutChan=0; OutChan < TotalOut; OutChan++) { // These are the 6 Tetrahedral @@ -623,7 +636,7 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], } else - if (rx >= rz && rz >= ry) { + if (rx >= rz && rz >= ry) { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); @@ -635,7 +648,7 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; + c3 = DENS(X0, Y0, Z1) - c0; } else @@ -655,7 +668,7 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], } else - if (rz >= ry && ry >= rx) { + if (rz >= ry && ry >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); @@ -663,7 +676,7 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], } else { - c1 = c2 = c3 = 0; + c1 = c2 = c3 = 0; } Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz; @@ -675,7 +688,6 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) static void TetrahedralInterp16(register const cmsUInt16Number Input[], @@ -683,108 +695,140 @@ void TetrahedralInterp16(register const cmsUInt16Number Input[], register const cmsInterpParams* p) { const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table; - cmsS15Fixed16Number fx, fy, fz; - cmsS15Fixed16Number rx, ry, rz; - int x0, y0, z0; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; - cmsUInt32Number OutChan; - cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; - cmsUInt32Number TotalOut = p -> nOutputs; - + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + cmsUInt32Number TotalOut = p -> nOutputs; - fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); - fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); - fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); - x0 = FIXED_TO_INT(fx); - y0 = FIXED_TO_INT(fy); - z0 = FIXED_TO_INT(fz); + x0 = FIXED_TO_INT(fx); + y0 = FIXED_TO_INT(fy); + z0 = FIXED_TO_INT(fz); - rx = FIXED_REST_TO_INT(fx); - ry = FIXED_REST_TO_INT(fy); - rz = FIXED_REST_TO_INT(fz); + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); X0 = p -> opta[2] * x0; - X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]); Y0 = p -> opta[1] * y0; - Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]); Z0 = p -> opta[0] * z0; - Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]); - // These are the 6 Tetrahedral - for (OutChan=0; OutChan < TotalOut; OutChan++) { + LutTable = &LutTable[X0+Y0+Z0]; - c0 = DENS(X0, Y0, Z0); - - if (rx >= ry && ry >= rz) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (rx >= rz && rz >= ry) { - - c1 = DENS(X1, Y0, Z0) - c0; - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)) + // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16 + // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16 + // at the cost of being off by one at 7fff and 17ffe. + if (rx >= ry) { + if (ry >= rz) { + Y1 += X1; + Z1 += Y1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c3 -= c2; + c2 -= c1; + c1 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); } - else - if (rz >= rx && rx >= ry) { - - c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); - c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else - if (ry >= rx && rx >= rz) { - - c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); - - } - else - if (ry >= rz && rz >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); - - } - else - if (rz >= ry && ry >= rx) { - - c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); - c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; - - } - else { - c1 = c2 = c3 = 0; - } - - Rest = c1 * rx + c2 * ry + c3 * rz; - - Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + } else if (rz >= rx) { + X1 += Z1; + Y1 += X1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c2 -= c1; + c1 -= c3; + c3 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else { + Z1 += X1; + Y1 += Z1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c2 -= c3; + c3 -= c1; + c1 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } + } else { + if (rx >= rz) { + X1 += Y1; + Z1 += X1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c3 -= c1; + c1 -= c2; + c2 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else if (ry >= rz) { + Z1 += Y1; + X1 += Z1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c1 -= c3; + c3 -= c2; + c2 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else { + Y1 += Z1; + X1 += Y1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c1 -= c2; + c2 -= c3; + c3 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } } - } -#undef DENS #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) static -void Eval4Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval4Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; +{ + const cmsUInt16Number* LutTable; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; @@ -793,7 +837,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], int x0, y0, z0; cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; cmsUInt32Number i; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; cmsUInt32Number OutChan; cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; @@ -803,14 +847,14 @@ void Eval4Inputs(register const cmsUInt16Number Input[], fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]); fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]); - k0 = FIXED_TO_INT(fk); + k0 = FIXED_TO_INT(fk); x0 = FIXED_TO_INT(fx); - y0 = FIXED_TO_INT(fy); + y0 = FIXED_TO_INT(fy); z0 = FIXED_TO_INT(fz); rk = FIXED_REST_TO_INT(fk); - rx = FIXED_REST_TO_INT(fx); - ry = FIXED_REST_TO_INT(fy); + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); rz = FIXED_REST_TO_INT(fz); K0 = p16 -> opta[3] * k0; @@ -840,7 +884,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else - if (rx >= rz && rz >= ry) { + if (rx >= rz && rz >= ry) { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); @@ -852,7 +896,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; + c3 = DENS(X0, Y0, Z1) - c0; } else @@ -872,7 +916,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else - if (rz >= ry && ry >= rx) { + if (rz >= ry && ry >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); @@ -880,10 +924,10 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else { - c1 = c2 = c3 = 0; + c1 = c2 = c3 = 0; } - Rest = c1 * rx + c2 * ry + c3 * rz; + Rest = c1 * rx + c2 * ry + c3 * rz; Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); } @@ -904,7 +948,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else - if (rx >= rz && rz >= ry) { + if (rx >= rz && rz >= ry) { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); @@ -916,7 +960,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; + c3 = DENS(X0, Y0, Z1) - c0; } else @@ -936,7 +980,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else - if (rz >= ry && ry >= rx) { + if (rz >= ry && ry >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); @@ -944,10 +988,10 @@ void Eval4Inputs(register const cmsUInt16Number Input[], } else { - c1 = c2 = c3 = 0; + c1 = c2 = c3 = 0; } - Rest = c1 * rx + c2 * ry + c3 * rz; + Rest = c1 * rx + c2 * ry + c3 * rz; Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); } @@ -955,7 +999,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], for (i=0; i < p16 -> nOutputs; i++) { - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); } } #undef DENS @@ -966,11 +1010,11 @@ void Eval4Inputs(register const cmsUInt16Number Input[], static -void Eval4InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void Eval4InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number rest; cmsFloat32Number pk; int k0, K0, K1; @@ -979,9 +1023,8 @@ void Eval4InputsFloat(const cmsFloat32Number Input[], cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - - pk = Input[0] * p->Domain[0]; - k0 = _cmsQuickFloor(pk); + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); rest = pk - (cmsFloat32Number) k0; K0 = p -> opta[3] * k0; @@ -989,7 +1032,7 @@ void Eval4InputsFloat(const cmsFloat32Number Input[], p1 = *p; memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number)); - + T = LutTable + K0; p1.Table = T; @@ -1004,18 +1047,18 @@ void Eval4InputsFloat(const cmsFloat32Number Input[], cmsFloat32Number y0 = Tmp1[i]; cmsFloat32Number y1 = Tmp2[i]; - Output[i] = y0 + (y1 - y0) * rest; + Output[i] = y0 + (y1 - y0) * rest; } } static -void Eval5Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval5Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; @@ -1024,7 +1067,7 @@ void Eval5Inputs(register const cmsUInt16Number Input[], cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); k0 = FIXED_TO_INT(fk); rk = FIXED_REST_TO_INT(fk); @@ -1047,18 +1090,18 @@ void Eval5Inputs(register const cmsUInt16Number Input[], for (i=0; i < p16 -> nOutputs; i++) { - Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); } } static -void Eval5InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void Eval5InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number rest; cmsFloat32Number pk; int k0, K0, K1; @@ -1067,8 +1110,8 @@ void Eval5InputsFloat(const cmsFloat32Number Input[], cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - pk = Input[0] * p->Domain[0]; - k0 = _cmsQuickFloor(pk); + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); rest = pk - (cmsFloat32Number) k0; K0 = p -> opta[4] * k0; @@ -1079,31 +1122,31 @@ void Eval5InputsFloat(const cmsFloat32Number Input[], T = LutTable + K0; p1.Table = T; - + Eval4InputsFloat(Input + 1, Tmp1, &p1); - + T = LutTable + K1; p1.Table = T; Eval4InputsFloat(Input + 1, Tmp2, &p1); - + for (i=0; i < p -> nOutputs; i++) { cmsFloat32Number y0 = Tmp1[i]; cmsFloat32Number y1 = Tmp2[i]; - Output[i] = y0 + (y1 - y0) * rest; + Output[i] = y0 + (y1 - y0) * rest; } } static -void Eval6Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval6Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; @@ -1111,7 +1154,7 @@ void Eval6Inputs(register const cmsUInt16Number Input[], cmsUInt32Number i; cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); k0 = FIXED_TO_INT(fk); rk = FIXED_REST_TO_INT(fk); @@ -1141,11 +1184,11 @@ void Eval6Inputs(register const cmsUInt16Number Input[], static -void Eval6InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void Eval6InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number rest; cmsFloat32Number pk; int k0, K0, K1; @@ -1154,8 +1197,8 @@ void Eval6InputsFloat(const cmsFloat32Number Input[], cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - pk = Input[0] * p->Domain[0]; - k0 = _cmsQuickFloor(pk); + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); rest = pk - (cmsFloat32Number) k0; K0 = p -> opta[5] * k0; @@ -1163,33 +1206,33 @@ void Eval6InputsFloat(const cmsFloat32Number Input[], p1 = *p; memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number)); - + T = LutTable + K0; p1.Table = T; - + Eval5InputsFloat(Input + 1, Tmp1, &p1); - + T = LutTable + K1; p1.Table = T; Eval5InputsFloat(Input + 1, Tmp2, &p1); - + for (i=0; i < p -> nOutputs; i++) { cmsFloat32Number y0 = Tmp1[i]; cmsFloat32Number y1 = Tmp2[i]; - Output[i] = y0 + (y1 - y0) * rest; + Output[i] = y0 + (y1 - y0) * rest; } } static -void Eval7Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval7Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; @@ -1198,7 +1241,7 @@ void Eval7Inputs(register const cmsUInt16Number Input[], cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); k0 = FIXED_TO_INT(fk); rk = FIXED_REST_TO_INT(fk); @@ -1207,8 +1250,8 @@ void Eval7Inputs(register const cmsUInt16Number Input[], K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); - + memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number)); + T = LutTable + K0; p1.Table = T; @@ -1226,11 +1269,11 @@ void Eval7Inputs(register const cmsUInt16Number Input[], static -void Eval7InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void Eval7InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number rest; cmsFloat32Number pk; int k0, K0, K1; @@ -1239,8 +1282,8 @@ void Eval7InputsFloat(const cmsFloat32Number Input[], cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - pk = Input[0] * p->Domain[0]; - k0 = _cmsQuickFloor(pk); + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); rest = pk - (cmsFloat32Number) k0; K0 = p -> opta[6] * k0; @@ -1248,34 +1291,34 @@ void Eval7InputsFloat(const cmsFloat32Number Input[], p1 = *p; memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number)); - + T = LutTable + K0; p1.Table = T; Eval6InputsFloat(Input + 1, Tmp1, &p1); - + T = LutTable + K1; p1.Table = T; - + Eval6InputsFloat(Input + 1, Tmp2, &p1); - - + + for (i=0; i < p -> nOutputs; i++) { cmsFloat32Number y0 = Tmp1[i]; cmsFloat32Number y1 = Tmp2[i]; - Output[i] = y0 + (y1 - y0) * rest; - + Output[i] = y0 + (y1 - y0) * rest; + } } static -void Eval8Inputs(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], +void Eval8Inputs(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], register const cmsInterpParams* p16) -{ - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; @@ -1283,7 +1326,7 @@ void Eval8Inputs(register const cmsUInt16Number Input[], cmsUInt32Number i; cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); k0 = FIXED_TO_INT(fk); rk = FIXED_REST_TO_INT(fk); @@ -1293,7 +1336,7 @@ void Eval8Inputs(register const cmsUInt16Number Input[], p1 = *p16; memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number)); - + T = LutTable + K0; p1.Table = T; @@ -1311,11 +1354,11 @@ void Eval8Inputs(register const cmsUInt16Number Input[], static -void Eval8InputsFloat(const cmsFloat32Number Input[], - cmsFloat32Number Output[], +void Eval8InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], const cmsInterpParams* p) -{ - const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; cmsFloat32Number rest; cmsFloat32Number pk; int k0, K0, K1; @@ -1323,9 +1366,9 @@ void Eval8InputsFloat(const cmsFloat32Number Input[], cmsUInt32Number i; cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; cmsInterpParams p1; - - pk = Input[0] * p->Domain[0]; - k0 = _cmsQuickFloor(pk); + + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); rest = pk - (cmsFloat32Number) k0; K0 = p -> opta[7] * k0; @@ -1338,24 +1381,24 @@ void Eval8InputsFloat(const cmsFloat32Number Input[], p1.Table = T; Eval7InputsFloat(Input + 1, Tmp1, &p1); - + T = LutTable + K1; p1.Table = T; Eval7InputsFloat(Input + 1, Tmp2, &p1); - + for (i=0; i < p -> nOutputs; i++) { cmsFloat32Number y0 = Tmp1[i]; cmsFloat32Number y1 = Tmp2[i]; - Output[i] = y0 + (y1 - y0) * rest; + Output[i] = y0 + (y1 - y0) * rest; } } // The default factory -static +static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags) { @@ -1366,7 +1409,7 @@ cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cm memset(&Interpolation, 0, sizeof(Interpolation)); // Safety check - if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) + if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) return Interpolation; switch (nInputChannels) { @@ -1375,7 +1418,7 @@ cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cm if (nOutputChannels == 1) { - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = LinLerp1Dfloat; else Interpolation.Lerp16 = LinLerp1D; @@ -1384,31 +1427,31 @@ cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cm else { if (IsFloat) - Interpolation.LerpFloat = Eval1InputFloat; + Interpolation.LerpFloat = Eval1InputFloat; else - Interpolation.Lerp16 = Eval1Input; + Interpolation.Lerp16 = Eval1Input; } break; case 2: // Duotone - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = BilinearInterpFloat; else Interpolation.Lerp16 = BilinearInterp16; break; - case 3: // RGB et al + case 3: // RGB et al if (IsTrilinear) { - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = TrilinearInterpFloat; else Interpolation.Lerp16 = TrilinearInterp16; } else { - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = TetrahedralInterpFloat; else { @@ -1417,37 +1460,37 @@ cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cm } break; - case 4: // CMYK lut + case 4: // CMYK lut - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = Eval4InputsFloat; else Interpolation.Lerp16 = Eval4Inputs; break; case 5: // 5 Inks - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = Eval5InputsFloat; else Interpolation.Lerp16 = Eval5Inputs; - break; + break; case 6: // 6 Inks - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = Eval6InputsFloat; else Interpolation.Lerp16 = Eval6Inputs; break; case 7: // 7 inks - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = Eval7InputsFloat; else Interpolation.Lerp16 = Eval7Inputs; break; case 8: // 8 inks - if (IsFloat) + if (IsFloat) Interpolation.LerpFloat = Eval8InputsFloat; else Interpolation.Lerp16 = Eval8Inputs; diff --git a/thirdparty/liblcms2/src/cmsio0.c b/thirdparty/liblcms2/src/cmsio0.c index 589ea6a3..4449acd4 100644 --- a/thirdparty/liblcms2/src/cmsio0.c +++ b/thirdparty/liblcms2/src/cmsio0.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -37,18 +37,18 @@ // NULL IOhandler basically does nothing but keep track on how many bytes have been // written. This is handy when creating profiles, where the file size is needed in the -// header. Then, whole profile is serialized across NULL IOhandler and a second pass +// header. Then, whole profile is serialized across NULL IOhandler and a second pass // writes the bytes to the pertinent IOhandler. -typedef struct { +typedef struct { cmsUInt32Number Pointer; // Points to current location } FILENULL; static cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ +{ FILENULL* ResData = (FILENULL*) iohandler ->stream; - + cmsUInt32Number len = size * count; ResData -> Pointer += len; return count; @@ -61,15 +61,15 @@ cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) { FILENULL* ResData = (FILENULL*) iohandler ->stream; - ResData ->Pointer = offset; - return TRUE; + ResData ->Pointer = offset; + return TRUE; } static cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler) { FILENULL* ResData = (FILENULL*) iohandler ->stream; - return ResData -> Pointer; + return ResData -> Pointer; } static @@ -88,9 +88,9 @@ cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Pt static cmsBool NULLClose(cmsIOHANDLER* iohandler) -{ +{ FILENULL* ResData = (FILENULL*) iohandler ->stream; - + _cmsFree(iohandler ->ContextID, ResData); _cmsFree(iohandler ->ContextID, iohandler); return TRUE; @@ -101,17 +101,17 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) { struct _cms_io_handler* iohandler = NULL; FILENULL* fm = NULL; - + iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler)); if (iohandler == NULL) return NULL; fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL)); if (fm == NULL) goto Error; - + fm ->Pointer = 0; iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; + iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; iohandler ->ReportedSize = 0; iohandler ->PhysicalFile[0] = 0; @@ -124,8 +124,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) return iohandler; -Error: - if (fm) _cmsFree(ContextID, fm); +Error: if (iohandler) _cmsFree(ContextID, iohandler); return NULL; @@ -146,7 +145,7 @@ typedef struct { static cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ +{ FILEMEM* ResData = (FILEMEM*) iohandler ->stream; cmsUInt8Number* Ptr; cmsUInt32Number len = size * count; @@ -160,7 +159,7 @@ cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsU Ptr = ResData -> Block; Ptr += ResData -> Pointer; - memmove(Buffer, Ptr, len); + memmove(Buffer, Ptr, len); ResData -> Pointer += len; return count; @@ -173,12 +172,12 @@ cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset) FILEMEM* ResData = (FILEMEM*) iohandler ->stream; if (offset > ResData ->Size) { - cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); + cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); return FALSE; } - ResData ->Pointer = offset; - return TRUE; + ResData ->Pointer = offset; + return TRUE; } // Tell for memory @@ -187,19 +186,24 @@ cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) { FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - if (ResData == NULL) return 0; - return ResData -> Pointer; + if (ResData == NULL) return 0; + return ResData -> Pointer; } -// Writes data to memory, also keeps used space for further reference. +// Writes data to memory, also keeps used space for further reference. static -cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) +cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) { FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - if (ResData == NULL) return FALSE; // Housekeeping + if (ResData == NULL) return FALSE; // Housekeeping + // Check for available space. Clip. + if (ResData->Pointer + size > ResData->Size) { + size = ResData ->Size - ResData->Pointer; + } + if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing memmove(ResData ->Block + ResData ->Pointer, Ptr, size); @@ -208,23 +212,20 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, co if (ResData ->Pointer > iohandler->UsedSpace) iohandler->UsedSpace = ResData ->Pointer; - - iohandler->UsedSpace += size; - return TRUE; } static cmsBool MemoryClose(struct _cms_io_handler* iohandler) -{ +{ FILEMEM* ResData = (FILEMEM*) iohandler ->stream; if (ResData ->FreeBlockOnClose) { if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block); } - + _cmsFree(iohandler ->ContextID, ResData); _cmsFree(iohandler ->ContextID, iohandler); @@ -232,14 +233,14 @@ cmsBool MemoryClose(struct _cms_io_handler* iohandler) } // Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes -// a copy of the memory block for letting user to free the memory after invoking open profile. In write +// a copy of the memory block for letting user to free the memory after invoking open profile. In write // mode ("w"), Buffere points to the begin of memory block to be written. cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode) { cmsIOHANDLER* iohandler = NULL; FILEMEM* fm = NULL; - _cmsAssert(AccessMode != NULL); + _cmsAssert(AccessMode != NULL); iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -272,14 +273,14 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff iohandler -> ReportedSize = size; break; - case 'w': + case 'w': fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); if (fm == NULL) goto Error; fm ->Block = (cmsUInt8Number*) Buffer; fm ->FreeBlockOnClose = FALSE; fm ->Size = size; - fm ->Pointer = 0; + fm ->Pointer = 0; iohandler -> ReportedSize = 0; break; @@ -289,7 +290,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff } iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; + iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; iohandler ->PhysicalFile[0] = 0; @@ -339,8 +340,8 @@ cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) // Returns file pointer position static cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) -{ - return ftell((FILE*)iohandler ->stream); +{ + return (cmsUInt32Number) ftell((FILE*)iohandler ->stream); } // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error @@ -356,19 +357,21 @@ cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Bu // Closes the file static cmsBool FileClose(cmsIOHANDLER* iohandler) -{ +{ if (fclose((FILE*) iohandler ->stream) != 0) return FALSE; _cmsFree(iohandler ->ContextID, iohandler); return TRUE; } -// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set -// to NULL and no real writting is performed. This only happens in writting access mode +// Create a iohandler for disk based files. cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) { cmsIOHANDLER* iohandler = NULL; FILE* fm = NULL; + _cmsAssert(FileName != NULL); + _cmsAssert(AccessMode != NULL); + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -381,7 +384,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; } - iohandler -> ReportedSize = cmsfilelength(fm); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); break; case 'w': @@ -404,12 +407,9 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; - // Keep track of the original file - if (FileName != NULL) { - - strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); - iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; - } + // Keep track of the original file + strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); + iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; iohandler ->Read = FileRead; iohandler ->Seek = FileSeek; @@ -420,20 +420,20 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha return iohandler; } -// Create a iohandler for stream based files +// Create a iohandler for stream based files cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) { cmsIOHANDLER* iohandler = NULL; - + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = cmsfilelength(Stream); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); iohandler -> PhysicalFile[0] = 0; - + iohandler ->Read = FileRead; iohandler ->Seek = FileSeek; iohandler ->Close = FileClose; @@ -465,19 +465,22 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set it to empty Icc -> TagCount = 0; - // Set default version + // Set default version Icc ->Version = 0x02100000; // Set creation date/time memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + // Return the handle return (cmsHPROFILE) Icc; } cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; if (Icc == NULL) return NULL; return Icc -> ContextID; @@ -487,8 +490,8 @@ cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) // Return the number of tags cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - if (Icc == NULL) return -1; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + if (Icc == NULL) return -1; return Icc->TagCount; } @@ -496,9 +499,9 @@ cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) // Return the tag signature of a given tag number cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available + if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check return Icc ->TagNames[n]; @@ -508,77 +511,107 @@ cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Numb static int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig) { - cmsUInt32Number i; + cmsUInt32Number i; - for (i=0; i < Profile -> TagCount; i++) { + for (i=0; i < Profile -> TagCount; i++) { - if (sig == Profile -> TagNames[i]) - return i; - } + if (sig == Profile -> TagNames[i]) + return i; + } - return -1; + return -1; } // Search for a specific tag in tag dictionary. Returns position or -1 if tag not found. // If followlinks is turned on, then the position of the linked tag is returned int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks) { - int n; - cmsTagSignature LinkedSig; + int n; + cmsTagSignature LinkedSig; - do { + do { - // Search for given tag in ICC profile directory - n = SearchOneTag(Icc, sig); - if (n < 0) - return -1; // Not found + // Search for given tag in ICC profile directory + n = SearchOneTag(Icc, sig); + if (n < 0) + return -1; // Not found - if (!lFollowLinks) - return n; // Found, don't follow links + if (!lFollowLinks) + return n; // Found, don't follow links - // Is this a linked tag? - LinkedSig = Icc ->TagLinked[n]; + // Is this a linked tag? + LinkedSig = Icc ->TagLinked[n]; - // Yes, follow link - if (LinkedSig != (cmsTagSignature) 0) { - sig = LinkedSig; - } + // Yes, follow link + if (LinkedSig != (cmsTagSignature) 0) { + sig = LinkedSig; + } - } while (LinkedSig != (cmsTagSignature) 0); + } while (LinkedSig != (cmsTagSignature) 0); - return n; + return n; +} + +// Deletes a tag entry + +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + Icc ->TagPtrs[i] = NULL; + } + } + + } } -// Create a new tag entry - +// Creates a new tag entry static cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) { - int i; + int i; - // Search for the tag + // Search for the tag i = _cmsSearchTag(Icc, sig, FALSE); - - // Now let's do it easy. If the tag has been already written, that's an error if (i >= 0) { - cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); - return FALSE; + + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; } else { - // New one - + // No, make a new one + if (Icc -> TagCount >= MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); return FALSE; } - *NewPos = Icc ->TagCount; + *NewPos = Icc ->TagCount; Icc -> TagCount++; } - return TRUE; + return TRUE; } @@ -602,25 +635,28 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Read the header - if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { - return FALSE; + if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { + return FALSE; } // Validate file as an ICC profile if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) { cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature"); - return FALSE; + return FALSE; } // Adjust endianess of the used parameters Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); + Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); - _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes); + Icc -> creator = _cmsAdjustEndianess32(Header.creator); + + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); Icc -> Version = _cmsAdjustEndianess32(Header.version); // Get size as reported in header @@ -630,7 +666,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if (HeaderSize >= Icc ->IOhandler ->ReportedSize) HeaderSize = Icc ->IOhandler ->ReportedSize; - + // Get creation date/time _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created); @@ -639,7 +675,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Read tag directory - if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; + if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; if (TagCount > MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount); @@ -657,7 +693,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Perform some sanity check. Offset + size should fall inside file. if (Tag.offset + Tag.size > HeaderSize || - Tag.offset + Tag.size < Tag.offset) + Tag.offset + Tag.size < Tag.offset) continue; Icc -> TagNames[Icc ->TagCount] = Tag.sig; @@ -670,23 +706,23 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if ((Icc ->TagOffsets[j] == Tag.offset) && (Icc ->TagSizes[j] == Tag.size)) { - Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; + Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; } } Icc ->TagCount++; } - + return TRUE; } // Saves profile header cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) { - cmsICCHeader Header; + cmsICCHeader Header; cmsUInt32Number i; - cmsTagEntry Tag; + cmsTagEntry Tag; cmsInt32Number Count = 0; Header.size = _cmsAdjustEndianess32(UsedSpace); @@ -703,17 +739,17 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); #ifdef CMS_IS_WINDOWS_ - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); #else - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); #endif Header.flags = _cmsAdjustEndianess32(Icc -> flags); Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); Header.model = _cmsAdjustEndianess32(Icc -> model); - _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes); - + _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes); + // Rendering intent in the header (for embedded profiles) Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); @@ -727,7 +763,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) memset(&Header.reserved, 0, sizeof(Header.reserved)); - // Set profile ID. Endianess is always big endian + // Set profile ID. Endianess is always big endian memmove(&Header.profileID, &Icc ->ProfileID, 16); // Dump the header @@ -742,7 +778,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) } // Store number of tags - if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; + if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; for (i=0; i < Icc -> TagCount; i++) { @@ -788,28 +824,33 @@ void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->manufacturer; + return Icc ->manufacturer; } void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) manufacturer; + Icc -> manufacturer = manufacturer; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->creator; } cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->model; + return Icc ->model; } void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) model; + Icc -> model = model; } - void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; @@ -824,8 +865,8 @@ void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flag void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(ProfileID, Icc ->ProfileID.ID8, 16); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(ProfileID, Icc ->ProfileID.ID8, 16); } void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) @@ -836,8 +877,8 @@ void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* Profi cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(Dest, &Icc ->Created, sizeof(struct tm)); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Dest, &Icc ->Created, sizeof(struct tm)); return TRUE; } @@ -896,9 +937,9 @@ cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut) char Buff[100]; int i, len; cmsUInt32Number out; - + for (len=0; in > 0 && len < 100; len++) { - + Buff[len] = (char) (in % BaseIn); in /= BaseIn; } @@ -916,7 +957,7 @@ void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Vers // 4.2 -> 0x4200000 - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; } cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) @@ -940,7 +981,7 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIO NewIcc = (_cmsICCPROFILE*) hEmpty; NewIcc ->IOhandler = io; - if (!_cmsReadHeader(NewIcc)) goto Error; + if (!_cmsReadHeader(NewIcc)) goto Error; return hEmpty; Error: @@ -948,6 +989,32 @@ Error: return NULL; } +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (write) { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + // Create profile from disk file cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) { @@ -964,7 +1031,7 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char if (*sAccess == 'W' || *sAccess == 'w') { NewIcc -> IsWrite = TRUE; - + return hEmpty; } @@ -997,11 +1064,11 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* I if (*sAccess == 'w') { - NewIcc -> IsWrite = TRUE; + NewIcc -> IsWrite = TRUE; return hEmpty; } - if (!_cmsReadHeader(NewIcc)) goto Error; + if (!_cmsReadHeader(NewIcc)) goto Error; return hEmpty; Error: @@ -1027,8 +1094,8 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* NewIcc = (_cmsICCPROFILE*) hEmpty; - // Ok, in this case const void* is casted to void* just because open IO handler - // shares read and writting modes. Don't abuse this feature! + // Ok, in this case const void* is casted to void* just because open IO handler + // shares read and writting modes. Don't abuse this feature! NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r"); if (NewIcc ->IOhandler == NULL) goto Error; @@ -1058,12 +1125,13 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) cmsIOHANDLER* io = Icc ->IOhandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature TypeBase; + cmsTagTypeSignature Type; cmsTagTypeHandler* TypeHandler; - + cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc); + cmsTagTypeHandler LocalTypeHandler; for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] == 0) continue; // Linked tags are not written @@ -1075,7 +1143,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) if (!Data) { - // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. // In this case a blind copy of the block data is performed if (FileOrig != NULL && Icc -> TagOffsets[i]) { @@ -1085,7 +1153,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE; - Mem = _cmsMalloc(Icc ->ContextID, TagSize); + Mem = _cmsMalloc(Icc ->ContextID, TagSize); if (Mem == NULL) return FALSE; if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE; @@ -1093,11 +1161,11 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) _cmsFree(Icc ->ContextID, Mem); Icc -> TagSizes[i] = (io ->UsedSpace - Begin); - + // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; + if (! _cmsWriteAlignment(io)) + return FALSE; } continue; @@ -1112,38 +1180,48 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) else { // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it + + if (TagDescriptor ->DecideType != NULL) { - TypeHandler = Icc ->TagTypeHandlers[i]; + Type = TagDescriptor ->DecideType(Version, Data); + } + else { + + Type = TagDescriptor ->SupportedTypes[0]; + } + + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); continue; } - TypeBase = TypeHandler ->Signature; - if (!_cmsWriteTypeBase(io, TypeBase)) + TypeBase = TypeHandler ->Signature; + if (!_cmsWriteTypeBase(io, TypeBase)) return FALSE; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) { - char String[5]; + char String[5]; - _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); + _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String); - return FALSE; + return FALSE; } } - Icc -> TagSizes[i] = (io ->UsedSpace - Begin); + Icc -> TagSizes[i] = (io ->UsedSpace - Begin); // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; + if (! _cmsWriteAlignment(io)) + return FALSE; } @@ -1181,11 +1259,13 @@ cmsBool SetLinks( _cmsICCPROFILE* Icc) cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO; + _cmsICCPROFILE Keep; + cmsIOHANDLER* PrevIO = NULL; cmsUInt32Number UsedSpace; cmsContext ContextID; + _cmsAssert(hProfile != NULL); + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); ContextID = cmsGetProfileContextID(hProfile); @@ -1194,18 +1274,19 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH // Pass #1 does compute offsets - if (!_cmsWriteHeader(Icc, 0)) return 0; - if (!SaveTags(Icc, &Keep)) return 0; + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; UsedSpace = PrevIO ->UsedSpace; // Pass #2 does save to iohandler if (io != NULL) { - Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto CleanUp; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; - if (!SaveTags(Icc, &Keep)) goto CleanUp; + + Icc ->IOhandler = io; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -1214,20 +1295,20 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH return UsedSpace; -CleanUp: - cmsCloseIOhandler(PrevIO); +Error: + cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return 0; } -// Low-level save to disk. +// Low-level save to disk. cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) -{ +{ cmsContext ContextID = cmsGetProfileContextID(hProfile); cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w"); cmsBool rc; - + if (io == NULL) return FALSE; rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); @@ -1245,7 +1326,7 @@ cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream) cmsBool rc; cmsContext ContextID = cmsGetProfileContextID(hProfile); cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream); - + if (io == NULL) return FALSE; rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); @@ -1261,12 +1342,14 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn cmsBool rc; cmsIOHANDLER* io; cmsContext ContextID = cmsGetProfileContextID(hProfile); - + + _cmsAssert(BytesNeeded != NULL); + // Should we just calculate the needed space? - if (MemPtr == NULL) { + if (MemPtr == NULL) { *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return TRUE; + return (*BytesNeeded == 0) ? FALSE : TRUE; } // That is a real write operation @@ -1286,15 +1369,15 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsBool rc = TRUE; - cmsUInt32Number i; + cmsUInt32Number i; if (!Icc) return FALSE; - // Was open in write mode? + // Was open in write mode? if (Icc ->IsWrite) { Icc ->IsWrite = FALSE; // Assure no further writting - rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); + rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); } for (i=0; i < Icc -> TagCount; i++) { @@ -1304,19 +1387,22 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; if (TypeHandler != NULL) { + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); } else _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); } } - if (Icc ->IOhandler != NULL) { - rc &= cmsCloseIOhandler(Icc->IOhandler); - } + if (Icc ->IOhandler != NULL) { + rc &= cmsCloseIOhandler(Icc->IOhandler); + } + + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory @@ -1336,9 +1422,9 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ nMaxTypes = TagDescriptor->nSupportedTypes; if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN) nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN; - + for (i=0; i < nMaxTypes; i++) { - if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; + if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; } return FALSE; @@ -1348,58 +1434,72 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ // That's the main read function void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsIOHANDLER* io = Icc ->IOhandler; cmsTagTypeHandler* TypeHandler; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature BaseType; cmsUInt32Number Offset, TagSize; cmsUInt32Number ElemCount; int n; - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return NULL; // Not found, return NULL + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) goto Error; // Not found, return NULL + // If the element is already in memory, return the pointer + if (Icc -> TagPtrs[n]) { - // If the element is already in memory, return the pointer - if (Icc -> TagPtrs[n]) { + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked - if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked - return Icc -> TagPtrs[n]; - } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc -> TagPtrs[n]; + } - // We need to read it. Get the offset and size to the file + // We need to read it. Get the offset and size to the file Offset = Icc -> TagOffsets[n]; - TagSize = Icc -> TagSizes[n]; - + TagSize = Icc -> TagSizes[n]; + // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + goto Error; // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(sig); - if (TagDescriptor == NULL) return NULL; // Unsupported. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } // if supported, get type and check if in list BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) return NULL; + if (BaseType == 0) goto Error; - if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; TagSize -= 8; // Alredy read by the type base logic // Get type handler - TypeHandler = _cmsGetTagTypeHandler(BaseType); - if (TypeHandler == NULL) return NULL; + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; + LocalTypeHandler = *TypeHandler; // Read the tag Icc -> TagTypeHandlers[n] = TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); // The tag type is supported, but something wrong happend and we cannot read the tag. // let know the user about this (although it is just a warning) @@ -1409,40 +1509,47 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - return NULL; + goto Error; } // This is a weird error that may be a symptom of something more serious, the number of - // stored item is actually less than the number of required elements. + // stored item is actually less than the number of required elements. if (ElemCount < TagDescriptor ->ElemCount) { char String[5]; _cmsTagSignature2String(String, sig); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", - String, TagDescriptor ->ElemCount, ElemCount); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", + String, TagDescriptor ->ElemCount, ElemCount); } - + // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; } // Get true type of data cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsTagTypeHandler* TypeHandler; - int n; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler; + int n; - // Search for given tag in ICC profile directory - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL + // Search for given tag in ICC profile directory + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL - // Get the handler. The true type is there - TypeHandler = Icc -> TagTypeHandlers[n]; - return TypeHandler ->Signature; + // Get the handler. The true type is there + TypeHandler = Icc -> TagTypeHandlers[n]; + return TypeHandler ->Signature; } @@ -1450,53 +1557,35 @@ cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig // in that list, the previous version is deleted. cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsTagTypeSignature Type; int i; cmsFloat64Number Version; char TypeString[5], SigString[5]; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + // To delete tags. if (data == NULL) { - cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag"); - return FALSE; + // Delete the tag + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); + Icc ->TagNames[i] = (cmsTagSignature) 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; } - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >=0) { - - if (Icc -> TagPtrs[i] != NULL) { - - // Already exists. Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); - } - } - } - } - else { - // New one - i = Icc -> TagCount; - - if (i >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - Icc -> TagCount++; - } + if (!_cmsNewTag(Icc, sig, &i)) goto Error; // This is not raw Icc ->TagSaveAsRaw[i] = FALSE; @@ -1504,51 +1593,50 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v // This is not a link Icc ->TagLinked[i] = (cmsTagSignature) 0; - // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(sig); + // Get information about the TAG. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL){ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - return FALSE; + goto Error; } - - // Now we need to know which type to use. It depends on the version. + + // Now we need to know which type to use. It depends on the version. Version = cmsGetProfileVersion(hProfile); if (TagDescriptor ->DecideType != NULL) { // Let the tag descriptor to decide the type base on depending on - // the data. This is useful for example on parametric curves, where + // the data. This is useful for example on parametric curves, where // curves specified by a table cannot be saved as parametric and needs - // to be revented to single v2-curves, even on v4 profiles. + // to be casted to single v2-curves, even on v4 profiles. Type = TagDescriptor ->DecideType(Version, data); } else { - Type = TagDescriptor ->SupportedTypes[0]; } // Does the tag support this type? if (!IsTypeSupported(TagDescriptor, Type)) { - + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; // Should never happen + goto Error; // Should never happen } @@ -1558,23 +1646,30 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - - return FALSE; + + goto Error; } - + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } -// Read and write raw data. The only way those function would work and keep consistence with normal read and write +// Read and write raw data. The only way those function would work and keep consistence with normal read and write // is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained // data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where // raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows @@ -1582,96 +1677,136 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - void *Object; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + void *Object; int i; cmsIOHANDLER* MemIO; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; - // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) return 0; // Not found, return 0 + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; - // It is already read? + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, TRUE); + if (i < 0) goto Error; // Not found, + + // It is already read? if (Icc -> TagPtrs[i] == NULL) { // No yet, get original position Offset = Icc ->TagOffsets[i]; TagSize = Icc ->TagSizes[i]; - // read the data directly, don't keep copy - if (data != NULL) { + if (data != NULL) { - if (BufferSize < TagSize) - TagSize = BufferSize; + if (BufferSize < TagSize) + TagSize = BufferSize; - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; - } + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } // The data has been already read, or written. But wait!, maybe the user choosed to save as // raw data. In this case, return the raw data directly if (Icc ->TagSaveAsRaw[i]) { - - if (data != NULL) { - TagSize = Icc ->TagSizes[i]; - if (BufferSize < TagSize) - TagSize = BufferSize; + if (data != NULL) { + + TagSize = Icc ->TagSizes[i]; + if (BufferSize < TagSize) + TagSize = BufferSize; memmove(data, Icc ->TagPtrs[i], TagSize); - } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } - // Already readed, or previously set by cmsWriteTag(). We need to serialize that + // Already readed, or previously set by cmsWriteTag(). We need to serialize that // data to raw in order to maintain consistency. + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); Object = cmsReadTag(hProfile, sig); - if (Object == NULL) return 0; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (Object == NULL) goto Error; // Now we need to serialize to a memory block: just use a memory iohandler - if (data == NULL) { - MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); - } else{ - MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); - } - if (MemIO == NULL) return 0; + if (data == NULL) { + MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); + } else{ + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + } + if (MemIO == NULL) goto Error; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (TypeHandler == NULL) goto Error; // Serialize - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0; + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + + if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { + cmsCloseIOhandler(MemIO); + goto Error; + } // Get Size and close rc = MemIO ->Tell(MemIO); cmsCloseIOhandler(MemIO); // Ignore return code this time + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; } // Similar to the anterior. This function allows to write directly to the ICC profile any data, without -// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading +// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading // it as cooked without serializing does result into an error. If that is wha you want, you will need to dump // the profile to memry or disk and then reopen it. cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Mark the tag as being written as RAW Icc ->TagSaveAsRaw[i] = TRUE; @@ -1682,26 +1817,33 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); Icc ->TagSizes[i] = Size; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } // Using this function you can collapse several tag entries to the same block in the profile cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Keep necessary information Icc ->TagSaveAsRaw[i] = FALSE; Icc ->TagNames[i] = sig; Icc ->TagLinked[i] = dest; - + Icc ->TagPtrs[i] = NULL; Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } @@ -1709,12 +1851,12 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi // Returns the tag linked to sig, in the case two tags are sharing same resource cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, FALSE); - if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 + i = _cmsSearchTag(Icc, sig, FALSE); + if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 return Icc -> TagLinked[i]; } diff --git a/thirdparty/liblcms2/src/cmsio1.c b/thirdparty/liblcms2/src/cmsio1.c index c93eaa80..89856e57 100644 --- a/thirdparty/liblcms2/src/cmsio1.c +++ b/thirdparty/liblcms2/src/cmsio1.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -56,9 +56,9 @@ static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Percept // Several resources for gray conversions. static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) }; -static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 }; -static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 }; -static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; +static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 }; +static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 }; +static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; // Get a media white point fixing some issues found in certain old profiles cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) @@ -67,7 +67,7 @@ cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) _cmsAssert(Dest != NULL); - Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); // If no wp, take D50 if (Tag == NULL) { @@ -80,7 +80,7 @@ cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { *Dest = *cmsD50_XYZ(); - return TRUE; + return TRUE; } } @@ -100,7 +100,6 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); if (Tag != NULL) { - *Dest = *Tag; return TRUE; } @@ -113,7 +112,7 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { - cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); if (White == NULL) { @@ -121,7 +120,7 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) return TRUE; } - return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White); + return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ()); } } @@ -141,7 +140,7 @@ cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile) PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag); PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag); - if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL) + if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL) return FALSE; _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X); @@ -159,12 +158,13 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) cmsToneCurve *GrayTRC; cmsPipeline* Lut; cmsContext ContextID = cmsGetProfileContextID(hProfile); - + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); if (GrayTRC == NULL) return NULL; Lut = cmsPipelineAlloc(ContextID, 1, 3); - if (Lut == NULL) return NULL; + if (Lut == NULL) + goto Error; if (cmsGetPCS(hProfile) == cmsSigLabData) { @@ -172,31 +172,38 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) cmsUInt16Number Zero[2] = { 0x8080, 0x8080 }; cmsToneCurve* EmptyTab; cmsToneCurve* LabCurves[3]; - - EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); - if (EmptyTab == NULL) { + EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); - cmsPipelineFree(Lut); - return NULL; - } + if (EmptyTab == NULL) + goto Error; LabCurves[0] = GrayTRC; LabCurves[1] = EmptyTab; LabCurves[2] = EmptyTab; - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves)); - + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves))) { + cmsFreeToneCurve(EmptyTab); + goto Error; + } + cmsFreeToneCurve(EmptyTab); } else { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL)); + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL))) + goto Error; } - + return Lut; + +Error: + cmsFreeToneCurve(GrayTRC); + cmsPipelineFree(Lut); + return NULL; } // RGB Matrix shaper @@ -212,15 +219,15 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL; // XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so - // we need to adjust the output by a factor of (0x10000/0xffff) to put data in + // we need to adjust the output by a factor of (0x10000/0xffff) to put data in // a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2) - + for (i=0; i < 3; i++) for (j=0; j < 3; j++) Mat.v[i].n[j] *= InpAdj; - - Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); @@ -230,15 +237,76 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) Lut = cmsPipelineAlloc(ContextID, 3, 3); if (Lut != NULL) { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL))) + goto Error; + + // Note that it is certainly possible a single profile would have a LUT based + // tag for output working in lab and a matrix-shaper for the fallback cases. + // This is not allowed by the spec, but this code is tolerant to those cases + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID))) + goto Error; + } + } return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; } + + +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + + if (Lut == NULL) return NULL; + + // input and output of transform are in lcms 0..1 encoding. If XYZ or Lab spaces are used, + // these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0) + if ( spc == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else if (spc == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + if ( PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else if( PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + + // Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc -// is adjusted here in order to create a LUT that takes care of all those details +// is adjusted here in order to create a LUT that takes care of all those details. +// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) { cmsTagTypeSignature OriginalType; @@ -246,57 +314,95 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = Device2PCSFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + // On named color, take the appropiate tag + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - // Floating point LUT are always V4, so no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - } + cmsPipeline* Lut; + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = Device2PCS16[0]; - } + if (nc == NULL) return NULL; - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + Lut = cmsPipelineAlloc(ContextID, 0, 0); + if (Lut == NULL) { + cmsFreeNamedColorList(nc); + return NULL; + } - // Check profile version and LUT type. Do the necessary adjustments if needed - - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; - - // After reading it, we have now info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); - - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - - // We need to adjust data only for Lab16 on output - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; - - // Add a matrix for conversion V2 to V4 Lab PCS - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) { + cmsPipelineFree(Lut); + return NULL; + } return Lut; - } + } + + // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no + // matter other LUT are present and have precedence. Intent = -1 means just this. + if (Intent != -1) { + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, but the encoding range is no + // longer 0..1.0, so we need to add an stage depending on the color space + return _cmsReadFloatInputTag(hProfile, tagFloat); + } + + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = Device2PCS16[0]; + } + + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // After reading it, we have now info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + + // We need to adjust data only for Lab16 on output + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // If the input is Lab, add also a conversion at the begin + if (cmsGetColorSpace(hProfile) == cmsSigLabData && + !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + + // Add a matrix for conversion V2 to V4 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; + } + } // Lut was not found, try to create a matrix-shaper // Check if this is a grayscale profile. if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - // if so, build appropiate conversion tables. + // if so, build appropiate conversion tables. // The tables are the PCS iluminant, scaled across GrayTRC - return BuildGrayInputMatrixPipeline(hProfile); + return BuildGrayInputMatrixPipeline(hProfile); } - // Not gray, create a normal matrix-shaper + // Not gray, create a normal matrix-shaper return BuildRGBInputMatrixShaper(hProfile); } // --------------------------------------------------------------------------------------------------------------- -// Gray output pipeline. +// Gray output pipeline. // XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be // given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve. // The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well. @@ -308,7 +414,7 @@ cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) cmsPipeline* Lut; cmsContext ContextID = cmsGetProfileContextID(hProfile); - GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); if (GrayTRC == NULL) return NULL; RevGrayTRC = cmsReverseToneCurve(GrayTRC); @@ -322,21 +428,27 @@ cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL))) + goto Error; } else { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL))) + goto Error; } - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC))) + goto Error; + cmsFreeToneCurve(RevGrayTRC); - return Lut; + +Error: + cmsFreeToneCurve(RevGrayTRC); + cmsPipelineFree(Lut); + return NULL; } - - static cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) { @@ -353,14 +465,14 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) return NULL; // XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so - // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of + // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of // (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0; for (i=0; i < 3; i++) for (j=0; j < 3; j++) Inv.v[i].n[j] *= OutpAdj; - Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); @@ -371,19 +483,33 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) InvShapes[1] = cmsReverseToneCurve(Shapes[1]); InvShapes[2] = cmsReverseToneCurve(Shapes[2]); - if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) { + if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) { return NULL; } Lut = cmsPipelineAlloc(ContextID, 3, 3); if (Lut != NULL) { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)); + // Note that it is certainly possible a single profile would have a LUT based + // tag for output working in lab and a matrix-shaper for the fallback cases. + // This is not allowed by the spec, but this code is tolerant to those cases + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID))) + goto Error; + } + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes))) + goto Error; } cmsFreeToneCurveTriple(InvShapes); return Lut; +Error: + cmsFreeToneCurveTriple(InvShapes); + cmsPipelineFree(Lut); + return NULL; } @@ -402,11 +528,56 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; - _cmsSetInterpolationRoutine(CLUT ->Params); + _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); } } } + +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + cmsColorSpaceSignature dataSpace = cmsGetColorSpace(hProfile); + + if (Lut == NULL) return NULL; + + // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, + // and since the formatter has already accomodated to 0..1.0, we should undo this change + if ( PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else + if (PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline + if ( dataSpace == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else if (dataSpace == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + // Create an output MPE LUT from agiven profile. Version mismatches are handled here cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) { @@ -415,63 +586,118 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4, so no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - } + if (Intent != -1) { - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = PCS2Device16[0]; - } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + // Floating point LUT are always V4 + return _cmsReadFloatOutputTag(hProfile, tagFloat); + } - // Check profile version and LUT type. Do the necessary adjustments if needed + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = PCS2Device16[0]; + } - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + // Check profile version and LUT type. Do the necessary adjustments if needed - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - if (Lut == NULL) return NULL; + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; + + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); + + // We need to adjust data only for Lab and Lut16 type + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // Add a matrix for conversion V4 to V2 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + + // If the output is Lab, add also a conversion at the end + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; - // We need to adjust data only for Lab and Lut16 type - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) return Lut; - - // Add a matrix for conversion V4 to V2 Lab PCS - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); - return Lut; - } +Error: + cmsPipelineFree(Lut); + return NULL; + } + } // Lut not found, try to create a matrix-shaper // Check if this is a grayscale profile. - if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - // if so, build appropiate conversion tables. - // The tables are the PCS iluminant, scaled across GrayTRC - return BuildGrayOutputPipeline(hProfile); + // if so, build appropiate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayOutputPipeline(hProfile); } - // Not gray, create a normal matrix-shaper + // Not gray, create a normal matrix-shaper, which only operates in XYZ space return BuildRGBOutputMatrixShaper(hProfile); } // --------------------------------------------------------------------------------------------------------------- -// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The +// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); + + if (Lut == NULL) return NULL; + + if (spc == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else + if (spc == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + if (PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else + if (PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; +} + +// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The // tag name here may default to AToB0 cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) { @@ -481,22 +707,48 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = Device2PCSFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // On named color, take the appropiate tag + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); + + if (nc == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 0, 0); + if (Lut == NULL) + goto Error; + + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE))) + goto Error; + + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; +Error: + cmsPipelineFree(Lut); + cmsFreeNamedColorList(nc); + return NULL; + } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4, no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + // Floating point LUT are always V + return _cmsReadFloatDevicelinkTag(hProfile, tagFloat); } tagFloat = Device2PCSFloat[0]; - if (cmsIsTag(hProfile, tagFloat)) { - + if (cmsIsTag(hProfile, tagFloat)) { + return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); } if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - + tag16 = Device2PCS16[0]; - if (!cmsIsTag(hProfile, tag16)) return NULL; + if (!cmsIsTag(hProfile, tag16)) return NULL; } // Check profile version and LUT type. Do the necessary adjustments if needed @@ -509,41 +761,45 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) Lut = cmsPipelineDup(Lut); if (Lut == NULL) return NULL; - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type OriginalType = _cmsGetTagTrueType(hProfile, tag16); // We need to adjust data for Lab16 on output if (OriginalType != cmsSigLut16Type) return Lut; - + // Here it is possible to get Lab on both sides - if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + if (cmsGetColorSpace(hProfile) == cmsSigLabData) { + if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error2; } - if (cmsGetColorSpace(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (cmsGetPCS(hProfile) == cmsSigLabData) { + if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error2; } return Lut; - +Error2: + cmsPipelineFree(Lut); + return NULL; } // --------------------------------------------------------------------------------------------------------------- // Returns TRUE if the profile is implemented as matrix-shaper cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) -{ +{ switch (cmsGetColorSpace(hProfile)) { case cmsSigGrayData: - + return cmsIsTag(hProfile, cmsSigGrayTRCTag); case cmsSigRgbData: @@ -563,7 +819,7 @@ cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) // Returns TRUE if the intent is implemented as CLUT cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) -{ +{ const cmsTagSignature* TagTable; // For devicelinks, the supported intent is that one stated in the header @@ -574,10 +830,10 @@ cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUI switch (UsedDirection) { case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break; - case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break; + case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break; // For proofing, we need rel. colorimetric in output. Let's do some recursion - case LCMS_USED_AS_PROOF: + case LCMS_USED_AS_PROOF: return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) && cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT); @@ -611,7 +867,6 @@ cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, // Read both, profile sequence description and profile sequence id if present. Then combine both to // create qa unique structure holding both. Shame on ICC to store things in such complicated way. - cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) { cmsSEQ* ProfileSeq; @@ -621,7 +876,7 @@ cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) // Take profile sequence description first ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag); - + // Take profile sequence ID ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag); @@ -630,18 +885,19 @@ cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId); if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq); - // We have to mix both together. For that they must agree + // We have to mix both together. For that they must agree if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq); NewSeq = cmsDupProfileSequenceDescription(ProfileSeq); - - // Ok, proceed to the mixing - for (i=0; i < ProfileSeq ->n; i++) { - - memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); - NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); - } + // Ok, proceed to the mixing + if (NewSeq != NULL) { + for (i=0; i < ProfileSeq ->n; i++) { + + memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); + } + } return NewSeq; } @@ -682,22 +938,22 @@ cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfil cmsPSEQDESC* ps = &seq ->seq[i]; cmsHPROFILE h = hProfiles[i]; cmsTechnologySignature* techpt; - + cmsGetHeaderAttributes(h, &ps ->attributes); - cmsGetHeaderProfileID(h, ps ->ProfileID.ID8); + cmsGetHeaderProfileID(h, ps ->ProfileID.ID8); ps ->deviceMfg = cmsGetHeaderManufacturer(h); ps ->deviceModel = cmsGetHeaderModel(h); - + techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag); if (techpt == NULL) ps ->technology = (cmsTechnologySignature) 0; else ps ->technology = *techpt; - + ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag); - ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag); + ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag); ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag); - + } return seq; @@ -714,7 +970,7 @@ const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info) switch (Info) { case cmsInfoDescription: - sig = cmsSigProfileDescriptionTag; + sig = cmsSigProfileDescriptionTag; break; case cmsInfoManufacturer: @@ -738,8 +994,8 @@ const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info) -cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, - const char LanguageCode[3], const char CountryCode[3], +cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], wchar_t* Buffer, cmsUInt32Number BufferSize) { const cmsMLU* mlu = GetInfo(hProfile, Info); @@ -749,8 +1005,8 @@ cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType In } -cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, - const char LanguageCode[3], const char CountryCode[3], +cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], char* Buffer, cmsUInt32Number BufferSize) { const cmsMLU* mlu = GetInfo(hProfile, Info); diff --git a/thirdparty/liblcms2/src/cmslut.c b/thirdparty/liblcms2/src/cmslut.c index d0fe9c80..c491662b 100644 --- a/thirdparty/liblcms2/src/cmslut.c +++ b/thirdparty/liblcms2/src/cmslut.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -28,20 +28,20 @@ // Allocates an empty multi profile element -cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, +cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, cmsStageSignature Type, - cmsUInt32Number InputChannels, + cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels, - _cmsStageEvalFn EvalPtr, - _cmsStageDupElemFn DupElemPtr, - _cmsStageFreeElemFn FreePtr, - void* Data) + _cmsStageEvalFn EvalPtr, + _cmsStageDupElemFn DupElemPtr, + _cmsStageFreeElemFn FreePtr, + void* Data) { cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); if (ph == NULL) return NULL; - - + + ph ->ContextID = ContextID; ph ->Type = Type; @@ -49,18 +49,18 @@ cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, ph ->InputChannels = InputChannels; ph ->OutputChannels = OutputChannels; - ph ->EvalPtr = EvalPtr; - ph ->DupElemPtr = DupElemPtr; - ph ->FreePtr = FreePtr; + ph ->EvalPtr = EvalPtr; + ph ->DupElemPtr = DupElemPtr; + ph ->FreePtr = FreePtr; ph ->Data = Data; - return ph; + return ph; } static -void EvaluateIdentity(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateIdentity(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); @@ -69,10 +69,10 @@ void EvaluateIdentity(const cmsFloat32Number In[], cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) { - return _cmsStageAllocPlaceholder(ContextID, - cmsSigIdentityElemType, + return _cmsStageAllocPlaceholder(ContextID, + cmsSigIdentityElemType, nChannels, nChannels, - EvaluateIdentity, + EvaluateIdentity, NULL, NULL, NULL); @@ -84,8 +84,8 @@ void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32 { cmsUInt32Number i; - for (i=0; i < n; i++) { - Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); + for (i=0; i < n; i++) { + Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); } } @@ -105,7 +105,7 @@ void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32 // that conform the LUT. It should be called with the LUT, the number of expected elements and // then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If // the function founds a match with current pipeline, it fills the pointers and returns TRUE -// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass +// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass // the storage process. cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) { @@ -125,11 +125,11 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms for (i=0; i < n; i++) { // Get asked type - Type = va_arg(args, cmsStageSignature); + Type = (cmsStageSignature)va_arg(args, cmsStageSignature); if (mpe ->Type != Type) { va_end(args); // Mismatch. We are done. - return FALSE; + return FALSE; } mpe = mpe ->Next; } @@ -138,14 +138,14 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms mpe = Lut ->Elements; for (i=0; i < n; i++) { - ElemPtr = va_arg(args, void**); - if (ElemPtr != NULL) + ElemPtr = va_arg(args, void**); + if (ElemPtr != NULL) *ElemPtr = mpe; mpe = mpe ->Next; } - va_end(args); + va_end(args); return TRUE; } @@ -164,8 +164,8 @@ cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) } static -void EvaluateCurves(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateCurves(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { _cmsStageToneCurvesData* Data; @@ -196,7 +196,7 @@ void CurveSetElemTypeFree(cmsStage* mpe) if (Data ->TheCurves != NULL) { for (i=0; i < Data ->nCurves; i++) { - if (Data ->TheCurves[i] != NULL) + if (Data ->TheCurves[i] != NULL) cmsFreeToneCurve(Data ->TheCurves[i]); } } @@ -232,13 +232,13 @@ void* CurveSetDup(cmsStage* mpe) Error: - if (NewElem ->TheCurves != NULL) { + if (NewElem ->TheCurves != NULL) { for (i=0; i < NewElem ->nCurves; i++) { if (NewElem ->TheCurves[i]) - cmsFreeToneCurve(Data ->TheCurves[i]); + cmsFreeToneCurve(NewElem ->TheCurves[i]); } } - _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, NewElem ->TheCurves); _cmsFree(mpe ->ContextID, NewElem); return NULL; } @@ -250,15 +250,15 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe cmsUInt32Number i; _cmsStageToneCurvesData* NewElem; cmsStage* NewMPE; - - + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData)); + NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); if (NewElem == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } @@ -267,7 +267,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe NewElem ->nCurves = nChannels; NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); if (NewElem ->TheCurves == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } @@ -281,12 +281,13 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe } if (NewElem ->TheCurves[i] == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } + } - return NewMPE; + return NewMPE; } @@ -294,7 +295,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) { cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); - + if (mpe == NULL) return NULL; mpe ->Implements = cmsSigIdentityElemType; return mpe; @@ -308,8 +309,8 @@ cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) // Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used static -void EvaluateMatrix(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateMatrix(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { cmsUInt32Number i, j; @@ -324,10 +325,10 @@ void EvaluateMatrix(const cmsFloat32Number In[], Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; } - if (Data ->Offset != NULL) + if (Data ->Offset != NULL) Tmp += Data->Offset[i]; - Out[i] = (cmsFloat32Number) Tmp; + Out[i] = (cmsFloat32Number) Tmp; } @@ -342,7 +343,7 @@ void* MatrixElemDup(cmsStage* mpe) _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; _cmsStageMatrixData* NewElem; cmsUInt32Number sz; - + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); if (NewElem == NULL) return NULL; @@ -351,7 +352,7 @@ void* MatrixElemDup(cmsStage* mpe) NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; if (Data ->Offset) - NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, + NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; return (void*) NewElem; @@ -362,6 +363,8 @@ static void MatrixElemTypeFree(cmsStage* mpe) { _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + if (Data == NULL) + return; if (Data ->Double) _cmsFree(mpe ->ContextID, Data ->Double); @@ -373,7 +376,7 @@ void MatrixElemTypeFree(cmsStage* mpe) -cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, +cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) { cmsUInt32Number i, n; @@ -392,10 +395,10 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); if (NewElem == NULL) return NULL; - + NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); @@ -410,7 +413,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R if (Offset != NULL) { - + NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); if (NewElem->Offset == NULL) { MatrixElemTypeFree(NewMPE); @@ -422,7 +425,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R } } - + NewMPE ->Data = (void*) NewElem; return NewMPE; } @@ -437,7 +440,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R static void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) { - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); } @@ -449,11 +452,11 @@ void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; - + _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); - FromFloatTo16(In, In16, mpe ->InputChannels); + FromFloatTo16(In, In16, mpe ->InputChannels); Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); From16ToFloat(Out16, Out, mpe ->OutputChannels); } @@ -486,8 +489,8 @@ void* CLUTElemDup(cmsStage* mpe) { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; _cmsStageCLutData* NewElem; - - + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) return NULL; @@ -496,20 +499,31 @@ void* CLUTElemDup(cmsStage* mpe) if (Data ->Tab.T) { - if (Data ->HasFloatValues) + if (Data ->HasFloatValues) { NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); - else + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } else { NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } } - + NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, - Data ->Params ->nSamples, + Data ->Params ->nSamples, Data ->Params ->nInputs, - Data ->Params ->nOutputs, + Data ->Params ->nOutputs, NewElem ->Tab.T, Data ->Params ->dwFlags); - - return (void*) NewElem; + if (NewElem->Params != NULL) + return (void*) NewElem; + Error: + if (NewElem->Tab.T) + // This works for both types + _cmsFree(mpe ->ContextID, NewElem -> Tab.T); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; } @@ -518,7 +532,7 @@ void CLutElemTypeFree(cmsStage* mpe) { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - + // Already empty if (Data == NULL) return; @@ -526,29 +540,36 @@ void CLutElemTypeFree(cmsStage* mpe) if (Data -> Tab.T) _cmsFree(mpe ->ContextID, Data -> Tab.T); - _cmsFreeInterpParams(Data ->Params); + _cmsFreeInterpParams(Data ->Params); _cmsFree(mpe ->ContextID, mpe ->Data); } // Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different // granularity on each dimension. -cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, - const cmsUInt32Number clutPoints[], - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, + const cmsUInt32Number clutPoints[], + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsUInt16Number* Table) { cmsUInt32Number i, n; _cmsStageCLutData* NewElem; cmsStage* NewMPE; - + + _cmsAssert(clutPoints != NULL); + + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) { cmsStageFree(NewMPE); return NULL; @@ -586,10 +607,10 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, return NewMPE; } -cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsUInt16Number* Table) { cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; @@ -599,15 +620,14 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nGridPoints; - return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); } -cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsFloat32Number* Table) { cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; @@ -627,15 +647,20 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c cmsUInt32Number i, n; _cmsStageCLutData* NewElem; cmsStage* NewMPE; - + _cmsAssert(clutPoints != NULL); + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); if (NewMPE == NULL) return NULL; - - NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) { cmsStageFree(NewMPE); return NULL; @@ -644,7 +669,7 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c NewMPE ->Data = (void*) NewElem; // There is a potential integer overflow on conputing n and nEntries. - NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan); + NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); NewElem -> HasFloatValues = TRUE; if (n == 0) { @@ -664,16 +689,12 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c } } - - NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); if (NewElem ->Params == NULL) { cmsStageFree(NewMPE); return NULL; } - - return NewMPE; } @@ -684,7 +705,7 @@ int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Numbe int nChan = *(int*) Cargo; int i; - for (i=0; i < nChan; i++) + for (i=0; i < nChan; i++) Out[i] = In[i]; return 1; @@ -696,13 +717,13 @@ cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; cmsStage* mpe ; int i; - + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = 2; mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); if (mpe == NULL) return NULL; - + if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { cmsStageFree(mpe); return NULL; @@ -729,17 +750,24 @@ cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) { int i, t, nTotalPoints, index, rest; - int nInputs, nOutputs; + int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut; + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*) mpe->Data; + + if (clut == NULL) return FALSE; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -755,7 +783,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v rest /= nSamples[t]; - In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); + In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); } if (clut ->Tab.T != NULL) { @@ -786,14 +814,16 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler int i, t, nTotalPoints, index, rest; int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -804,12 +834,12 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler rest = i; for (t = nInputs-1; t >=0; --t) { - + cmsUInt32Number Colorant = rest % nSamples[t]; rest /= nSamples[t]; - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); } if (clut ->Tab.TFloat != NULL) { @@ -857,7 +887,7 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number cmsUInt32Number Colorant = rest % clutPoints[t]; rest /= clutPoints[t]; - In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); + In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); } @@ -887,7 +917,7 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI cmsUInt32Number Colorant = rest % clutPoints[t]; rest /= clutPoints[t]; - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); } @@ -904,8 +934,8 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI static -void EvaluateLab2XYZ(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateLab2XYZ(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { cmsCIELab Lab; @@ -913,18 +943,18 @@ void EvaluateLab2XYZ(const cmsFloat32Number In[], const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; // V4 rules - Lab.L = In[0] * 100.0; + Lab.L = In[0] * 100.0; Lab.a = In[1] * 255.0 - 128.0; Lab.b = In[2] * 255.0 - 128.0; cmsLab2XYZ(NULL, &XYZ, &Lab); - // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff + // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) - Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); - Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); - Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); + Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); + Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); + Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); return; cmsUNUSED_PARAMETER(mpe); @@ -939,9 +969,9 @@ cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) // ******************************************************************************** -// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable +// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable // number of gridpoints that would make exact match. However, a prelinearization -// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. +// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. // Almost all what we need but unfortunately, the rest of entries should be scaled by // (255*257/256) and this is not exact. @@ -956,13 +986,13 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); for (j=0; j < 3; j++) { - + if (LabTable[j] == NULL) { cmsFreeToneCurveTriple(LabTable); return NULL; } - - // We need to map * (0xffff / 0xff00), thats same as (257 / 256) + + // We need to map * (0xffff / 0xff00), thats same as (257 / 256) // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); for (i=0; i < 257; i++) { @@ -975,6 +1005,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); cmsFreeToneCurveTriple(LabTable); + if (mpe == NULL) return NULL; mpe ->Implements = cmsSigLabV2toV4; return mpe; } @@ -985,8 +1016,8 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) { static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, - 0, 65535.0/65280.0, 0, - 0, 0, 65535.0/65280.0 + 0, 65535.0/65280.0, 0, + 0, 0, 65535.0/65280.0 }; cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); @@ -1001,8 +1032,8 @@ cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) { static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, - 0, 65280.0/65535.0, 0, - 0, 0, 65280.0/65535.0 + 0, 65280.0/65535.0, 0, + 0, 0, 65280.0/65535.0 }; cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); @@ -1013,6 +1044,89 @@ cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) } +// To Lab to float. Note that the MPE gives numbers in normal Lab range +// and we need 0..1.0 range for the formatters +// L* : 0...100 => 0...1.0 (L* / 100) +// ab* : -128..+127 to 0..1 ((ab* + 128) / 255) + +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 1.0/100.0, 0, 0, + 0, 1.0/255.0, 0, + 0, 0, 1.0/255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + 128.0/255.0, + 128.0/255.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLab2FloatPCS; + return mpe; +} + +// Fom XYZ to floating point PCS +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) +{ +#define n (32768.0/65535.0) + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigXYZ2FloatPCS; + return mpe; +} + +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 100.0, 0, 0, + 0, 255.0, 0, + 0, 0, 255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + -128.0, + -128.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2Lab; + return mpe; +} + +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) +{ +#define n (65535.0/32768.0) + + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2XYZ; + return mpe; +} + + + // ******************************************************************************** // Type cmsSigXYZ2LabElemType // ******************************************************************************** @@ -1022,20 +1136,20 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const { cmsCIELab Lab; cmsCIEXYZ XYZ; - const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; // From 0..1.0 to XYZ - XYZ.X = In[0] * XYZadj; - XYZ.Y = In[1] * XYZadj; + XYZ.X = In[0] * XYZadj; + XYZ.Y = In[1] * XYZadj; XYZ.Z = In[2] * XYZadj; cmsXYZ2Lab(NULL, &Lab, &XYZ); - + // From V4 Lab to 0..1.0 - Out[0] = (cmsFloat32Number) (Lab.L / 100.0); - Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); + Out[0] = (cmsFloat32Number) (Lab.L / 100.0); + Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); return; @@ -1043,9 +1157,9 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const } cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) -{ +{ return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); - + } // ******************************************************************************** @@ -1065,10 +1179,10 @@ cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) } -// Free a single MPE +// Free a single MPE void CMSEXPORT cmsStageFree(cmsStage* mpe) { - if (mpe ->FreePtr) + if (mpe ->FreePtr) mpe ->FreePtr(mpe); _cmsFree(mpe ->ContextID, mpe); @@ -1105,24 +1219,34 @@ cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) { cmsStage* NewMPE; - + if (mpe == NULL) return NULL; - NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, - mpe ->Type, - mpe ->InputChannels, + NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, + mpe ->Type, + mpe ->InputChannels, mpe ->OutputChannels, mpe ->EvalPtr, mpe ->DupElemPtr, mpe ->FreePtr, NULL); if (NewMPE == NULL) return NULL; - - NewMPE ->Implements = mpe ->Implements; - - if (mpe ->DupElemPtr) - NewMPE ->Data = mpe ->DupElemPtr(mpe); - else + + NewMPE ->Implements = mpe ->Implements; + + if (mpe ->DupElemPtr) { + + NewMPE ->Data = mpe ->DupElemPtr(mpe); + + if (NewMPE->Data == NULL) { + + cmsStageFree(NewMPE); + return NULL; + } + + } else { + NewMPE ->Data = NULL; + } return NewMPE; } @@ -1135,7 +1259,7 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) static void BlessLUT(cmsPipeline* lut) { - // We can set the input/ouput channels only if we have elements. + // We can set the input/ouput channels only if we have elements. if (lut ->Elements != NULL) { cmsStage *First, *Last; @@ -1149,50 +1273,50 @@ void BlessLUT(cmsPipeline* lut) } -// Default to evaluate the LUT on 16 bit-basis. Precision is retained. +// Default to evaluate the LUT on 16 bit-basis. Precision is retained. static void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) { cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; + cmsStage *mpe; cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; int Phase = 0, NextPhase; - + From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { - NextPhase = Phase ^ 1; + NextPhase = Phase ^ 1; mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); Phase = NextPhase; } - + FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); } -// Does evaluate the LUT on cmsFloat32Number-basis. +// Does evaluate the LUT on cmsFloat32Number-basis. static void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) { cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; + cmsStage *mpe; cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; int Phase = 0, NextPhase; - + memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { NextPhase = Phase ^ 1; mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); - Phase = NextPhase; + Phase = NextPhase; } memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); @@ -1221,7 +1345,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In NewLUT ->EvalFloatFn = _LUTevalFloat; NewLUT ->DupDataFn = NULL; NewLUT ->FreeDataFn = NULL; - NewLUT ->Data = NewLUT; + NewLUT ->Data = NewLUT; NewLUT ->ContextID = ContextID; BlessLUT(NewLUT); @@ -1229,30 +1353,37 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In return NewLUT; } +cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + return lut ->ContextID; +} cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) { + _cmsAssert(lut != NULL); return lut ->InputChannels; } cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) { + _cmsAssert(lut != NULL); return lut ->OutputChannels; } // Free a profile elements LUT void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) { - cmsStage *mpe, *Next; + cmsStage *mpe, *Next; if (lut == NULL) return; - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = Next) { Next = mpe ->Next; - cmsStageFree(mpe); + cmsStageFree(mpe); } if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); @@ -1261,16 +1392,18 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) } -// Default to evaluate the LUT on 16 bit-basis. +// Default to evaluate the LUT on 16 bit-basis. void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) { + _cmsAssert(lut != NULL); lut ->Eval16Fn(In, Out, lut->Data); } -// Does evaluate the LUT on cmsFloat32Number-basis. +// Does evaluate the LUT on cmsFloat32Number-basis. void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) { + _cmsAssert(lut != NULL); lut ->EvalFloatFn(In, Out, lut); } @@ -1280,14 +1413,16 @@ void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Numbe cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) { cmsPipeline* NewLUT; - cmsStage *NewMPE, *Anterior = NULL, *mpe; + cmsStage *NewMPE, *Anterior = NULL, *mpe; cmsBool First = TRUE; if (lut == NULL) return NULL; - NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); - for (mpe = lut ->Elements; - mpe != NULL; + NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); + if (NewLUT == NULL) return NULL; + + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { NewMPE = cmsStageDup(mpe); @@ -1296,22 +1431,24 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) cmsPipelineFree(NewLUT); return NULL; } - + if (First) { NewLUT ->Elements = NewMPE; First = FALSE; } else { - Anterior ->Next = NewMPE; + Anterior ->Next = NewMPE; } Anterior = NewMPE; } - NewLUT ->DupDataFn = lut ->DupDataFn; - NewLUT ->FreeDataFn = lut ->FreeDataFn; + NewLUT ->Eval16Fn = lut ->Eval16Fn; + NewLUT ->EvalFloatFn = lut ->EvalFloatFn; + NewLUT ->DupDataFn = lut ->DupDataFn; + NewLUT ->FreeDataFn = lut ->FreeDataFn; - if (NewLUT ->DupDataFn != NULL) + if (NewLUT ->DupDataFn != NULL) NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); @@ -1322,12 +1459,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) } -void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) +int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) { cmsStage* Anterior = NULL, *pt; - _cmsAssert(lut != NULL); - _cmsAssert(mpe != NULL); + if (lut == NULL || mpe == NULL) + return FALSE; switch (loc) { @@ -1338,10 +1475,10 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag case cmsAT_END: - if (lut ->Elements == NULL) + if (lut ->Elements == NULL) lut ->Elements = mpe; else { - + for (pt = lut ->Elements; pt != NULL; pt = pt -> Next) Anterior = pt; @@ -1351,9 +1488,11 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag } break; default:; + return FALSE; } BlessLUT(lut); + return TRUE; } // Unlink an element and return the pointer to it @@ -1362,7 +1501,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag cmsStage *Anterior, *pt, *Last; cmsStage *Unlinked = NULL; - + // If empty LUT, there is nothing to remove if (lut ->Elements == NULL) { if (mpe) *mpe = NULL; @@ -1372,14 +1511,14 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag // On depending on the strategy... switch (loc) { - case cmsAT_BEGIN: + case cmsAT_BEGIN: { cmsStage* elem = lut ->Elements; - + lut ->Elements = elem -> Next; elem ->Next = NULL; Unlinked = elem; - + } break; @@ -1389,21 +1528,21 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag pt != NULL; pt = pt -> Next) { Anterior = Last; - Last = pt; + Last = pt; } Unlinked = Last; // Next already points to NULL // Truncate the chain - if (Anterior) + if (Anterior) Anterior ->Next = NULL; - else + else lut ->Elements = NULL; break; default:; } - if (mpe) + if (mpe) *mpe = Unlinked; else cmsStageFree(Unlinked); @@ -1415,9 +1554,9 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag // Concatenate two LUT into a new single one cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) { - cmsStage* mpe, *NewMPE; + cmsStage* mpe; - // If both LUTS does not have elements, we need to inherit + // If both LUTS does not have elements, we need to inherit // the number of channels if (l1 ->Elements == NULL && l2 ->Elements == NULL) { l1 ->InputChannels = l2 ->InputChannels; @@ -1425,22 +1564,17 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) } // Cat second - for (mpe = l2 ->Elements; - mpe != NULL; + for (mpe = l2 ->Elements; + mpe != NULL; mpe = mpe ->Next) { // We have to dup each element - NewMPE = cmsStageDup(mpe); - - if (NewMPE == NULL) { - return FALSE; - } - - cmsPipelineInsertStage(l1, cmsAT_END, NewMPE); + if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) + return FALSE; } - BlessLUT(l1); - return TRUE; + BlessLUT(l1); + return TRUE; } @@ -1479,58 +1613,58 @@ cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) return n; } -// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional +// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. -void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, - _cmsOPTeval16Fn Eval16, - void* PrivateData, - _cmsOPTfreeDataFn FreePrivateDataFn, - _cmsOPTdupDataFn DupPrivateDataFn) +void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsOPTeval16Fn Eval16, + void* PrivateData, + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn) { Lut ->Eval16Fn = Eval16; Lut ->DupDataFn = DupPrivateDataFn; - Lut ->FreeDataFn = FreePrivateDataFn; + Lut ->FreeDataFn = FreePrivateDataFn; Lut ->Data = PrivateData; } // ----------------------------------------------------------- Reverse interpolation -// Here's how it goes. The derivative Df(x) of the function f is the linear -// transformation that best approximates f near the point x. It can be represented -// by a matrix A whose entries are the partial derivatives of the components of f +// Here's how it goes. The derivative Df(x) of the function f is the linear +// transformation that best approximates f near the point x. It can be represented +// by a matrix A whose entries are the partial derivatives of the components of f // with respect to all the coordinates. This is know as the Jacobian // -// The best linear approximation to f is given by the matrix equation: -// -// y-y0 = A (x-x0) -// -// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this -// linear approximation will give a "better guess" for the zero of f. Thus let y=0, -// and since y0=f(x0) one can solve the above equation for x. This leads to the -// Newton's method formula: +// The best linear approximation to f is given by the matrix equation: // -// xn+1 = xn - A-1 f(xn) -// -// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the -// fashion described above. Iterating this will give better and better approximations -// if you have a "good enough" initial guess. +// y-y0 = A (x-x0) +// +// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this +// linear approximation will give a "better guess" for the zero of f. Thus let y=0, +// and since y0=f(x0) one can solve the above equation for x. This leads to the +// Newton's method formula: +// +// xn+1 = xn - A-1 f(xn) +// +// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the +// fashion described above. Iterating this will give better and better approximations +// if you have a "good enough" initial guess. #define JACOBIAN_EPSILON 0.001f #define INVERSION_MAX_ITERATIONS 30 // Increment with reflexion on boundary -static +static void IncDelta(cmsFloat32Number *Val) { - if (*Val < (1.0 - JACOBIAN_EPSILON)) + if (*Val < (1.0 - JACOBIAN_EPSILON)) *Val += JACOBIAN_EPSILON; - - else + + else *Val -= JACOBIAN_EPSILON; - + } @@ -1554,7 +1688,7 @@ cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], i // Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method // // x1 <- x - [J(x)]^-1 * f(x) -// +// // lut: The LUT on where to do the search // Target: LabK, 3 values of Lab plus destination K which is fixed // Result: The obtained CMYK @@ -1566,20 +1700,15 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], const cmsPipeline* lut) { cmsUInt32Number i, j; - cmsFloat64Number error, LastError = 1E20; + cmsFloat64Number error, LastError = 1E20; cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; cmsVEC3 tmp, tmp2; - cmsMAT3 Jacobian; - cmsFloat64Number LastResult[4]; - - + cmsMAT3 Jacobian; + // Only 3->3 and 4->3 are supported if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; if (lut ->OutputChannels != 3) return FALSE; - - // Mark result of -1 - LastResult[0] = LastResult[1] = LastResult[2] = -1.0f; - + // Take the hint as starting point if specified if (Hint == NULL) { @@ -1589,10 +1718,10 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], else { // Only copy 3 channels from hint... - for (j=0; j < 3; j++) - x[j] = Hint[j]; + for (j=0; j < 3; j++) + x[j] = Hint[j]; } - + // If Lut is 4-dimensions, then grab target[3], which is fixed if (lut ->InputChannels == 4) { x[3] = Target[3]; @@ -1600,7 +1729,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], else x[3] = 0; // To keep lint happy - // Iterate + // Iterate for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { // Get beginning fx @@ -1610,19 +1739,19 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], error = EuclideanDistance(fx, Target, 3); // If not convergent, return last safe value - if (error >= LastError) + if (error >= LastError) break; // Keep latest values LastError = error; - for (j=0; j < lut ->InputChannels; j++) - Result[j] = x[j]; + for (j=0; j < lut ->InputChannels; j++) + Result[j] = x[j]; // Found an exact match? - if (error <= 0) + if (error <= 0) break; - // Obtain slope (the Jacobian) + // Obtain slope (the Jacobian) for (j = 0; j < 3; j++) { xd[0] = x[0]; @@ -1636,7 +1765,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); - Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); + Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); } // Solve system @@ -1663,3 +1792,4 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], return TRUE; } + diff --git a/thirdparty/liblcms2/src/cmsmd5.c b/thirdparty/liblcms2/src/cmsmd5.c index ecf3d907..966730cf 100644 --- a/thirdparty/liblcms2/src/cmsmd5.c +++ b/thirdparty/liblcms2/src/cmsmd5.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -42,7 +42,7 @@ void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs) } #else -#define byteReverse(buf, len) +#define byteReverse(buf, len) #endif @@ -66,7 +66,7 @@ typedef struct { static void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16]) - + { register cmsUInt32Number a, b, c, d; @@ -176,14 +176,14 @@ void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len) { _cmsMD5* ctx = (_cmsMD5*) Handle; cmsUInt32Number t; - + t = ctx->bits[0]; if ((ctx->bits[0] = t + (len << 3)) < t) - ctx->bits[1]++; + ctx->bits[1]++; ctx->bits[1] += len >> 29; - t = (t >> 3) & 0x3f; + t = (t >> 3) & 0x3f; if (t) { @@ -265,15 +265,15 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) cmsUInt8Number* Mem = NULL; cmsHANDLE MD5 = NULL; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - _cmsICCPROFILE Keep; + _cmsICCPROFILE Keep; - _cmsAssert(hProfile != NULL); + _cmsAssert(hProfile != NULL); ContextID = cmsGetProfileContextID(hProfile); // Save a copy of the profile header memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); - + // Set RI, attributes and ID memset(&Icc ->attributes, 0, sizeof(Icc ->attributes)); Icc ->RenderingIntent = 0; @@ -288,7 +288,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) // Save to temporary storage if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error; - + // Create MD5 object MD5 = MD5alloc(ContextID); if (MD5 == NULL) goto Error; @@ -298,7 +298,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) // Temp storage is no longer needed _cmsFree(ContextID, Mem); - + // Restore header memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -309,7 +309,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) Error: // Free resources as something went wrong - if (MD5 != NULL) _cmsFree(ContextID, MD5); + // "MD5" cannot be other than NULL here, so no need to free it if (Mem != NULL) _cmsFree(ContextID, Mem); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return FALSE; diff --git a/thirdparty/liblcms2/src/cmsmtrx.c b/thirdparty/liblcms2/src/cmsmtrx.c index 84035c93..583b1ab2 100644 --- a/thirdparty/liblcms2/src/cmsmtrx.c +++ b/thirdparty/liblcms2/src/cmsmtrx.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -30,7 +30,7 @@ #define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;} -// Initiate a vector +// Initiate a vector void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z) { r -> n[VX] = x; @@ -60,7 +60,7 @@ cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v) return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ]; } -// Euclidean length +// Euclidean length cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a) { return sqrt(a ->n[VX] * a ->n[VX] + @@ -97,16 +97,16 @@ cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a) { - cmsMAT3 Identity; - int i, j; + cmsMAT3 Identity; + int i, j; - _cmsMAT3identity(&Identity); + _cmsMAT3identity(&Identity); - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; - return TRUE; + return TRUE; } diff --git a/thirdparty/liblcms2/src/cmsnamed.c b/thirdparty/liblcms2/src/cmsnamed.c index d1a86b6e..acfd1c8c 100644 --- a/thirdparty/liblcms2/src/cmsnamed.c +++ b/thirdparty/liblcms2/src/cmsnamed.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -32,81 +32,81 @@ // Allocates an empty multi localizad unicode object cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) { - cmsMLU* mlu; + cmsMLU* mlu; - // nItems should be positive if given - if (nItems <= 0) nItems = 2; + // nItems should be positive if given + if (nItems <= 0) nItems = 2; - // Create the container - mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); - if (mlu == NULL) return NULL; + // Create the container + mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); + if (mlu == NULL) return NULL; - mlu ->ContextID = ContextID; + mlu ->ContextID = ContextID; - // Create entry array - mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); - if (mlu ->Entries == NULL) { - _cmsFree(ContextID, mlu); - return NULL; - } + // Create entry array + mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); + if (mlu ->Entries == NULL) { + _cmsFree(ContextID, mlu); + return NULL; + } - // Ok, keep indexes up to date - mlu ->AllocatedEntries = nItems; - mlu ->UsedEntries = 0; + // Ok, keep indexes up to date + mlu ->AllocatedEntries = nItems; + mlu ->UsedEntries = 0; - return mlu; + return mlu; } -// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. +// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. static cmsBool GrowMLUpool(cmsMLU* mlu) { - cmsUInt32Number size; - void *NewPtr; + cmsUInt32Number size; + void *NewPtr; - // Sanity check - if (mlu == NULL) return FALSE; + // Sanity check + if (mlu == NULL) return FALSE; - if (mlu ->PoolSize == 0) - size = 256; - else - size = mlu ->PoolSize * 2; + if (mlu ->PoolSize == 0) + size = 256; + else + size = mlu ->PoolSize * 2; - // Check for overflow - if (size < mlu ->PoolSize) return FALSE; + // Check for overflow + if (size < mlu ->PoolSize) return FALSE; - // Reallocate the pool - NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); - if (NewPtr == NULL) return FALSE; + // Reallocate the pool + NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); + if (NewPtr == NULL) return FALSE; - mlu ->MemPool = NewPtr; - mlu ->PoolSize = size; + mlu ->MemPool = NewPtr; + mlu ->PoolSize = size; - return TRUE; + return TRUE; } -// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two. +// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. static cmsBool GrowMLUtable(cmsMLU* mlu) { int AllocatedEntries; _cmsMLUentry *NewPtr; - - // Sanity check - if (mlu == NULL) return FALSE; + + // Sanity check + if (mlu == NULL) return FALSE; AllocatedEntries = mlu ->AllocatedEntries * 2; - // Check for overflow - if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; + // Check for overflow + if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; - // Reallocate the memory + // Reallocate the memory NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); if (NewPtr == NULL) return FALSE; - + mlu ->Entries = NewPtr; mlu ->AllocatedEntries = AllocatedEntries; @@ -114,37 +114,37 @@ cmsBool GrowMLUtable(cmsMLU* mlu) } -// Search for a specific entry in the structure. Language and Country are used. +// Search for a specific entry in the structure. Language and Country are used. static int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) { int i; - - // Sanity check - if (mlu == NULL) return -1; - // Iterate whole table + // Sanity check + if (mlu == NULL) return -1; + + // Iterate whole table for (i=0; i < mlu ->UsedEntries; i++) { - if (mlu ->Entries[i].Country == CountryCode && + if (mlu ->Entries[i].Country == CountryCode && mlu ->Entries[i].Language == LanguageCode) return i; } - // Not found + // Not found return -1; } -// Add a block of characters to the intended MLU. Language and country are specified. +// Add a block of characters to the intended MLU. Language and country are specified. // Only one entry for Language/country pair is allowed. static -cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, +cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) { cmsUInt32Number Offset; cmsUInt8Number* Ptr; - // Sanity check - if (mlu == NULL) return FALSE; + // Sanity check + if (mlu == NULL) return FALSE; // Is there any room available? if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { @@ -155,20 +155,20 @@ cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! // Check for size - while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { + while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { if (!GrowMLUpool(mlu)) return FALSE; - } + } Offset = mlu ->PoolUsed; - - Ptr = (cmsUInt8Number*) mlu ->MemPool; - if (Ptr == NULL) return FALSE; - // Set the entry + Ptr = (cmsUInt8Number*) mlu ->MemPool; + if (Ptr == NULL) return FALSE; + + // Set the entry memmove(Ptr + Offset, Block, size); mlu ->PoolUsed += size; - + mlu ->Entries[mlu ->UsedEntries].StrW = Offset; mlu ->Entries[mlu ->UsedEntries].Len = size; mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; @@ -179,7 +179,7 @@ cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, } -// Add an ASCII entry. +// Add an ASCII entry. cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) { cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1; @@ -195,21 +195,21 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const for (i=0; i < len; i++) WStr[i] = (wchar_t) ASCIIString[i]; - + rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); _cmsFree(mlu ->ContextID, WStr); return rc; - + } // We don't need any wcs support library -static +static cmsUInt32Number mywcslen(const wchar_t *s) { const wchar_t *p; - p = s; + p = s; while (*p) p++; @@ -223,9 +223,9 @@ cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language); cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country); cmsUInt32Number len; - + if (mlu == NULL) return FALSE; - if (WideString == NULL) return FALSE; + if (WideString == NULL) return FALSE; len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t); return AddMLUBlock(mlu, len, WideString, Lang, Cntry); @@ -234,73 +234,73 @@ cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char // Duplicating a MLU is as easy as copying all members cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu) { - cmsMLU* NewMlu = NULL; + cmsMLU* NewMlu = NULL; - // Duplicating a NULL obtains a NULL - if (mlu == NULL) return NULL; + // Duplicating a NULL obtains a NULL + if (mlu == NULL) return NULL; - NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); - if (NewMlu == NULL) return NULL; + NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); + if (NewMlu == NULL) return NULL; - // Should never happen - if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) - goto Error; + // Should never happen + if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) + goto Error; - // Sanitize... - if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; + // Sanitize... + if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; - memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); - NewMlu ->UsedEntries = mlu ->UsedEntries; + memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); + NewMlu ->UsedEntries = mlu ->UsedEntries; - // The MLU may be empty - if (mlu ->PoolUsed == 0) { - NewMlu ->MemPool = NULL; - } - else { - // It is not empty - NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); - if (NewMlu ->MemPool == NULL) goto Error; - } + // The MLU may be empty + if (mlu ->PoolUsed == 0) { + NewMlu ->MemPool = NULL; + } + else { + // It is not empty + NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); + if (NewMlu ->MemPool == NULL) goto Error; + } - NewMlu ->PoolSize = mlu ->PoolUsed; + NewMlu ->PoolSize = mlu ->PoolUsed; - if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; + if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; - memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); - NewMlu ->PoolUsed = mlu ->PoolUsed; + memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); + NewMlu ->PoolUsed = mlu ->PoolUsed; - return NewMlu; + return NewMlu; Error: - if (NewMlu != NULL) cmsMLUfree(NewMlu); - return NULL; + if (NewMlu != NULL) cmsMLUfree(NewMlu); + return NULL; } // Free any used memory void CMSEXPORT cmsMLUfree(cmsMLU* mlu) { - if (mlu) { + if (mlu) { - if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); - if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); + if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); + if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); - _cmsFree(mlu ->ContextID, mlu); - } + _cmsFree(mlu ->ContextID, mlu); + } } -// The algorithm first searches for an exact match of country and language, if not found it uses +// The algorithm first searches for an exact match of country and language, if not found it uses // the Language. If none is found, first entry is used instead. static -const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, - cmsUInt32Number *len, - cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, - cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) +const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, + cmsUInt32Number *len, + cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, + cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) { int i; int Best = -1; - _cmsMLUentry* v; + _cmsMLUentry* v; if (mlu == NULL) return NULL; @@ -316,12 +316,12 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (v -> Country == CountryCode) { - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; - if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; if (len != NULL) *len = v ->Len; - return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match + return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match } } } @@ -330,30 +330,30 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (Best == -1) Best = 0; - v = mlu ->Entries + Best; + v = mlu ->Entries + Best; - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; - if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; if (len != NULL) *len = v ->Len; - return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); + return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); } // Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len -cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - char* Buffer, cmsUInt32Number BufferSize) +cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) { const wchar_t *Wide; cmsUInt32Number StrLen = 0; cmsUInt32Number ASCIIlen, i; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - // Sanitize + // Sanitize if (mlu == NULL) return 0; // Get WideChar @@ -373,7 +373,7 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, ASCIIlen = BufferSize - 1; // Precess each character - for (i=0; i < ASCIIlen; i++) { + for (i=0; i < ASCIIlen; i++) { if (Wide[i] == 0) Buffer[i] = 0; @@ -381,28 +381,28 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, Buffer[i] = (char) Wide[i]; } - // We put a termination "\0" + // We put a termination "\0" Buffer[ASCIIlen] = 0; return ASCIIlen + 1; } -// Obtain a wide representation of the MLU, on depending on current locale settings -cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - wchar_t* Buffer, cmsUInt32Number BufferSize) +// Obtain a wide representation of the MLU, on depending on current locale settings +cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) { const wchar_t *Wide; cmsUInt32Number StrLen = 0; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - // Sanitize + // Sanitize if (mlu == NULL) return 0; Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); if (Wide == NULL) return 0; - + // Maybe we want only to know the len? if (Buffer == NULL) return StrLen + sizeof(wchar_t); @@ -414,35 +414,64 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, StrLen = BufferSize - + sizeof(wchar_t); memmove(Buffer, Wide, StrLen); - Buffer[StrLen / sizeof(wchar_t)] = 0; + Buffer[StrLen / sizeof(wchar_t)] = 0; return StrLen + sizeof(wchar_t); } // Get also the language and country -CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, - const char LanguageCode[3], const char CountryCode[3], - char ObtainedLanguage[3], char ObtainedCountry[3]) +CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char ObtainedLanguage[3], char ObtainedCountry[3]) { - const wchar_t *Wide; - - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); - cmsUInt16Number ObtLang, ObtCode; + const wchar_t *Wide; - // Sanitize + cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); + cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number ObtLang, ObtCode; + + // Sanitize if (mlu == NULL) return FALSE; Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); - if (Wide == NULL) return FALSE; - - // Get used language and code - *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); - *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); + if (Wide == NULL) return FALSE; - ObtainedLanguage[2] = ObtainedCountry[2] = 0; - return TRUE; + // Get used language and code + *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); + *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); + + ObtainedLanguage[2] = ObtainedCountry[2] = 0; + return TRUE; +} + + + +// Get the number of translations in the MLU object +cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu) +{ + if (mlu == NULL) return 0; + return mlu->UsedEntries; +} + +// Get the language and country codes for a specific MLU index +cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]) +{ + _cmsMLUentry *entry; + + if (mlu == NULL) return FALSE; + + if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE; + + entry = &mlu->Entries[idx]; + + *(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language); + *(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country); + + return TRUE; } @@ -451,7 +480,7 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, // Grow the list to keep at least NumElements static cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) -{ +{ cmsUInt32Number size; _cmsNAMEDCOLOR * NewPtr; @@ -466,9 +495,9 @@ cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) if (size > 1024*100) return FALSE; NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); - if (NewPtr == NULL) + if (NewPtr == NULL) return FALSE; - + v ->List = NewPtr; v ->Allocated = size; return TRUE; @@ -478,9 +507,9 @@ cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) { cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); - + if (v == NULL) return NULL; - + v ->List = NULL; v ->nColors = 0; v ->ContextID = ContextID; @@ -488,8 +517,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn while (v -> Allocated < n) GrowNamedColorList(v); - strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)); - strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)); + strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); + strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); + v->Prefix[32] = v->Suffix[32] = 0; + v -> ColorantCount = ColorantCount; return v; @@ -497,15 +528,16 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn // Free a list void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) -{ +{ + if (v == NULL) return; if (v ->List) _cmsFree(v ->ContextID, v ->List); - if (v) _cmsFree(v ->ContextID, v); -} + _cmsFree(v ->ContextID, v); +} cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) { cmsNAMEDCOLORLIST* NewNC; - + if (v == NULL) return NULL; NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); @@ -525,10 +557,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) // Append a color to a list. List pointer may change if reallocated -cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, - const char* Name, +cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, + const char* Name, cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) -{ +{ cmsUInt32Number i; if (NamedColorList == NULL) return FALSE; @@ -543,9 +575,12 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, for (i=0; i < 3; i++) NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i]; - if (Name != NULL) - strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, - sizeof(NamedColorList ->List[NamedColorList ->nColors].Name)); + if (Name != NULL) { + + strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); + NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; + + } else NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; @@ -554,21 +589,21 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, return TRUE; } -// Returns number of elements +// Returns number of elements cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList) -{ +{ if (NamedColorList == NULL) return 0; return NamedColorList ->nColors; } // Info aboout a given color -cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, - char* Name, - char* Prefix, +cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, + char* Name, + char* Prefix, char* Suffix, - cmsUInt16Number* PCS, + cmsUInt16Number* PCS, cmsUInt16Number* Colorant) -{ +{ if (NamedColorList == NULL) return FALSE; if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; @@ -576,11 +611,11 @@ cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cm if (Name) strcpy(Name, NamedColorList->List[nColor].Name); if (Prefix) strcpy(Prefix, NamedColorList->Prefix); if (Suffix) strcpy(Suffix, NamedColorList->Suffix); - if (PCS) + if (PCS) memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); - if (Colorant) - memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, + if (Colorant) + memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); @@ -589,7 +624,7 @@ cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cm // Search for a given color name (no prefix or suffix) cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) -{ +{ int i, n; if (NamedColorList == NULL) return -1; @@ -618,6 +653,24 @@ void* DupNamedColorList(cmsStage* mpe) return cmsDupNamedColorList(List); } +static +void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); + + if (index >= NamedColorList-> nColors) { + cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); + } + else { + + // Named color always uses Lab + Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0); + Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0); + Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0); + } +} + static void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) { @@ -629,23 +682,23 @@ void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const c cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); } else { - for (j=0; j < NamedColorList ->ColorantCount; j++) - Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); + for (j=0; j < NamedColorList ->ColorantCount; j++) + Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); } } // Named color lookup element -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList) +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) { - return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, - cmsSigNamedColorElemType, - 1, 3, - EvalNamedColor, - DupNamedColorList, - FreeNamedColorList, - cmsDupNamedColorList(NamedColorList)); - + return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, + cmsSigNamedColorElemType, + 1, UsePCS ? 3 : NamedColorList ->ColorantCount, + UsePCS ? EvalNamedColorPCS : EvalNamedColor, + DupNamedColorList, + FreeNamedColorList, + cmsDupNamedColorList(NamedColorList)); + } @@ -674,19 +727,23 @@ cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUI if (n > 255) return NULL; Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); - if (Seq == NULL) return NULL; - + if (Seq == NULL) return NULL; + Seq -> ContextID = ContextID; Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); Seq -> n = n; - + if (Seq -> seq == NULL) { + _cmsFree(ContextID, Seq); + return NULL; + } + for (i=0; i < n; i++) { Seq -> seq[i].Manufacturer = NULL; Seq -> seq[i].Model = NULL; Seq -> seq[i].Description = NULL; } - + return Seq; } @@ -715,10 +772,10 @@ cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ)); if (NewSeq == NULL) return NULL; - + NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC)); if (NewSeq ->seq == NULL) goto Error; - + NewSeq -> ContextID = pseq ->ContextID; NewSeq -> n = pseq ->n; @@ -734,7 +791,7 @@ cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer); NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model); NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description); - + } return NewSeq; @@ -745,6 +802,128 @@ Error: return NULL; } +// Dictionaries -------------------------------------------------------------------------------------------------------- + +// Dictionaries are just very simple linked lists +typedef struct _cmsDICT_struct { + cmsDICTentry* head; + cmsContext ContextID; +} _cmsDICT; + +// Allocate an empty dictionary +cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID) +{ + _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT)); + if (dict == NULL) return NULL; + + dict ->ContextID = ContextID; + return (cmsHANDLE) dict; + +} + +// Dispose resources +void CMSEXPORT cmsDictFree(cmsHANDLE hDict) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + cmsDICTentry *entry, *next; + + _cmsAssert(dict != NULL); + + // Walk the list freeing all nodes + entry = dict ->head; + while (entry != NULL) { + + if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName); + if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue); + if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name); + if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value); + + // Don't fall in the habitual trap... + next = entry ->Next; + _cmsFree(dict ->ContextID, entry); + + entry = next; + } + + _cmsFree(dict ->ContextID, dict); +} + + +// Duplicate a wide char string +static +wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr) +{ + if (ptr == NULL) return NULL; + return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t)); +} + +// Add a new entry to the linked list +cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + cmsDICTentry *entry; + + _cmsAssert(dict != NULL); + _cmsAssert(Name != NULL); + + entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry)); + if (entry == NULL) return FALSE; + + entry ->DisplayName = cmsMLUdup(DisplayName); + entry ->DisplayValue = cmsMLUdup(DisplayValue); + entry ->Name = DupWcs(dict ->ContextID, Name); + entry ->Value = DupWcs(dict ->ContextID, Value); + + entry ->Next = dict ->head; + dict ->head = entry; + + return TRUE; +} + + +// Duplicates an existing dictionary +cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) +{ + _cmsDICT* old_dict = (_cmsDICT*) hDict; + cmsHANDLE hNew; + cmsDICTentry *entry; + + _cmsAssert(old_dict != NULL); + + hNew = cmsDictAlloc(old_dict ->ContextID); + if (hNew == NULL) return NULL; + + // Walk the list freeing all nodes + entry = old_dict ->head; + while (entry != NULL) { + + if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) { + + cmsDictFree(hNew); + return NULL; + } + + entry = entry -> Next; + } + + return hNew; +} + +// Get a pointer to the linked list +const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + + if (dict == NULL) return NULL; + return dict ->head; +} + +// Helper For external languages +const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e) +{ + if (e == NULL) return NULL; + return e ->Next; +} diff --git a/thirdparty/liblcms2/src/cmsopt.c b/thirdparty/liblcms2/src/cmsopt.c index b1ce98e3..bf950917 100644 --- a/thirdparty/liblcms2/src/cmsopt.c +++ b/thirdparty/liblcms2/src/cmsopt.c @@ -2,24 +2,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -39,7 +39,7 @@ typedef struct { cmsUInt16Number rx[256], ry[256], rz[256]; cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data - + } Prelin8Data; @@ -52,33 +52,29 @@ typedef struct { // Number of channels int nInputs; int nOutputs; - - // Since there is no limitation of the output number of channels, this buffer holding the connexion CLUT-shaper - // has to be dynamically allocated. This is not the case of first step shaper-CLUT, which is limited to max inputs - cmsUInt16Number* StageDEF; - _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance - cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; - + _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance + cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; + _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid const cmsInterpParams* CLUTparams; // (not-owned pointer) - + _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer) cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer) - + } Prelin16Data; -// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed +// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed typedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits! #define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5)) typedef struct { - + cmsContext ContextID; cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0) @@ -88,7 +84,7 @@ typedef struct { cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that) cmsS1Fixed14Number Off[3]; - cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 + cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 cmsUInt16Number Shaper2G[16385]; cmsUInt16Number Shaper2B[16385]; @@ -119,10 +115,10 @@ void _RemoveElement(cmsStage** head) cmsStageFree(mpe); } -// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. +// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. static cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) -{ +{ cmsStage** pt = &Lut ->Elements; cmsBool AnyOpt = FALSE; @@ -132,7 +128,7 @@ cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) _RemoveElement(pt); AnyOpt = TRUE; } - else + else pt = &((*pt) -> Next); } @@ -142,14 +138,14 @@ cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) // Same, but only if two adjacent elements are found static cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2) -{ +{ cmsStage** pt1; cmsStage** pt2; cmsBool AnyOpt = FALSE; pt1 = &Lut ->Elements; if (*pt1 == NULL) return AnyOpt; - + while (*pt1 != NULL) { pt2 = &((*pt1) -> Next); @@ -160,22 +156,20 @@ cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op _RemoveElement(pt1); AnyOpt = TRUE; } - else - pt1 = &((*pt1) -> Next); + else + pt1 = &((*pt1) -> Next); } return AnyOpt; } -// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed +// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed // by a v4 to v2 and vice-versa. The elements are then discarded. static cmsBool PreOptimize(cmsPipeline* Lut) -{ +{ cmsBool AnyOpt = FALSE, Opt; - AnyOpt = FALSE; - do { Opt = FALSE; @@ -195,6 +189,12 @@ cmsBool PreOptimize(cmsPipeline* Lut) // Remove V2 to V4 followed by V4 to V2 Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2); + // Remove float pcs Lab conversions + Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab); + + // Remove float pcs Lab conversions + Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ); + if (Opt) AnyOpt = TRUE; } while (Opt); @@ -204,12 +204,12 @@ cmsBool PreOptimize(cmsPipeline* Lut) static void Eval16nop1D(register const cmsUInt16Number Input[], - register cmsUInt16Number Output[], + register cmsUInt16Number Output[], register const struct _cms_interp_struc* p) { Output[0] = Input[0]; - cmsUNUSED_PARAMETER(p); + cmsUNUSED_PARAMETER(p); } static @@ -219,18 +219,19 @@ void PrelinEval16(register const cmsUInt16Number Input[], { Prelin16Data* p16 = (Prelin16Data*) D; cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; + cmsUInt16Number StageDEF[cmsMAXCHANNELS]; int i; for (i=0; i < p16 ->nInputs; i++) { - + p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); } - p16 ->EvalCLUT(StageABC, p16 ->StageDEF, p16 ->CLUTparams); + p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams); for (i=0; i < p16 ->nOutputs; i++) { - - p16 ->EvalCurveOut16[i](&p16->StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); + + p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); } } @@ -240,7 +241,6 @@ void PrelinOpt16free(cmsContext ContextID, void* ptr) { Prelin16Data* p16 = (Prelin16Data*) ptr; - _cmsFree(ContextID, p16 ->StageDEF); _cmsFree(ContextID, p16 ->EvalCurveOut16); _cmsFree(ContextID, p16 ->ParamsCurveOut16); @@ -249,13 +249,12 @@ void PrelinOpt16free(cmsContext ContextID, void* ptr) static void* Prelin16dup(cmsContext ContextID, const void* ptr) -{ +{ Prelin16Data* p16 = (Prelin16Data*) ptr; Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); if (Duped == NULL) return NULL; - Duped ->StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); @@ -264,19 +263,19 @@ void* Prelin16dup(cmsContext ContextID, const void* ptr) static -Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, - const cmsInterpParams* ColorMap, - int nInputs, cmsToneCurve** In, +Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, + const cmsInterpParams* ColorMap, + int nInputs, cmsToneCurve** In, int nOutputs, cmsToneCurve** Out ) { int i; - Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data)); + Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data)); if (p16 == NULL) return NULL; p16 ->nInputs = nInputs; p16 -> nOutputs = nOutputs; - + for (i=0; i < nInputs; i++) { if (In == NULL) { @@ -294,7 +293,6 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; - p16 -> StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); @@ -320,7 +318,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, #define PRELINEARIZATION_POINTS 4096 -// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for +// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for // almost any transform. We use floating point precision and then convert from floating point to 16 bits. static int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) @@ -333,14 +331,14 @@ int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS); // From 16 bit to floating point - for (i=0; i < Lut ->InputChannels; i++) + for (i=0; i < Lut ->InputChannels; i++) InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0); // Evaluate in floating point cmsPipelineEvalFloat(InFloat, OutFloat, Lut); // Back to 16 bits representation - for (i=0; i < Lut ->OutputChannels; i++) + for (i=0; i < Lut ->OutputChannels; i++) Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0); // Always succeed @@ -351,11 +349,11 @@ int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number static cmsBool AllCurvesAreLinear(cmsStage* mpe) { - cmsToneCurve** Curves; + cmsToneCurve** Curves; cmsUInt32Number i, n; Curves = _cmsStageGetPtrToCurveSet(mpe); - if (Curves == NULL) return FALSE; + if (Curves == NULL) return FALSE; n = cmsStageOutputChannels(mpe); @@ -379,49 +377,61 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], int i, index; if (CLUT -> Type != cmsSigCLutElemType) { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut MPE"); + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage"); return FALSE; } - px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; - py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; - pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; - pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; - - x0 = (int) floor(px); - y0 = (int) floor(py); - z0 = (int) floor(pz); - w0 = (int) floor(pw); - if (nChannelsIn == 4) { + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; + pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; + pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; + + x0 = (int) floor(px); + y0 = (int) floor(py); + z0 = (int) floor(pz); + w0 = (int) floor(pw); + if (((px - x0) != 0) || ((py - y0) != 0) || ((pz - z0) != 0) || ((pw - w0) != 0)) return FALSE; // Not on exact node index = p16 -> opta[3] * x0 + - p16 -> opta[2] * y0 + - p16 -> opta[1] * z0 + - p16 -> opta[0] * w0; + p16 -> opta[2] * y0 + + p16 -> opta[1] * z0 + + p16 -> opta[0] * w0; } - else + else if (nChannelsIn == 3) { + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; + pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; + + x0 = (int) floor(px); + y0 = (int) floor(py); + z0 = (int) floor(pz); + if (((px - x0) != 0) || ((py - y0) != 0) || ((pz - z0) != 0)) return FALSE; // Not on exact node index = p16 -> opta[2] * x0 + - p16 -> opta[1] * y0 + - p16 -> opta[0] * z0; + p16 -> opta[1] * y0 + + p16 -> opta[0] * z0; } - else + else if (nChannelsIn == 1) { + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + + x0 = (int) floor(px); + if (((px - x0) != 0)) return FALSE; // Not on exact node - index = p16 -> opta[0] * x0; + index = p16 -> opta[0] * x0; } else { cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); @@ -434,13 +444,15 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], return TRUE; } -// Auxiliar, to see if two values are equal. +// Auxiliar, to see if two values are equal or very different static -cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) +cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) { int i; for (i=0; i < n; i++) { + + if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremly different that the fixup should be avoided if (White1[i] != White2[i]) return FALSE; } return TRUE; @@ -455,7 +467,7 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS]; cmsUInt32Number i, nOuts, nIns; cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL; - + if (!_cmsEndPointsBySpace(EntryColorSpace, &WhitePointIn, NULL, &nIns)) return FALSE; @@ -463,11 +475,13 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor &WhitePointOut, NULL, &nOuts)) return FALSE; // It needs to be fixed? + if (Lut ->InputChannels != nIns) return FALSE; + if (Lut ->OutputChannels != nOuts) return FALSE; cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut); - if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match - + if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match + // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin)) if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT)) @@ -480,31 +494,37 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin); - for (i=0; i < nIns; i++) { + for (i=0; i < nIns; i++) { WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]); } } else { - for (i=0; i < nIns; i++) - WhiteIn[i] = WhitePointIn[i]; + for (i=0; i < nIns; i++) + WhiteIn[i] = WhitePointIn[i]; } // If any post-linearization, we need to find how is represented white before the curve, do // a reverse interpolation in this case. if (PostLin) { - + cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin); - + for (i=0; i < nOuts; i++) { - + cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); - WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); - cmsFreeToneCurve(InversePostLin); + if (InversePostLin == NULL) { + WhiteOut[i] = WhitePointOut[i]; + + } else { + + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); + } } } else { - for (i=0; i < nOuts; i++) - WhiteOut[i] = WhitePointOut[i]; + for (i=0; i < nOuts; i++) + WhiteOut[i] = WhitePointOut[i]; } // Ok, proceed with patching. May fail and we don't care if it fails @@ -514,22 +534,23 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor } // ----------------------------------------------------------------------------------------------------------------------------------------------- -// This function creates simple LUT from complex ones. The generated LUT has an optional set of -// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. -// These curves have to exist in the original LUT in order to be used in the simplified output. +// This function creates simple LUT from complex ones. The generated LUT has an optional set of +// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. +// These curves have to exist in the original LUT in order to be used in the simplified output. // Caller may also use the flags to allow this feature. // LUTS with all curves will be simplified to a single curve. Parametric curves are lost. // This function should be used on 16-bits LUTS only, as floating point losses precision when simplified // ----------------------------------------------------------------------------------------------------------------------------------------------- static -cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { - cmsPipeline* Src; - cmsPipeline* Dest; - cmsStage* CLUT; + cmsPipeline* Src = NULL; + cmsPipeline* Dest = NULL; + cmsStage* mpe; + cmsStage* CLUT; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; - int nGridPoints; + int nGridPoints; cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsStage *NewPreLin = NULL; cmsStage *NewPostLin = NULL; @@ -538,7 +559,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 cmsToneCurve** DataSetOut; Prelin16Data* p16; - // This is a loosy optimization! does not apply in floating-point cases if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; @@ -552,7 +572,14 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 Src = *Lut; - // Allocate an empty LUT + // Named color pipelines cannot be optimized either + for (mpe = cmsPipelineGetPtrToFirstStage(Src); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + } + + // Allocate an empty LUT Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); if (!Dest) return FALSE; @@ -568,9 +595,10 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 // Maybe this is a linear tram, so we can avoid the whole stuff if (!AllCurvesAreLinear(PreLin)) { - // All seems ok, proceed. + // All seems ok, proceed. NewPreLin = cmsStageDup(PreLin); - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin); + if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin)) + goto Error; // Remove prelinearization. Since we have duplicated the curve // in destination LUT, the sampling shoud be applied after this stage. @@ -584,7 +612,9 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 if (CLUT == NULL) return FALSE; // Add the CLUT to the destination LUT - cmsPipelineInsertStage(Dest, cmsAT_END, CLUT); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { + goto Error; + } // Postlinearization tables are kept unless indicated by flags if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { @@ -598,9 +628,10 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 // Maybe this is a linear tram, so we can avoid the whole stuff if (!AllCurvesAreLinear(PostLin)) { - // All seems ok, proceed. + // All seems ok, proceed. NewPostLin = cmsStageDup(PostLin); - cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin)) + goto Error; // In destination LUT, the sampling shoud be applied after this stage. cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); @@ -608,18 +639,26 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 } } - // Now its time to do the sampling. We have to ignore pre/post linearization + // Now its time to do the sampling. We have to ignore pre/post linearization // The source LUT whithout pre/post curves is passed as parameter. if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { - +Error: // Ops, something went wrong, Restore stages - if (KeepPreLin != NULL) cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin); - if (KeepPostLin != NULL) cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin); + if (KeepPreLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) { + _cmsAssert(0); // This never happens + } + } + if (KeepPostLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) { + _cmsAssert(0); // This never happens + } + } cmsPipelineFree(Dest); return FALSE; - } + } - // Done. + // Done. if (KeepPreLin != NULL) cmsStageFree(KeepPreLin); if (KeepPostLin != NULL) cmsStageFree(KeepPostLin); @@ -640,13 +679,12 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 } else { - p16 = PrelinOpt16alloc(Dest ->ContextID, - DataCLUT ->Params, - Dest ->InputChannels, - DataSetIn, - Dest ->OutputChannels, - DataSetOut); - + p16 = PrelinOpt16alloc(Dest ->ContextID, + DataCLUT ->Params, + Dest ->InputChannels, + DataSetIn, + Dest ->OutputChannels, + DataSetOut); _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); } @@ -664,13 +702,13 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 *Lut = Dest; return TRUE; - cmsUNUSED_PARAMETER(Intent); + cmsUNUSED_PARAMETER(Intent); } // ----------------------------------------------------------------------------------------------------------------------------------------------- -// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on -// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works +// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on +// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works // for RGB transforms. See the paper for more details // ----------------------------------------------------------------------------------------------------------------------------------------------- @@ -706,12 +744,12 @@ void SlopeLimiting(cmsToneCurve* g) Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases beta = Val - Slope * AtEnd; - for (i = AtEnd; i < (int) g ->nEntries; i++) + for (i = AtEnd; i < (int) g ->nEntries; i++) g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); } -// Precomputes tables for 8-bit on input devicelink. +// Precomputes tables for 8-bit on input devicelink. static Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3]) { @@ -722,8 +760,8 @@ Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cms p8 = _cmsMallocZero(ContextID, sizeof(Prelin8Data)); if (p8 == NULL) return NULL; - - // Since this only works for 8 bit input, values comes always as x * 257, + + // Since this only works for 8 bit input, values comes always as x * 257, // we can safely take msb byte (x << 8 + x) for (i=0; i < 256; i++) { @@ -766,13 +804,13 @@ Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cms static void Prelin8free(cmsContext ContextID, void* ptr) -{ +{ _cmsFree(ContextID, ptr); } static void* Prelin8dup(cmsContext ContextID, const void* ptr) -{ +{ return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data)); } @@ -785,17 +823,17 @@ void PrelinEval8(register const cmsUInt16Number Input[], register cmsUInt16Number Output[], register const void* D) { - + cmsUInt8Number r, g, b; - cmsS15Fixed16Number rx, ry, rz; - cmsS15Fixed16Number c0, c1, c2, c3, Rest; - int OutChan; - register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + cmsS15Fixed16Number rx, ry, rz; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + int OutChan; + register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; Prelin8Data* p8 = (Prelin8Data*) D; register const cmsInterpParams* p = p8 ->p; int TotalOut = p -> nOutputs; const cmsUInt16Number* LutTable = p -> Table; - + r = Input[0] >> 8; g = Input[1] >> 8; b = Input[2] >> 8; @@ -812,7 +850,7 @@ void PrelinEval8(register const cmsUInt16Number Input[], Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]); Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]); - + // These are the 6 Tetrahedral for (OutChan=0; OutChan < TotalOut; OutChan++) { @@ -822,11 +860,11 @@ void PrelinEval8(register const cmsUInt16Number Input[], { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); } else if (rx >= rz && rz >= ry) - { + { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); @@ -836,59 +874,80 @@ void PrelinEval8(register const cmsUInt16Number Input[], { c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; + c3 = DENS(X0, Y0, Z1) - c0; } else if (ry >= rx && rx >= rz) { c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); } else if (ry >= rz && rz >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z0) - c0; - c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); } else if (rz >= ry && ry >= rx) - { + { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); - c3 = DENS(X0, Y0, Z1) - c0; + c3 = DENS(X0, Y0, Z1) - c0; } else { - c1 = c2 = c3 = 0; + c1 = c2 = c3 = 0; } - Rest = c1 * rx + c2 * ry + c3 * rz; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16); - Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); - } } #undef DENS + +// Curves that contain wide empty areas are not optimizeable +static +cmsBool IsDegenerated(const cmsToneCurve* g) +{ + int i, Zeros = 0, Poles = 0; + int nEntries = g ->nEntries; + + for (i=0; i < nEntries; i++) { + + if (g ->Table16[i] == 0x0000) Zeros++; + if (g ->Table16[i] == 0xffff) Poles++; + } + + if (Zeros == 1 && Poles == 1) return FALSE; // For linear tables + if (Zeros > (nEntries / 4)) return TRUE; // Degenerated, mostly zeros + if (Poles > (nEntries / 4)) return TRUE; // Degenerated, mostly poles + + return FALSE; +} + // -------------------------------------------------------------------------------------------------------------- // We need xput over here static -cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { cmsPipeline* OriginalLut; int nGridPoints; cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS]; - cmsUInt32Number t, i; + cmsUInt32Number t, i; cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS]; cmsBool lIsSuitable, lIsLinear; - cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; + cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; cmsStage* OptimizedCLUTmpe; cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsStage* OptimizedPrelinMpe; + cmsStage* mpe; cmsToneCurve** OptimizedPrelinCurves; _cmsStageCLutData* OptimizedPrelinCLUT; @@ -907,6 +966,14 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte } OriginalLut = *Lut; + + // Named color pipelines cannot be optimized either + for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + } + ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); @@ -938,7 +1005,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte } // Slope-limit the obtained curves - for (t = 0; t < OriginalLut ->InputChannels; t++) + for (t = 0; t < OriginalLut ->InputChannels; t++) SlopeLimiting(Trans[t]); // Check for validity @@ -952,7 +1019,10 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte // Exclude if non-monotonic if (!cmsIsToneCurveMonotonic(Trans[t])) - lIsSuitable = FALSE; + lIsSuitable = FALSE; + + if (IsDegenerated(Trans[t])) + lIsSuitable = FALSE; } // If it is not suitable, just quit @@ -968,7 +1038,8 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte LutPlusCurves = cmsPipelineDup(OriginalLut); if (LutPlusCurves == NULL) goto Error; - cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse)); + if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse))) + goto Error; // Create the result LUT OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); @@ -976,14 +1047,16 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); - // Create and insert the curves at the beginning - cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe); + // Create and insert the curves at the beginning + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe)) + goto Error; // Allocate the CLUT for result OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); // Add the CLUT to the destination LUT - cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe); + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe)) + goto Error; // Resample the LUT if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; @@ -1004,18 +1077,18 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte // Set the evaluator if 8-bit if (_cmsFormatterIs8bit(*InputFormat)) { - Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, - OptimizedPrelinCLUT ->Params, + Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, OptimizedPrelinCurves); if (p8 == NULL) return FALSE; _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup); - } + } else { - Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, - OptimizedPrelinCLUT ->Params, + Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, 3, OptimizedPrelinCurves, 3, NULL); if (p16 == NULL) return FALSE; @@ -1049,10 +1122,10 @@ Error: if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); } - if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); + if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT); - return FALSE; + return FALSE; cmsUNUSED_PARAMETER(Intent); } @@ -1062,12 +1135,12 @@ Error: static void CurvesFree(cmsContext ContextID, void* ptr) -{ +{ Curves16Data* Data = (Curves16Data*) ptr; int i; for (i=0; i < Data -> nCurves; i++) { - + _cmsFree(ContextID, Data ->Curves[i]); } @@ -1077,7 +1150,7 @@ void CurvesFree(cmsContext ContextID, void* ptr) static void* CurvesDup(cmsContext ContextID, const void* ptr) -{ +{ Curves16Data* Data = _cmsDupMem(ContextID, ptr, sizeof(Curves16Data)); int i; @@ -1092,7 +1165,7 @@ void* CurvesDup(cmsContext ContextID, const void* ptr) return (void*) Data; } -// Precomputes tables for 8-bit on input devicelink. +// Precomputes tables for 8-bit on input devicelink. static Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G) { @@ -1112,17 +1185,27 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); + if (c16->Curves[i] == NULL) { + + for (j=0; j < i; j++) { + _cmsFree(ContextID, c16->Curves[j]); + } + _cmsFree(ContextID, c16->Curves); + _cmsFree(ContextID, c16); + return NULL; + } + if (nElements == 256) { for (j=0; j < nElements; j++) { - c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); } } else { for (j=0; j < nElements; j++) { - c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); } } } @@ -1131,14 +1214,14 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT } static -void FastEvaluateCurves8(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], +void FastEvaluateCurves8(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], register const void* D) -{ +{ Curves16Data* Data = (Curves16Data*) D; cmsUInt8Number x; int i; - + for (i=0; i < Data ->nCurves; i++) { x = (In[i] >> 8); @@ -1146,15 +1229,15 @@ void FastEvaluateCurves8(register const cmsUInt16Number In[], } } - + static -void FastEvaluateCurves16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], +void FastEvaluateCurves16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], register const void* D) -{ +{ Curves16Data* Data = (Curves16Data*) D; int i; - + for (i=0; i < Data ->nCurves; i++) { Out[i] = Data -> Curves[i][In[i]]; } @@ -1162,15 +1245,15 @@ void FastEvaluateCurves16(register const cmsUInt16Number In[], static -void FastIdentity16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], +void FastIdentity16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], register const void* D) { cmsPipeline* Lut = (cmsPipeline*) D; cmsUInt32Number i; for (i=0; i < Lut ->InputChannels; i++) { - Out[i] = In[i]; + Out[i] = In[i]; } } @@ -1180,7 +1263,7 @@ void FastIdentity16(register const cmsUInt16Number In[], static cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { - cmsToneCurve** GammaTables = NULL; + cmsToneCurve** GammaTables = NULL; cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; cmsUInt32Number i, j; cmsPipeline* Src = *Lut; @@ -1199,7 +1282,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; } - // Allocate an empty LUT + // Allocate an empty LUT Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); if (Dest == NULL) return FALSE; @@ -1215,7 +1298,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI // Compute 16 bit result by using floating point for (i=0; i < PRELINEARIZATION_POINTS; i++) { - for (j=0; j < Src ->InputChannels; j++) + for (j=0; j < Src ->InputChannels; j++) InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); cmsPipelineEvalFloat(InFloat, OutFloat, Src); @@ -1237,7 +1320,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI // Maybe the curves are linear at the end if (!AllCurvesAreLinear(ObtainedCurves)) { - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves)) + goto Error; // If the curves are to be applied in 8 bits, we can save memory if (_cmsFormatterIs8bit(*InputFormat)) { @@ -1245,6 +1329,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); + if (c16 == NULL) goto Error; *dwFlags |= cmsFLAGS_NOCACHE; _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); @@ -1254,8 +1339,9 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); + if (c16 == NULL) goto Error; *dwFlags |= cmsFLAGS_NOCACHE; - _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); + _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); } } else { @@ -1263,7 +1349,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI // LUT optimizes to nothing. Set the identity LUT cmsStageFree(ObtainedCurves); - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels)); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels))) + goto Error; *dwFlags |= cmsFLAGS_NOCACHE; _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); @@ -1311,44 +1398,44 @@ void* DupMatShaper(cmsContext ContextID, const void* Data) } -// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point -// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, +// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point +// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, // in total about 50K, and the performance boost is huge! static -void MatShaperEval16(register const cmsUInt16Number In[], - register cmsUInt16Number Out[], +void MatShaperEval16(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], register const void* D) -{ +{ MatShaper8Data* p = (MatShaper8Data*) D; cmsS1Fixed14Number l1, l2, l3, r, g, b; cmsUInt32Number ri, gi, bi; - // In this case (and only in this case!) we can use this simplification since + // In this case (and only in this case!) we can use this simplification since // In[] is assured to come from a 8 bit number. (a << 8 | a) ri = In[0] & 0xFF; gi = In[1] & 0xFF; bi = In[2] & 0xFF; - + // Across first shaper, which also converts to 1.14 fixed point r = p->Shaper1R[ri]; g = p->Shaper1G[gi]; b = p->Shaper1B[bi]; - + // Evaluate the matrix in 1.14 fixed point l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14; l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14; l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14; - - // Now we have to clip to 0..1.0 range - ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1); - gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2); - bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3); - - // And across second shaper, + + // Now we have to clip to 0..1.0 range + ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1); + gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2); + bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3); + + // And across second shaper, Out[0] = p->Shaper2R[ri]; Out[1] = p->Shaper2G[gi]; Out[2] = p->Shaper2B[bi]; - + } // This table converts from 8 bits to 1.14 after applying the curve @@ -1359,9 +1446,9 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) cmsFloat32Number R, y; for (i=0; i < 256; i++) { - + R = (cmsFloat32Number) (i / 255.0); - y = cmsEvalToneCurveFloat(Curve, R); + y = cmsEvalToneCurveFloat(Curve, R); Table[i] = DOUBLE_TO_1FIXED14(y); } @@ -1378,19 +1465,19 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi R = (cmsFloat32Number) (i / 16384.0); Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 - + if (Is8BitsOutput) { // If 8 bits output, we can optimize further by computing the / 257 part. // first we compute the resulting byte and then we store the byte times // 257. This quantization allows to round very quick by doing a >> 8, but // since the low byte is always equal to msb, we can do a & 0xff and this works! - cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0 + 0.5); + cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); cmsUInt8Number b = FROM_16_TO_8(w); Table[i] = FROM_8_TO_16(b); } - else Table[i] = _cmsQuickSaturateWord(Val * 65535.0 + 0.5); + else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); } } @@ -1419,17 +1506,17 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c // Convert matrix to nFixed14. Note that those values may take more than 16 bits as for (i=0; i < 3; i++) { - for (j=0; j < 3; j++) { + for (j=0; j < 3; j++) { p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); } } - + for (i=0; i < 3; i++) { - if (Off == NULL) { + if (Off == NULL) { p ->Off[i] = 0; } - else { + else { p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); } } @@ -1438,7 +1525,7 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c if (Is8Bits) *OutputFormat |= OPTIMIZED_SH(1); - // Fill function pointers + // Fill function pointers _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); return TRUE; } @@ -1455,7 +1542,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 cmsMAT3 res; cmsBool IdentityMat; cmsPipeline* Dest, *Src; - + // Only works on RGB to RGB if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; @@ -1466,8 +1553,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 Src = *Lut; // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for - if (!cmsPipelineCheckAndRetreiveStages(Src, 4, - cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + if (!cmsPipelineCheckAndRetreiveStages(Src, 4, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE; // Get both matrices @@ -1488,26 +1575,30 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 IdentityMat = TRUE; } - // Allocate an empty LUT + // Allocate an empty LUT Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); if (!Dest) return FALSE; // Assamble the new LUT - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)); - if (!IdentityMat) - cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)); - cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) + goto Error; + + if (!IdentityMat) + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset))) + goto Error; + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) + goto Error; // If identity on matrix, we can further optimize the curves, so call the join curves routine if (IdentityMat) { - OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); + OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); } else { _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); - - // In this particular optimization, caché does not help as it takes more time to deal with + + // In this particular optimization, caché does not help as it takes more time to deal with // the caché that with the pixel handling *dwFlags |= cmsFLAGS_NOCACHE; @@ -1518,6 +1609,10 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 cmsPipelineFree(Src); *Lut = Dest; return TRUE; +Error: + // Leave Src unchanged + cmsPipelineFree(Dest); + return FALSE; } @@ -1526,9 +1621,9 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 // List of optimizations typedef struct _cmsOptimizationCollection_st { - + _cmsOPToptimizeFn OptimizePtr; - + struct _cmsOptimizationCollection_st *Next; } _cmsOptimizationCollection; @@ -1544,50 +1639,108 @@ static _cmsOptimizationCollection DefaultOptimization[] = { }; // The linked list head -static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; +_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginOptimizationList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsOptimizationPluginChunkType newHead = { NULL }; + _cmsOptimizationCollection* entry; + _cmsOptimizationCollection* Anterior = NULL; + _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; + + _cmsAssert(ctx != NULL); + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->OptimizationCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.OptimizationCollection == NULL) + newHead.OptimizationCollection = newEntry; + } + + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); +} + +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginOptimizationList(ctx, src); + } + else { + static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); + } +} + // Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* fl; - + if (Data == NULL) { - OptimizationCollection = DefaultOptimization; + ctx->OptimizationCollection = NULL; return TRUE; } - + // Optimizer callback is required if (Plugin ->OptimizePtr == NULL) return FALSE; - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(sizeof(_cmsOptimizationCollection)); + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); if (fl == NULL) return FALSE; // Copy the parameters fl ->OptimizePtr = Plugin ->OptimizePtr; - + // Keep linked list - fl ->Next = OptimizationCollection; - OptimizationCollection = fl; + fl ->Next = ctx->OptimizationCollection; + + // Set the head + ctx ->OptimizationCollection = fl; // All is ok return TRUE; } // The entry point for LUT optimization -cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** PtrLut, int Intent, - cmsUInt32Number* InputFormat, + cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) -{ +{ + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* Opts; cmsBool AnySuccess = FALSE; - + // A CLUT is being asked, so force this specific optimization if (*dwFlags & cmsFLAGS_FORCE_CLUT) { - + PreOptimize(*PtrLut); return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags); } @@ -1595,7 +1748,7 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, // Anything to optimize? if ((*PtrLut) ->Elements == NULL) { _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); - return TRUE; + return TRUE; } // Try to get rid of identities and trivial conversions. @@ -1610,19 +1763,30 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, // Do not optimize, keep all precision if (*dwFlags & cmsFLAGS_NOOPTIMIZE) return FALSE; - - // Try built-in optimizations and plug-in - for (Opts = OptimizationCollection; + + // Try plug-in optimizations + for (Opts = ctx->OptimizationCollection; Opts != NULL; Opts = Opts ->Next) { - + // If one schema succeeded, we are done if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { - + return TRUE; // Optimized! } } - + + // Try built-in optimizations + for (Opts = DefaultOptimization; + Opts != NULL; + Opts = Opts ->Next) { + + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; + } + } + // Only simple optimizations succeeded return AnySuccess; } diff --git a/thirdparty/liblcms2/src/cmspack.c b/thirdparty/liblcms2/src/cmspack.c index 196afa94..c84fd822 100644 --- a/thirdparty/liblcms2/src/cmspack.c +++ b/thirdparty/liblcms2/src/cmspack.c @@ -3,22 +3,22 @@ // Little Color Management System // Copyright (c) 1998-2010 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -26,10 +26,10 @@ #include "lcms2_internal.h" -// This module handles all formats supported by lcms. There are two flavors, 16 bits and +// This module handles all formats supported by lcms. There are two flavors, 16 bits and // floating point. Floating point is supported only in a subset, those formats holding -// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special -// case) +// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component +// as special case) // --------------------------------------------------------------------------- @@ -42,17 +42,15 @@ #define REVERSE_FLAVOR_16(x) ((cmsUInt16Number)(0xffff-(x))) // * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 -cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) +cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) { - int a; - - a = (x << 8 | x) >> 8; // * 257 / 256 + int a = (x << 8 | x) >> 8; // * 257 / 256 if ( a > 0xffff) return 0xffff; return (cmsUInt16Number) a; } // * 0xf00 / 0xffff = * 256 / 257 -cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) +cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) { return (cmsUInt16Number) (((x << 8) + 0x80) / 257); } @@ -61,24 +59,25 @@ cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) typedef struct { cmsUInt32Number Type; cmsUInt32Number Mask; - cmsFormatter16 Frm; + cmsFormatter16 Frm; } cmsFormatters16; typedef struct { cmsUInt32Number Type; cmsUInt32Number Mask; - cmsFormatterFloat Frm; + cmsFormatterFloat Frm; } cmsFormattersFloat; + #define ANYSPACE COLORSPACE_SH(31) #define ANYCHANNELS CHANNELS_SH(15) #define ANYEXTRA EXTRA_SH(7) #define ANYPLANAR PLANAR_SH(1) #define ANYENDIAN ENDIAN16_SH(1) #define ANYSWAP DOSWAP_SH(1) -#define ANYSWAPFIRST SWAPFIRST_SH(1) +#define ANYSWAPFIRST SWAPFIRST_SH(1) #define ANYFLAVOR FLAVOR_SH(1) @@ -88,12 +87,13 @@ typedef struct { #pragma warning(disable : 4100) #endif -// Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- +// Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- + // Does almost everything but is slow static -cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -102,7 +102,7 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->InputFormat); int SwapFirst = T_SWAPFIRST(info -> InputFormat); int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt16Number v; int i; @@ -113,10 +113,10 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; - v = FROM_8_TO_16(*accum); + v = FROM_8_TO_16(*accum); v = Reverse ? REVERSE_FLAVOR_16(v) : v; wIn[index] = v; - accum++; + accum++; } if (!ExtraFirst) { @@ -131,29 +131,34 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, } return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); + } // Extra channels are just ignored because come in the next planes static -cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap= T_DOSWAP(info ->InputFormat); - int Reverse= T_FLAVOR(info ->InputFormat); + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); int i; cmsUInt8Number* Init = accum; - if (DoSwap) { + if (DoSwap ^ SwapFirst) { accum += T_EXTRA(info -> InputFormat) * Stride; } for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = FROM_8_TO_16(*accum); + cmsUInt16Number v = FROM_8_TO_16(*accum); wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; accum += Stride; @@ -164,8 +169,8 @@ cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, // Special cases, provided for performance static -cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -175,11 +180,14 @@ cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(*accum); accum++; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -189,11 +197,14 @@ cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -203,12 +214,15 @@ cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // Y return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KYMC static -cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -218,11 +232,14 @@ cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -232,11 +249,14 @@ cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(*accum); accum++; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -245,11 +265,14 @@ cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -259,6 +282,26 @@ cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // R return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + accum++; // A + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -273,13 +316,16 @@ cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // BRG static -cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -288,11 +334,14 @@ cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // R return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -301,11 +350,14 @@ cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -315,11 +367,14 @@ cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -328,18 +383,25 @@ cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // for duplex static -cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) +cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) { wIn[0] = FROM_8_TO_16(*accum); accum++; // ch1 wIn[1] = FROM_8_TO_16(*accum); accum++; // ch2 + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -347,52 +409,68 @@ cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, // Monochrome duplicates L into RGB for null-transforms static -cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - return accum; -} - - -static -cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - accum += 1; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + accum += 1; + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L accum += 2; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++; // L + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -402,7 +480,7 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->InputFormat); int SwapFirst = T_SWAPFIRST(info -> InputFormat); int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; int i; if (ExtraFirst) { @@ -412,14 +490,14 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = *(cmsUInt16Number*) accum; + cmsUInt16Number v = *(cmsUInt16Number*) accum; if (SwapEndian) v = CHANGE_ENDIAN(v); wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; - accum += sizeof(cmsUInt16Number); + accum += sizeof(cmsUInt16Number); } if (!ExtraFirst) { @@ -435,11 +513,13 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, } return accum; + + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -457,14 +537,14 @@ cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = *(cmsUInt16Number*) accum; + cmsUInt16Number v = *(cmsUInt16Number*) accum; if (SwapEndian) v = CHANGE_ENDIAN(v); wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; - accum += Stride * sizeof(cmsUInt16Number); + accum += Stride * sizeof(cmsUInt16Number); } return (Init + sizeof(cmsUInt16Number)); @@ -472,8 +552,8 @@ cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, static -cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -483,11 +563,14 @@ cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -497,11 +580,14 @@ cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -511,12 +597,15 @@ cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KYMC static -cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -526,11 +615,14 @@ cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -540,35 +632,46 @@ cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C R wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // C R wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -578,11 +681,14 @@ cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -592,60 +698,78 @@ cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; + wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum += 8; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) +cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) { wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // ch1 wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // ch2 return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // This is a conversion of Lab double to 16 bits static -cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) -{ +{ if (T_PLANAR(info -> InputFormat)) { cmsFloat64Number* Pt = (cmsFloat64Number*) accum; @@ -667,13 +791,47 @@ cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, } } + +// This is a conversion of Lab float to 16 bits +static +cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsCIELab Lab; + + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + + Lab.L = Pt[0]; + Lab.a = Pt[Stride]; + Lab.b = Pt[Stride*2]; + + cmsFloat2LabEncoded(wIn, &Lab); + return accum + sizeof(cmsFloat32Number); + } + else { + + Lab.L = ((cmsFloat32Number*) accum)[0]; + Lab.a = ((cmsFloat32Number*) accum)[1]; + Lab.b = ((cmsFloat32Number*) accum)[2]; + + cmsFloat2LabEncoded(wIn, &Lab); + accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum; + } +} + // This is a conversion of XYZ double to 16 bits static -cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) -{ +{ if (T_PLANAR(info -> InputFormat)) { cmsFloat64Number* Pt = (cmsFloat64Number*) accum; @@ -696,23 +854,59 @@ cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, } } +// This is a conversion of XYZ float to 16 bits +static +cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[Stride]; + XYZ.Z = Pt[Stride*2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat32Number); + + } + + else { + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[1]; + XYZ.Z = Pt[2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number); + + return accum; + } +} + // Check if space is marked as ink cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) { switch (T_COLORSPACE(Type)) { - case PT_CMY: - case PT_CMYK: - case PT_MCH5: + case PT_CMY: + case PT_CMYK: + case PT_MCH5: case PT_MCH6: - case PT_MCH7: - case PT_MCH8: - case PT_MCH9: - case PT_MCH10: - case PT_MCH11: - case PT_MCH12: - case PT_MCH13: - case PT_MCH14: + case PT_MCH7: + case PT_MCH8: + case PT_MCH9: + case PT_MCH10: + case PT_MCH11: + case PT_MCH12: + case PT_MCH13: + case PT_MCH14: case PT_MCH15: return TRUE; default: return FALSE; @@ -721,70 +915,122 @@ cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) // Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits static -cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) +cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) { - cmsFloat64Number* Inks = (cmsFloat64Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); cmsFloat64Number v; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + cmsUInt16Number vi; + int i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { + int index = DoSwap ? (nChan - i - 1) : i; + if (Planar) - - v = Inks[i * Stride]; + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; else - v = Inks[i]; + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start]; - wIn[i] = _cmsQuickSaturateWord(v * maximum); + vi = _cmsQuickSaturateWord(v * maximum); + + if (Reverse) + vi = REVERSE_FLAVOR_16(vi); + + wIn[index] = vi; + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; } if (T_PLANAR(info -> InputFormat)) return accum + sizeof(cmsFloat64Number); else - return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); } + + static -cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); cmsFloat32Number v; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + cmsUInt16Number vi; + int i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { + int index = DoSwap ? (nChan - i - 1) : i; + if (Planar) - - v = Inks[i * Stride]; + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; else - v = Inks[i]; + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; - wIn[i] = _cmsQuickSaturateWord(v * maximum); + vi = _cmsQuickSaturateWord(v * maximum); + + if (Reverse) + vi = REVERSE_FLAVOR_16(vi); + + wIn[index] = vi; + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; } if (T_PLANAR(info -> InputFormat)) return accum + sizeof(cmsFloat32Number); else - return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); } + + // For 1 channel, we need to duplicate data (it comes in 0..1.0 range) static -cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], +cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { @@ -792,81 +1038,131 @@ cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0); - return accum + sizeof(cmsFloat64Number); + return accum + sizeof(cmsFloat64Number); + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } //------------------------------------------------------------------------------------------------------------------- -// True float transformation. - -// For anything going from cmsFloat32Number +// For anything going from cmsFloat32Number static -cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], +cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], cmsUInt8Number* accum, cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; - for (i=0; i < nChan; i++) { + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; if (Planar) - wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; else - wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; + + v /= maximum; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; } if (T_PLANAR(info -> InputFormat)) return accum + sizeof(cmsFloat32Number); else - return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); } // For anything going from double + static -cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) +cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) { - cmsFloat64Number* Inks = (cmsFloat64Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat64Number v; + int i, start = 0; cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; - for (i=0; i < nChan; i++) { + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; if (Planar) - wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; else - wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start]; + + v /= maximum; + + wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v); + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; } if (T_PLANAR(info -> InputFormat)) return accum + sizeof(cmsFloat64Number); else - return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); } + // From Lab double to cmsFloat32Number static -cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], +cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], cmsUInt8Number* accum, cmsUInt32Number Stride) -{ +{ cmsFloat64Number* Pt = (cmsFloat64Number*) accum; if (T_PLANAR(info -> InputFormat)) { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); @@ -874,7 +1170,7 @@ cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); @@ -885,16 +1181,16 @@ cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, // From Lab double to cmsFloat32Number static -cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], +cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], cmsUInt8Number* accum, cmsUInt32Number Stride) -{ +{ cmsFloat32Number* Pt = (cmsFloat32Number*) accum; if (T_PLANAR(info -> InputFormat)) { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); @@ -902,7 +1198,7 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); @@ -912,27 +1208,28 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, } + // 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF) static -cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], +cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], cmsUInt8Number* accum, cmsUInt32Number Stride) -{ +{ cmsFloat64Number* Pt = (cmsFloat64Number*) accum; if (T_PLANAR(info -> InputFormat)) { - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); return accum + sizeof(cmsFloat64Number); } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); @@ -941,25 +1238,25 @@ cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, } static -cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], +cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], cmsUInt8Number* accum, cmsUInt32Number Stride) -{ +{ cmsFloat32Number* Pt = (cmsFloat32Number*) accum; if (T_PLANAR(info -> InputFormat)) { - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); return accum + sizeof(cmsFloat32Number); } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); - wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); @@ -967,14 +1264,16 @@ cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, } } + + // Packing routines ----------------------------------------------------------------------------------------------------------- // Generic chunky for byte static -cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -983,7 +1282,7 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt8Number* swap1; cmsUInt8Number v = 0; int i; @@ -1018,13 +1317,15 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, return output; + + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1034,7 +1335,7 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt16Number* swap1; cmsUInt16Number v = 0; int i; @@ -1074,21 +1375,30 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, return output; + + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int SwapFirst = T_SWAPFIRST(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); int i; cmsUInt8Number* Init = output; + + if (DoSwap ^ SwapFirst) { + output += T_EXTRA(info -> OutputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; @@ -1099,12 +1409,14 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, } return (Init + 1); + + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1129,7 +1441,7 @@ cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, if (SwapEndian) v = CHANGE_ENDIAN(v); - if (Reverse) + if (Reverse) v = REVERSE_FLAVOR_16(v); *(cmsUInt16Number*) output = v; @@ -1142,8 +1454,8 @@ cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, // CMYKcm (unrolled for speed) static -cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1155,13 +1467,16 @@ cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[5]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KCMYcm static -cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1173,12 +1488,15 @@ cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // CMYKcm static -cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1196,12 +1514,15 @@ cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KCMYcm static -cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1219,12 +1540,15 @@ cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1234,11 +1558,14 @@ cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[3]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1248,12 +1575,15 @@ cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1263,12 +1593,15 @@ cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // ABGR static -cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1278,11 +1611,14 @@ cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1292,11 +1628,14 @@ cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[3]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1310,11 +1649,14 @@ cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1328,12 +1670,15 @@ cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // ABGR static -cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1347,12 +1692,15 @@ cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // CMYK static -cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1366,12 +1714,15 @@ cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1380,11 +1731,14 @@ cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1394,11 +1748,14 @@ cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1410,11 +1767,14 @@ cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, output += 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1423,11 +1783,14 @@ cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1436,11 +1799,14 @@ cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, *output++ = (wOut[2] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1449,11 +1815,14 @@ cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1462,12 +1831,15 @@ cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, *output++ = (wOut[0] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1479,11 +1851,14 @@ cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1495,11 +1870,14 @@ cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1511,11 +1889,14 @@ cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1525,11 +1906,14 @@ cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info, output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1539,12 +1923,15 @@ cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info, output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1554,11 +1941,14 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1568,11 +1958,14 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Inf *output++ = (wOut[2] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1582,11 +1975,14 @@ cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1596,40 +1992,49 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info, *output++ = (wOut[0] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) -{ +{ *output++ = FROM_16_TO_8(wOut[2]); *output++ = FROM_16_TO_8(wOut[1]); *output++ = FROM_16_TO_8(wOut[0]); output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) -{ +{ *output++ = (wOut[2] & 0xFF); *output++ = (wOut[1] & 0xFF); *output++ = (wOut[0] & 0xFF); output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1642,11 +2047,14 @@ cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1659,15 +2067,18 @@ cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) -{ +{ output+= 2; *(cmsUInt16Number*) output = wOut[0]; output+= 2; @@ -1677,15 +2088,18 @@ cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) -{ +{ *(cmsUInt16Number*) output = wOut[2]; output+= 2; *(cmsUInt16Number*) output = wOut[1]; @@ -1695,47 +2109,62 @@ cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(wOut[0]); + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0])); + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(wOut[0]); output++; + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1743,11 +2172,14 @@ cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1755,12 +2187,15 @@ cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1768,11 +2203,14 @@ cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1780,12 +2218,15 @@ cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1793,31 +2234,37 @@ cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info, output+= 4; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { - output += 2; + output += 2; *(cmsUInt16Number*) output = wOut[0]; output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // Unencoded Float values -- don't try optimize speed static -cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, +cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, register cmsUInt32Number Stride) { - if (T_PLANAR(Info -> OutputFormat)) { + if (T_PLANAR(info -> OutputFormat)) { cmsCIELab Lab; cmsFloat64Number* Out = (cmsFloat64Number*) output; @@ -1832,14 +2279,43 @@ cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info, else { cmsLabEncoded2Float((cmsCIELab*) output, wOut); - return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number)); } +} + +static +cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsLabEncoded2Float(&Lab, wOut); + + if (T_PLANAR(info -> OutputFormat)) { + + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + Out[0] = (cmsFloat32Number)Lab.L; + Out[Stride] = (cmsFloat32Number)Lab.a; + Out[Stride*2] = (cmsFloat32Number)Lab.b; + + return output + sizeof(cmsFloat32Number); + } + else { + + ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L; + ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a; + ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b; + + return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number); + } } static -cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { @@ -1849,7 +2325,7 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, cmsFloat64Number* Out = (cmsFloat64Number*) output; cmsXYZEncoded2Float(&XYZ, wOut); - Out[0] = XYZ.X; + Out[0] = XYZ.X; Out[Stride] = XYZ.Y; Out[Stride*2] = XYZ.Z; @@ -1865,96 +2341,168 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, } static -cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) +cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) { - cmsFloat64Number* Inks = (cmsFloat64Number*) output; - int nChan = T_CHANNELS(Info -> OutputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(Info ->InputFormat) ? 655.35 : 65535.0; - if (T_PLANAR(Info -> OutputFormat)) { - for (i=0; i < nChan; i++) { + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); - Inks[i*Stride] = wOut[i] / maximum; - } + Out[0] = (cmsFloat32Number) XYZ.X; + Out[Stride] = (cmsFloat32Number) XYZ.Y; + Out[Stride*2] = (cmsFloat32Number) XYZ.Z; - return output + sizeof(cmsFloat64Number); - } + return output + sizeof(cmsFloat32Number); + + } else { - for (i=0; i < nChan; i++) { + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); - Inks[i] = wOut[i] / maximum; - } + Out[0] = (cmsFloat32Number) XYZ.X; + Out[1] = (cmsFloat32Number) XYZ.Y; + Out[2] = (cmsFloat32Number) XYZ.Z; - - return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number); + return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); } - } static -cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], +cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) output; - int nChan = T_CHANNELS(Info -> OutputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0; + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*) output; + int i, start = 0; - if (T_PLANAR(Info -> OutputFormat)) { + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i=0; i < nChan; i++) { - Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum); - } + int index = DoSwap ? (nChan - i - 1) : i; - return output + sizeof(cmsFloat32Number); - } - else { + v = (cmsFloat64Number) wOut[index] / maximum; - for (i=0; i < nChan; i++) { + if (Reverse) + v = maximum - v; - Inks[i] = (cmsFloat32Number) (wOut[i] / maximum); - } - - - return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number); + if (Planar) + ((cmsFloat64Number*) output)[(i + start) * Stride]= v; + else + ((cmsFloat64Number*) output)[i + start] = v; } + if (!ExtraFirst) { + output += Extra * sizeof(cmsFloat64Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); + *swap1 = v; + } + + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + nChan * sizeof(cmsFloat64Number); + } +static +cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat32Number* swap1 = (cmsFloat32Number*) output; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat64Number) wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v; + else + ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsFloat32Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number) v; + } + + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + nChan * sizeof(cmsFloat32Number); +} + + + // -------------------------------------------------------------------------------------------------------- static -cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) +cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) { int nChan = T_CHANNELS(info -> OutputFormat); int DoSwap = T_DOSWAP(info ->OutputFormat); int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat32Number* swap1; + cmsFloat32Number* swap1 = (cmsFloat32Number*) output; cmsFloat64Number v = 0; - int i; + int i, start = 0; - swap1 = (cmsFloat32Number*) output; - - if (ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { @@ -1965,42 +2513,48 @@ cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, if (Reverse) v = maximum - v; - *(cmsFloat32Number*) output = (cmsFloat32Number) v; - - output += sizeof(cmsFloat32Number); + if (Planar) + ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v; + else + ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; } if (!ExtraFirst) { output += Extra * sizeof(cmsFloat32Number); } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); *swap1 = (cmsFloat32Number) v; } - - return output; + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + nChan * sizeof(cmsFloat32Number); } static -cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) +cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); - int i; - cmsUInt8Number* Init = output; + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*) output; + int i, start = 0; - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number); - } + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { @@ -2008,111 +2562,43 @@ cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, v = wOut[index] * maximum; - if (Reverse) - v = maximum - v; - - *(cmsFloat32Number*) output = (cmsFloat32Number) v; - output += (Stride * sizeof(cmsFloat32Number)); - } - - return (Init + sizeof(cmsFloat32Number)); -} - - -static -cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; - cmsFloat64Number* swap1; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v = 0; - int i; - - swap1 = (cmsFloat64Number*) output; - - if (ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] * maximum; - if (Reverse) v = maximum - v; - *(cmsFloat64Number*) output = v; - - output += sizeof(cmsFloat64Number); + if (Planar) + ((cmsFloat64Number*) output)[(i + start) * Stride] = v; + else + ((cmsFloat64Number*) output)[i + start] = v; } if (!ExtraFirst) { output += Extra * sizeof(cmsFloat64Number); } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); *swap1 = v; } - return output; -} + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + nChan * sizeof(cmsFloat64Number); -static -cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); - int i; - cmsUInt8Number* Init = output; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v; - - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] * maximum; - - if (Reverse) - v = maximum - v; - - *(cmsFloat64Number*) output = v; - output += (Stride * sizeof(cmsFloat64Number)); - } - - return (Init + sizeof(cmsFloat64Number)); } + static -cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], +cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], cmsUInt8Number* output, cmsUInt32Number Stride) -{ +{ cmsFloat32Number* Out = (cmsFloat32Number*) output; if (T_PLANAR(Info -> OutputFormat)) { @@ -2129,17 +2615,18 @@ cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); - return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); } } + static -cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], +cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], cmsUInt8Number* output, cmsUInt32Number Stride) -{ +{ cmsFloat64Number* Out = (cmsFloat64Number*) output; if (T_PLANAR(Info -> OutputFormat)) { @@ -2156,7 +2643,7 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); - return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); } } @@ -2164,11 +2651,11 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, // From 0..1 range to 0..MAX_ENCODEABLE_XYZ static -cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], +cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], cmsUInt8Number* output, cmsUInt32Number Stride) -{ +{ cmsFloat32Number* Out = (cmsFloat32Number*) output; if (T_PLANAR(Info -> OutputFormat)) { @@ -2185,19 +2672,18 @@ cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); } } - // Same, but convert to double static -cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, - cmsFloat32Number wOut[], +cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], cmsUInt8Number* output, cmsUInt32Number Stride) -{ +{ cmsFloat64Number* Out = (cmsFloat64Number*) output; if (T_PLANAR(Info -> OutputFormat)) { @@ -2214,12 +2700,229 @@ cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); - return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); } } +// ---------------------------------------------------------------------------------------------------------------- + +#ifndef CMS_NO_HALF_SUPPORT + +// Decodes an stream of half floats to wIn[] described by input format + +static +cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F; + + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); + else + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; + + if (Reverse) v = maximum - v; + + wIn[index] = _cmsQuickSaturateWord(v * maximum); + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsUInt16Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt16Number); +} + +// Decodes an stream of half floats to wIn[] described by input format + +static +cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; + + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); + else + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; + + v /= maximum; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsUInt16Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + +static +cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F; + cmsFloat32Number v = 0; + cmsUInt16Number* swap1 = (cmsUInt16Number*) output; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat32Number) wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v); + else + ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half(v); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); + *swap1 = _cmsFloat2Half(v); + } + + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + nChan * sizeof(cmsUInt16Number); +} + + + +static +cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F; + cmsUInt16Number* swap1 = (cmsUInt16Number*) output; + cmsFloat32Number v = 0; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v ); + else + ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( v ); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); + *swap1 = (cmsUInt16Number) _cmsFloat2Half( v ); + } + + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + nChan * sizeof(cmsUInt16Number); +} + +#endif + // ---------------------------------------------------------------------------------------------------------------- @@ -2229,12 +2932,19 @@ static cmsFormatters16 InputFormatters16[] = { // ---------------------------- ------------------------------------ ---------------------------- { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16}, { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, - { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, + { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYSWAP|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYEXTRA|ANYSWAP|ANYSPACE, UnrollHalfTo16}, +#endif - - { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte}, + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte}, { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Unroll1ByteSkip1}, { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2), ANYSPACE, Unroll1ByteSkip2}, { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll1ByteReversed}, @@ -2249,15 +2959,20 @@ static cmsFormatters16 InputFormatters16[] = { { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Unroll3BytesSkip1SwapSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, - { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST| + ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word}, { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed}, @@ -2271,13 +2986,13 @@ static cmsFormatters16 InputFormatters16[] = { { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3WordsSkip1SwapFirst}, { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSkip1Swap}, { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll4WordsReverse}, - { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst}, - { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords }, - { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords}, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, }; @@ -2288,11 +3003,19 @@ static cmsFormattersFloat InputFormattersFloat[] = { // ---------------------------- ------------------------------------ ---------------------------- { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleToFloat}, { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatToFloat}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleToFloat}, { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat}, - { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, - { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, + + { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollHalfToFloat}, +#endif }; @@ -2303,9 +3026,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number cmsUInt32Number i; cmsFormatter fr; + switch (dwFlags) { - if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) { - + case CMS_PACK_FLAGS_16BITS: { for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) { cmsFormatters16* f = InputFormatters16 + i; @@ -2315,7 +3038,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number } } } - else { + break; + + case CMS_PACK_FLAGS_FLOAT: { for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { cmsFormattersFloat* f = InputFormattersFloat + i; @@ -2325,6 +3050,11 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number } } } + break; + + default:; + + } fr.Fmt16 = NULL; return fr; @@ -2336,10 +3066,20 @@ static cmsFormatters16 OutputFormatters16[] = { { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFrom16}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, - { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, - { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16}, + + { FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackHalfFrom16}, +#endif + + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte}, { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack1ByteSkip1}, { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1ByteSkip1SwapFirst}, @@ -2353,9 +3093,9 @@ static cmsFormatters16 OutputFormatters16[] = { { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1Optimized}, { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirstOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapSwapFirstOptimized}, - { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapOptimized}, { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesSwapOptimized}, @@ -2364,7 +3104,7 @@ static cmsFormatters16 OutputFormatters16[] = { { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Pack3Bytes}, { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1}, { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst}, { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap}, { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap}, @@ -2372,12 +3112,12 @@ static cmsFormatters16 OutputFormatters16[] = { { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes}, { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse}, - { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, - { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word}, { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1}, @@ -2391,18 +3131,18 @@ static cmsFormatters16 OutputFormatters16[] = { { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3WordsAndSkip1Swap}, { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapSwapFirst}, { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Pack4Words}, { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack4WordsReverse}, - { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap}, { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack4WordsBigEndian}, { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words}, { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap}, - { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords} }; @@ -2413,39 +3153,36 @@ static cmsFormattersFloat OutputFormattersFloat[] = { // ---------------------------- --------------------------------------------------- ---------------------------- { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFromFloat}, { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFromFloat}, + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, - { FLOAT_SH(1)|BYTES_SH(4), - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyFloatsFromFloat }, - { FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarFloatsFromFloat}, - { FLOAT_SH(1)|BYTES_SH(0), - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyDoublesFromFloat }, - { FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarDoublesFromFloat}, + + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, + { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, +#endif + }; // Bit fields set to one in the mask are not compared +static cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) { cmsUInt32Number i; cmsFormatter fr; - if (dwFlags & CMS_PACK_FLAGS_FLOAT) { + switch (dwFlags) + { - for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { - cmsFormattersFloat* f = OutputFormattersFloat + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.FmtFloat = f ->Frm; - return fr; - } - } - - } - else { + case CMS_PACK_FLAGS_16BITS: { for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) { cmsFormatters16* f = OutputFormatters16 + i; @@ -2455,6 +3192,24 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe return fr; } } + } + break; + + case CMS_PACK_FLAGS_FLOAT: { + + for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + cmsFormattersFloat* f = OutputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + } + break; + + default:; + } fr.Fmt16 = NULL; @@ -2469,49 +3224,107 @@ typedef struct _cms_formatters_factory_list { } cmsFormattersFactoryList; -static cmsFormattersFactoryList* FactoryList = NULL; +_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupFormatterFactoryList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsFormattersPluginChunkType newHead = { NULL }; + cmsFormattersFactoryList* entry; + cmsFormattersFactoryList* Anterior = NULL; + _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->FactoryList; + entry != NULL; + entry = entry ->Next) { + + cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.FactoryList == NULL) + newHead.FactoryList = newEntry; + } + + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); +} + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate the LIST + DupFormatterFactoryList(ctx, src); + } + else { + static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); + } +} + // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsFormattersFactoryList* fl ; - // Reset + // Reset to built-in defaults if (Data == NULL) { - FactoryList = NULL; + ctx ->FactoryList = NULL; return TRUE; } - - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList)); + + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); if (fl == NULL) return FALSE; fl ->Factory = Plugin ->FormattersFactory; - fl ->Next = FactoryList; - FactoryList = fl; + fl ->Next = ctx -> FactoryList; + ctx ->FactoryList = fl; return TRUE; } -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 - cmsFormatterDirection Dir, - cmsUInt32Number dwFlags) // Float or 16 bits +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsFormattersFactoryList* f; - for (f = FactoryList; f != NULL; f = f ->Next) { + for (f =ctx->FactoryList; f != NULL; f = f ->Next) { cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); if (fn.Fmt16 != NULL) return fn; } // Revert to default - if (Dir == cmsFormatterInput) + if (Dir == cmsFormatterInput) return _cmsGetStockInputFormatter(Type, dwFlags); - else + else return _cmsGetStockOutputFormatter(Type, dwFlags); } @@ -2533,7 +3346,7 @@ cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type) // Build a suitable formatter for the colorspace of this profile cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) { - + cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile); cmsUInt32Number ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); @@ -2546,7 +3359,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfil // Build a suitable formatter for the colorspace of this profile cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) { - + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); int ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace); cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); diff --git a/thirdparty/liblcms2/src/cmspcs.c b/thirdparty/liblcms2/src/cmspcs.c index 8dd1c22c..102cd7d2 100644 --- a/thirdparty/liblcms2/src/cmspcs.c +++ b/thirdparty/liblcms2/src/cmspcs.c @@ -3,22 +3,22 @@ // Little Color Management System // Copyright (c) 1998-2010 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -114,7 +114,7 @@ cmsFloat64Number f(cmsFloat64Number t) if (t <= Limit) return (841.0/108.0) * t + (16.0/116.0); else - return pow(t, 1.0/3.0); + return pow(t, 1.0/3.0); } static @@ -135,7 +135,7 @@ void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cms { cmsFloat64Number fx, fy, fz; - if (WhitePoint == NULL) + if (WhitePoint == NULL) WhitePoint = cmsD50_XYZ(); fx = f(xyz->X / WhitePoint->X); @@ -153,7 +153,7 @@ void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cm { cmsFloat64Number x, y, z; - if (WhitePoint == NULL) + if (WhitePoint == NULL) WhitePoint = cmsD50_XYZ(); y = (Lab-> L + 16.0) / 116.0; @@ -169,26 +169,26 @@ void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cm static cmsFloat64Number L2float2(cmsUInt16Number v) { - return (cmsFloat64Number) v / 652.800; + return (cmsFloat64Number) v / 652.800; } // the a/b part static cmsFloat64Number ab2float2(cmsUInt16Number v) -{ - return ((cmsFloat64Number) v / 256.0) - 128.0; +{ + return ((cmsFloat64Number) v / 256.0) - 128.0; } static cmsUInt16Number L2Fix2(cmsFloat64Number L) { - return _cmsQuickSaturateWord(L * 652.8); + return _cmsQuickSaturateWord(L * 652.8); } static cmsUInt16Number ab2Fix2(cmsFloat64Number ab) { - return _cmsQuickSaturateWord((ab + 128.0) * 256.0); + return _cmsQuickSaturateWord((ab + 128.0) * 256.0); } @@ -249,7 +249,7 @@ void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* f Lab.L = Clamp_L_doubleV2(fLab ->L); Lab.a = Clamp_ab_doubleV2(fLab ->a); Lab.b = Clamp_ab_doubleV2(fLab ->b); - + wLab[0] = L2Fix2(Lab.L); wLab[1] = ab2Fix2(Lab.a); wLab[2] = ab2Fix2(Lab.b); @@ -274,7 +274,7 @@ cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab) return ab; } -static +static cmsUInt16Number L2Fix4(cmsFloat64Number L) { return _cmsQuickSaturateWord(L * 655.35); @@ -289,11 +289,11 @@ cmsUInt16Number ab2Fix4(cmsFloat64Number ab) void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab) { cmsCIELab Lab; - + Lab.L = Clamp_L_doubleV4(fLab ->L); Lab.a = Clamp_ab_doubleV4(fLab ->a); Lab.b = Clamp_ab_doubleV4(fLab ->b); - + wLab[0] = L2Fix4(Lab.L); wLab[1] = ab2Fix4(Lab.a); wLab[2] = ab2Fix4(Lab.b); @@ -317,15 +317,15 @@ cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) h = 0; else h = atan2(a, b); - + h *= (180. / M_PI); - - while (h > 360.) + + while (h > 360.) h -= 360.; - + while ( h < 0) h += 360.; - + return h; } @@ -334,7 +334,7 @@ cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) static cmsFloat64Number Sqr(cmsFloat64Number v) { - return v * v; + return v * v; } // From cylindrical coordinates. No check is performed, then negative values are allowed void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab) @@ -352,13 +352,13 @@ void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh) Lab -> L = LCh -> L; Lab -> a = LCh -> C * cos(h); - Lab -> b = LCh -> C * sin(h); + Lab -> b = LCh -> C * sin(h); } // In XYZ All 3 components are encoded using 1.15 fixed point static cmsUInt16Number XYZ2Fix(cmsFloat64Number d) -{ +{ return _cmsQuickSaturateWord(d * 32768.0); } @@ -370,7 +370,7 @@ void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ xyz.Y = fXYZ -> Y; xyz.Z = fXYZ -> Z; - // Clamp to encodeable values. + // Clamp to encodeable values. if (xyz.Y <= 0) { xyz.X = 0; @@ -378,19 +378,19 @@ void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ xyz.Z = 0; } - if (xyz.X > MAX_ENCODEABLE_XYZ) + if (xyz.X > MAX_ENCODEABLE_XYZ) xyz.X = MAX_ENCODEABLE_XYZ; if (xyz.X < 0) xyz.X = 0; - if (xyz.Y > MAX_ENCODEABLE_XYZ) + if (xyz.Y > MAX_ENCODEABLE_XYZ) xyz.Y = MAX_ENCODEABLE_XYZ; if (xyz.Y < 0) xyz.Y = 0; - if (xyz.Z > MAX_ENCODEABLE_XYZ) + if (xyz.Z > MAX_ENCODEABLE_XYZ) xyz.Z = MAX_ENCODEABLE_XYZ; if (xyz.Z < 0) @@ -399,7 +399,7 @@ void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ XYZ[0] = XYZ2Fix(xyz.X); XYZ[1] = XYZ2Fix(xyz.Y); - XYZ[2] = XYZ2Fix(xyz.Z); + XYZ[2] = XYZ2Fix(xyz.Z); } @@ -422,7 +422,7 @@ void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3] fXYZ -> X = XYZ2float(XYZ[0]); fXYZ -> Y = XYZ2float(XYZ[1]); fXYZ -> Z = XYZ2float(XYZ[2]); -} +} // Returns dE on two Lab values @@ -438,7 +438,7 @@ cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab } -// Return the CIE94 Delta E +// Return the CIE94 Delta E cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) { cmsCIELCh LCh1, LCh2; @@ -452,7 +452,7 @@ cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab dC = fabs(LCh1.C - LCh2.C); dE = cmsDeltaE(Lab1, Lab2); - + dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC); if (dhsq < 0) dh = 0; @@ -463,7 +463,7 @@ cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab sc = 1.0 + (0.048 * c12); sh = 1.0 + (0.014 * c12); - + return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh)); } @@ -513,7 +513,7 @@ cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521; g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000)); - t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- + t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- 0.040*cos((2*Aveh-136)/(180/M_PI))+ 0.070*cos((3*Aveh-31)/(180/M_PI))+ 0.049*cos((4*Aveh+114)/(180/M_PI))- @@ -546,27 +546,27 @@ cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* cmsLab2LCh(&LCh1, Lab1); cmsLab2LCh(&LCh2, Lab2); - + dL = Lab2->L-Lab1->L; dC = LCh2.C-LCh1.C; dE = cmsDeltaE(Lab1, Lab2); - if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) + if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC)); else dh =0; - if ((LCh1.h > 164) && (LCh1.h < 345)) + if ((LCh1.h > 164) && (LCh1.h < 345)) t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI)))); - else + else t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI)))); sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638; sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L); - + if (Lab1->L<16) - sl = 0.511; + sl = 0.511; f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900)); sh = sc*(t*f+1-f); @@ -575,7 +575,7 @@ cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* return cmc; } -// dE2000 The weightings KL, KC and KH can be modified to reflect the relative +// dE2000 The weightings KL, KC and KH can be modified to reflect the relative // importance of lightness, chroma and hue in different industrial applications cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh) @@ -595,25 +595,25 @@ cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIEL cmsFloat64Number a_p = (1 + G ) * a1; cmsFloat64Number b_p = b1; cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p)); - cmsFloat64Number h_p = atan2deg(b_p, a_p); - + cmsFloat64Number h_p = atan2deg(b_p, a_p); + cmsFloat64Number a_ps = (1 + G) * as; cmsFloat64Number b_ps = bs; cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); cmsFloat64Number h_ps = atan2deg(b_ps, a_ps); - + cmsFloat64Number meanC_p =(C_p + C_ps) / 2; cmsFloat64Number hps_plus_hp = h_ps + h_p; cmsFloat64Number hps_minus_hp = h_ps - h_p; - cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : - (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : + cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : + (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : (hps_plus_hp - 360)/2; cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : - (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : + (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : (hps_minus_hp); cmsFloat64Number delta_L = (Ls - L1); cmsFloat64Number delta_C = (C_ps - C_p ); @@ -621,9 +621,9 @@ cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIEL cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2); - cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) - + 0.24 * cos(RADIANS(2*meanh_p)) - + 0.32 * cos(RADIANS(3*meanh_p + 6)) + cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) + + 0.24 * cos(RADIANS(2*meanh_p)) + + 0.32 * cos(RADIANS(3*meanh_p + 6)) - 0.2 * cos(RADIANS(4*meanh_p - 63)); cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) ); @@ -637,9 +637,9 @@ cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIEL cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc; - cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + - Sqr(delta_C/(Sc * Kc)) + - Sqr(delta_H/(Sh * Kh)) + + cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + + Sqr(delta_C/(Sc * Kc)) + + Sqr(delta_H/(Sh * Kh)) + Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh))); return deltaE00; @@ -662,41 +662,41 @@ int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsU // HighResPrecalc is maximum resolution if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { - if (nChannels > 4) + if (nChannels > 4) return 7; // 7 for Hifi if (nChannels == 4) // 23 for CMYK return 23; - - return 49; // 49 for RGB and others + + return 49; // 49 for RGB and others } // LowResPrecal is lower resolution if (dwFlags & cmsFLAGS_LOWRESPRECALC) { - - if (nChannels > 4) + + if (nChannels > 4) return 6; // 6 for more than 4 channels - if (nChannels == 1) + if (nChannels == 1) return 33; // For monochrome return 17; // 17 for remaining } // Default values - if (nChannels > 4) + if (nChannels > 4) return 7; // 7 for Hifi if (nChannels == 4) return 17; // 17 for CMYK - return 33; // 33 for RGB + return 33; // 33 for RGB } -cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, - cmsUInt16Number **White, +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, cmsUInt16Number **Black, cmsUInt32Number *nOutputs) { @@ -719,7 +719,7 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, if (Black) *Black = Grayblack; if (nOutputs) *nOutputs = 1; return TRUE; - + case cmsSigRgbData: if (White) *White = RGBwhite; if (Black) *Black = RGBblack; if (nOutputs) *nOutputs = 3; @@ -746,7 +746,7 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, return FALSE; } - + // Several utilities ------------------------------------------------------- @@ -799,9 +799,9 @@ cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation) int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) -{ +{ switch (ProfileSpace) { - + case cmsSigGrayData: return PT_GRAY; case cmsSigRgbData: return PT_RGB; case cmsSigCmyData: return PT_CMY; @@ -814,52 +814,52 @@ int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) case cmsSigHsvData: return PT_HSV; case cmsSigHlsData: return PT_HLS; case cmsSigYxyData: return PT_Yxy; - + case cmsSig1colorData: case cmsSigMCH1Data: return PT_MCH1; - + case cmsSig2colorData: case cmsSigMCH2Data: return PT_MCH2; - + case cmsSig3colorData: case cmsSigMCH3Data: return PT_MCH3; - + case cmsSig4colorData: case cmsSigMCH4Data: return PT_MCH4; - + case cmsSig5colorData: case cmsSigMCH5Data: return PT_MCH5; - + case cmsSig6colorData: case cmsSigMCH6Data: return PT_MCH6; - + case cmsSigMCH7Data: case cmsSig7colorData:return PT_MCH7; - + case cmsSigMCH8Data: case cmsSig8colorData:return PT_MCH8; - + case cmsSigMCH9Data: case cmsSig9colorData:return PT_MCH9; - + case cmsSigMCHAData: case cmsSig10colorData:return PT_MCH10; - + case cmsSigMCHBData: case cmsSig11colorData:return PT_MCH11; - + case cmsSigMCHCData: case cmsSig12colorData:return PT_MCH12; - + case cmsSigMCHDData: case cmsSig13colorData:return PT_MCH13; - + case cmsSigMCHEData: case cmsSig14colorData:return PT_MCH14; - + case cmsSigMCHFData: case cmsSig15colorData:return PT_MCH15; - + default: return (cmsColorSpaceSignature) (-1); } } @@ -869,31 +869,36 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) { switch (ColorSpace) { + case cmsSigMCH1Data: + case cmsSig1colorData: case cmsSigGrayData: return 1; + case cmsSigMCH2Data: case cmsSig2colorData: return 2; - + case cmsSigXYZData: case cmsSigLabData: case cmsSigLuvData: case cmsSigYCbCrData: case cmsSigYxyData: - case cmsSigRgbData: + case cmsSigRgbData: case cmsSigHsvData: case cmsSigHlsData: - case cmsSigCmyData: + case cmsSigCmyData: + case cmsSigMCH3Data: case cmsSig3colorData: return 3; - + case cmsSigLuvKData: case cmsSigCmykData: + case cmsSigMCH4Data: case cmsSig4colorData: return 4; case cmsSigMCH5Data: - case cmsSig5colorData: return 5; + case cmsSig5colorData: return 5; - case cmsSigMCH6Data: + case cmsSigMCH6Data: case cmsSig6colorData: return 6; - + case cmsSigMCH7Data: case cmsSig7colorData: return 7; @@ -908,7 +913,7 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) case cmsSigMCHBData: case cmsSig11colorData: return 11; - + case cmsSigMCHCData: case cmsSig12colorData: return 12; diff --git a/thirdparty/liblcms2/src/cmsplugin.c b/thirdparty/liblcms2/src/cmsplugin.c index 1fa5ff4e..317e33e2 100644 --- a/thirdparty/liblcms2/src/cmsplugin.c +++ b/thirdparty/liblcms2/src/cmsplugin.c @@ -3,22 +3,22 @@ // Little Color Management System // Copyright (c) 1998-2010 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -44,7 +44,7 @@ cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word) tmp = pByte[0]; pByte[0] = pByte[1]; pByte[1] = tmp; -#endif +#endif return Word; } @@ -76,12 +76,12 @@ cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord) // 1 2 3 4 5 6 7 8 // 8 7 6 5 4 3 2 1 -void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord) +void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord) { - + #ifndef CMS_USE_BIG_ENDIAN - - cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord; + + cmsUInt8Number* pIn = (cmsUInt8Number*) QWord; cmsUInt8Number* pOut = (cmsUInt8Number*) Result; _cmsAssert(Result != NULL); @@ -91,15 +91,19 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number Q pOut[5] = pIn[2]; pOut[4] = pIn[3]; pOut[3] = pIn[4]; - pOut[2] = pIn[5]; + pOut[2] = pIn[5]; pOut[1] = pIn[6]; pOut[0] = pIn[7]; #else - _cmsAssert(Result != NULL); - *Result = QWord; +# ifdef CMS_DONT_USE_INT64 + (*Result)[0] = QWord[0]; + (*Result)[1] = QWord[1]; +# else + *Result = *QWord; +# endif #endif } @@ -110,8 +114,8 @@ cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) + return FALSE; if (n != NULL) *n = tmp; return TRUE; @@ -123,8 +127,8 @@ cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) + return FALSE; if (n != NULL) *n = _cmsAdjustEndianess16(tmp); return TRUE; @@ -155,8 +159,8 @@ cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; if (n != NULL) *n = _cmsAdjustEndianess32(tmp); return TRUE; @@ -168,8 +172,8 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) + return FALSE; if (n != NULL) { @@ -186,10 +190,10 @@ cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) + return FALSE; - if (n != NULL) _cmsAdjustEndianess64(n, tmp); + if (n != NULL) _cmsAdjustEndianess64(n, &tmp); return TRUE; } @@ -200,8 +204,8 @@ cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) - return FALSE; + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; if (n != NULL) { *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp)); @@ -250,9 +254,9 @@ cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n) { _cmsAssert(io != NULL); - if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) + return FALSE; + return TRUE; } @@ -263,9 +267,9 @@ cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n) _cmsAssert(io != NULL); tmp = _cmsAdjustEndianess16(n); - if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) + return FALSE; + return TRUE; } @@ -290,9 +294,9 @@ cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) _cmsAssert(io != NULL); tmp = _cmsAdjustEndianess32(n); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + return TRUE; } @@ -305,22 +309,22 @@ cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) tmp = *(cmsUInt32Number*) &n; tmp = _cmsAdjustEndianess32(tmp); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + return TRUE; } -cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n) +cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) { cmsUInt64Number tmp; _cmsAssert(io != NULL); _cmsAdjustEndianess64(&tmp, n); - if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) + return FALSE; + return TRUE; } @@ -331,16 +335,16 @@ cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n _cmsAssert(io != NULL); tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n)); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) - return FALSE; - + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + return TRUE; } cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) { cmsEncodedXYZNumber xyz; - + _cmsAssert(io != NULL); _cmsAssert(XYZ != NULL); @@ -365,7 +369,7 @@ cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) { cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val); - return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); + return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); } // from Fixed point 15.16 to double @@ -386,13 +390,13 @@ cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) return sign * floater; } -// from double to Fixed point 15.16 +// from double to Fixed point 15.16 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v) { return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5)); } -// Date/Time functions +// Date/Time functions void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest) { @@ -431,7 +435,7 @@ cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io) _cmsAssert(io != NULL); - if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) + if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) return (cmsTagTypeSignature) 0; return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig); @@ -454,7 +458,7 @@ cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io) cmsUInt8Number Buffer[4]; cmsUInt32Number NextAligned, At; cmsUInt32Number BytesToNextAlignedPos; - + _cmsAssert(io != NULL); At = io -> Tell(io); @@ -502,7 +506,7 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) if (len < 0) return FALSE; // Truncated, which is a fatal error for us rc = io ->Write(io, len, Buffer); - + va_end(args); return rc; @@ -511,80 +515,102 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) // Plugin memory management ------------------------------------------------------------------------------------------------- -static _cmsSubAllocator* PluginPool = NULL; - // Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsUInt32Number size) +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) { - if (PluginPool == NULL) - PluginPool = _cmsCreateSubAlloc(0, 4*1024); + struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); - return _cmsSubAlloc(PluginPool, size); + if (ctx ->MemPool == NULL) { + + if (ContextID == NULL) { + + ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); + } + else { + cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); + return NULL; + } + } + + return _cmsSubAlloc(ctx->MemPool, size); } // Main plug-in dispatcher cmsBool CMSEXPORT cmsPlugin(void* Plug_in) +{ + return cmsPluginTHR(NULL, Plug_in); +} + +cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) { cmsPluginBase* Plugin; - for (Plugin = (cmsPluginBase*) Plug_in; - Plugin != NULL; + for (Plugin = (cmsPluginBase*) Plug_in; + Plugin != NULL; Plugin = Plugin -> Next) { if (Plugin -> Magic != cmsPluginMagicNumber) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); return FALSE; } - if (Plugin ->ExpectedVersion > LCMS_VERSION) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", - Plugin ->ExpectedVersion, LCMS_VERSION); - return FALSE; - } + if (Plugin ->ExpectedVersion > LCMS_VERSION) { + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + Plugin ->ExpectedVersion, LCMS_VERSION); + return FALSE; + } switch (Plugin -> Type) { case cmsPluginMemHandlerSig: - if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; break; case cmsPluginInterpolationSig: - if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; + if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; break; - + case cmsPluginTagTypeSig: - if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE; + if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE; break; - + case cmsPluginTagSig: - if (!_cmsRegisterTagPlugin(Plugin)) return FALSE; + if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE; break; case cmsPluginFormattersSig: - if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE; + if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE; break; case cmsPluginRenderingIntentSig: - if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE; + if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE; break; case cmsPluginParametricCurveSig: - if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE; + if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE; break; case cmsPluginMultiProcessElementSig: - if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE; break; case cmsPluginOptimizationSig: - if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; + if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginTransformSig: + if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginMutexSig: + if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; break; default: - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); return FALSE; - } + } } // Keep a reference to the plug-in @@ -595,18 +621,337 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in) // Revert all plug-ins to default void CMSEXPORT cmsUnregisterPlugins(void) { - _cmsRegisterMemHandlerPlugin(NULL); - _cmsRegisterInterpPlugin(NULL); - _cmsRegisterTagTypePlugin(NULL); - _cmsRegisterTagPlugin(NULL); - _cmsRegisterFormattersPlugin(NULL); - _cmsRegisterRenderingIntentPlugin(NULL); - _cmsRegisterParametricCurvesPlugin(NULL); - _cmsRegisterMultiProcessElementPlugin(NULL); - _cmsRegisterOptimizationPlugin(NULL); - - if (PluginPool != NULL) - _cmsSubAllocDestroy(PluginPool); - - PluginPool = NULL; + cmsUnregisterPluginsTHR(NULL); } + + +// The Global storage for system context. This is the one and only global variable +// pointers structure. All global vars are referenced here. +static struct _cmsContext_struct globalContext = { + + NULL, // Not in the linked list + NULL, // No suballocator + { + NULL, // UserPtr, + &_cmsLogErrorChunk, // Logger, + &_cmsAlarmCodesChunk, // AlarmCodes, + &_cmsAdaptationStateChunk, // AdaptationState, + &_cmsMemPluginChunk, // MemPlugin, + &_cmsInterpPluginChunk, // InterpPlugin, + &_cmsCurvesPluginChunk, // CurvesPlugin, + &_cmsFormattersPluginChunk, // FormattersPlugin, + &_cmsTagTypePluginChunk, // TagTypePlugin, + &_cmsTagPluginChunk, // TagPlugin, + &_cmsIntentsPluginChunk, // IntentPlugin, + &_cmsMPETypePluginChunk, // MPEPlugin, + &_cmsOptimizationPluginChunk, // OptimizationPlugin, + &_cmsTransformPluginChunk, // TransformPlugin, + &_cmsMutexPluginChunk // MutexPlugin + }, + + { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 +}; + + +// The context pool (linked list head) +static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; +static struct _cmsContext_struct* _cmsContextPoolHead = NULL; + +// Internal, get associated pointer, with guessing. Never returns NULL. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) +{ + struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct* ctx; + + + // On 0, use global settings + if (id == NULL) + return &globalContext; + + // Search + for (ctx = _cmsContextPoolHead; + ctx != NULL; + ctx = ctx ->Next) { + + // Found it? + if (id == ctx) + return ctx; // New-style context, + } + + return &globalContext; +} + + +// Internal: get the memory area associanted with each context client +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) +{ + struct _cmsContext_struct* ctx; + void *ptr; + + if (mc < 0 || mc >= MemoryClientMax) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); + return NULL; + } + + ctx = _cmsGetContext(ContextID); + ptr = ctx ->chunks[mc]; + + if (ptr != NULL) + return ptr; + + // A null ptr means no special settings for that context, and this + // reverts to Context0 globals + return globalContext.chunks[mc]; +} + + +// This function returns the given context its default pristine state, +// as no plug-ins were declared. There is no way to unregister a single +// plug-in, as a single call to cmsPluginTHR() function may register +// many different plug-ins simultaneously, then there is no way to +// identify which plug-in to unregister. +void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) +{ + _cmsRegisterMemHandlerPlugin(ContextID, NULL); + _cmsRegisterInterpPlugin(ContextID, NULL); + _cmsRegisterTagTypePlugin(ContextID, NULL); + _cmsRegisterTagPlugin(ContextID, NULL); + _cmsRegisterFormattersPlugin(ContextID, NULL); + _cmsRegisterRenderingIntentPlugin(ContextID, NULL); + _cmsRegisterParametricCurvesPlugin(ContextID, NULL); + _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); + _cmsRegisterOptimizationPlugin(ContextID, NULL); + _cmsRegisterTransformPlugin(ContextID, NULL); + _cmsRegisterMutexPlugin(ContextID, NULL); +} + + +// Returns the memory manager plug-in, if any, from the Plug-in bundle +static +cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) PluginBundle; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic == cmsPluginMagicNumber && + Plugin -> ExpectedVersion <= LCMS_VERSION && + Plugin -> Type == cmsPluginMemHandlerSig) { + + // Found! + return (cmsPluginMemHandler*) Plugin; + } + } + + // Nope, revert to defaults + return NULL; +} + + +// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) +{ + struct _cmsContext_struct* ctx; + struct _cmsContext_struct fakeContext; + + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); + + fakeContext.chunks[UserPtr] = UserData; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Create the context structure. + ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened! + + // Init the structure and the memory manager + memset(ctx, 0, sizeof(struct _cmsContext_struct)); + + // Keep memory manager + memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); + + // Maintain the linked list (with proper locking) + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = UserData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + // Now we can allocate the pool by using default memory manager + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + _cmsAllocLogErrorChunk(ctx, NULL); + _cmsAllocAlarmCodesChunk(ctx, NULL); + _cmsAllocAdaptationStateChunk(ctx, NULL); + _cmsAllocMemPluginChunk(ctx, NULL); + _cmsAllocInterpPluginChunk(ctx, NULL); + _cmsAllocCurvesPluginChunk(ctx, NULL); + _cmsAllocFormattersPluginChunk(ctx, NULL); + _cmsAllocTagTypePluginChunk(ctx, NULL); + _cmsAllocMPETypePluginChunk(ctx, NULL); + _cmsAllocTagPluginChunk(ctx, NULL); + _cmsAllocIntentsPluginChunk(ctx, NULL); + _cmsAllocOptimizationPluginChunk(ctx, NULL); + _cmsAllocTransformPluginChunk(ctx, NULL); + _cmsAllocMutexPluginChunk(ctx, NULL); + + // Setup the plug-ins + if (!cmsPluginTHR(ctx, Plugin)) { + + cmsDeleteContext(ctx); + return NULL; + } + + return (cmsContext) ctx; +} + +// Duplicates a context with all associated plug-ins. +// Caller may specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) +{ + int i; + struct _cmsContext_struct* ctx; + const struct _cmsContext_struct* src = _cmsGetContext(ContextID); + + void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; + + + ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened + + // Setup default memory allocators + memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + // Maintain the linked list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = userData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + // Allocate all required chunks. + _cmsAllocLogErrorChunk(ctx, src); + _cmsAllocAlarmCodesChunk(ctx, src); + _cmsAllocAdaptationStateChunk(ctx, src); + _cmsAllocMemPluginChunk(ctx, src); + _cmsAllocInterpPluginChunk(ctx, src); + _cmsAllocCurvesPluginChunk(ctx, src); + _cmsAllocFormattersPluginChunk(ctx, src); + _cmsAllocTagTypePluginChunk(ctx, src); + _cmsAllocMPETypePluginChunk(ctx, src); + _cmsAllocTagPluginChunk(ctx, src); + _cmsAllocIntentsPluginChunk(ctx, src); + _cmsAllocOptimizationPluginChunk(ctx, src); + _cmsAllocTransformPluginChunk(ctx, src); + _cmsAllocMutexPluginChunk(ctx, src); + + // Make sure no one failed + for (i=Logger; i < MemoryClientMax; i++) { + + if (src ->chunks[i] == NULL) { + cmsDeleteContext((cmsContext) ctx); + return NULL; + } + } + + return (cmsContext) ctx; +} + + + +static +struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) +{ + struct _cmsContext_struct* prev; + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev ->Next == id) + return prev; + } + + return NULL; // List is empty or only one element! +} + +// Frees any resources associated with the given context, +// and destroys the context placeholder. +// The ContextID can no longer be used in any THR operation. +void CMSEXPORT cmsDeleteContext(cmsContext ContextID) +{ + if (ContextID != NULL) { + + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct fakeContext; + struct _cmsContext_struct* prev; + + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Get rid of plugins + cmsUnregisterPluginsTHR(ContextID); + + // Since all memory is allocated in the private pool, all what we need to do is destroy the pool + if (ctx -> MemPool != NULL) + _cmsSubAllocDestroy(ctx ->MemPool); + ctx -> MemPool = NULL; + + // Maintain list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + if (_cmsContextPoolHead == ctx) { + + _cmsContextPoolHead = ctx->Next; + } + else { + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev -> Next == ctx) { + prev -> Next = ctx ->Next; + break; + } + } + } + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + // free the memory block itself + _cmsFree(&fakeContext, ctx); + } +} + +// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation +void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) +{ + return _cmsContextGetClientChunk(ContextID, UserPtr); +} + + diff --git a/thirdparty/liblcms2/src/cmsps2.c b/thirdparty/liblcms2/src/cmsps2.c index b41f58ff..224b44b5 100644 --- a/thirdparty/liblcms2/src/cmsps2.c +++ b/thirdparty/liblcms2/src/cmsps2.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2008 Marti Maria Saguer +// Copyright (c) 1998-2011 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -26,7 +26,7 @@ #include "lcms2_internal.h" -// PostScript ColorRenderingDictionary and ColorSpaceArray +// PostScript ColorRenderingDictionary and ColorSpaceArray #define MAXPSCOLS 60 // Columns on tables @@ -35,26 +35,26 @@ Implementation -------------- - PostScript does use XYZ as its internal PCS. But since PostScript - interpolation tables are limited to 8 bits, I use Lab as a way to - improve the accuracy, favoring perceptual results. So, for the creation - of each CRD, CSA the profiles are converted to Lab via a device + PostScript does use XYZ as its internal PCS. But since PostScript + interpolation tables are limited to 8 bits, I use Lab as a way to + improve the accuracy, favoring perceptual results. So, for the creation + of each CRD, CSA the profiles are converted to Lab via a device link between profile -> Lab or Lab -> profile. The PS code necessary to convert Lab <-> XYZ is also included. - Color Space Arrays (CSA) + Color Space Arrays (CSA) ================================================================================== In order to obtain precision, code chooses between three ways to implement the device -> XYZ transform. These cases identifies monochrome profiles (often implemented as a set of curves), matrix-shaper and Pipeline-based. - Monochrome + Monochrome ----------- - This is implemented as /CIEBasedA CSA. The prelinearization curve is + This is implemented as /CIEBasedA CSA. The prelinearization curve is placed into /DecodeA section, and matrix equals to D50. Since here is no interpolation tables, I do the conversion directly to XYZ @@ -62,24 +62,24 @@ flag is forced on such profiles. [ /CIEBasedA - << + << /DecodeA { transfer function } bind - /MatrixA [D50] + /MatrixA [D50] /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] /WhitePoint [D50] /BlackPoint [BP] /RenderingIntent (intent) >> - ] + ] On simpler profiles, the PCS is already XYZ, so no conversion is required. - + Matrix-shaper based ------------------- This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig - of profile implementation. Since here there are no interpolation tables, I do + of profile implementation. Since here there are no interpolation tables, I do the conversion directly to XYZ @@ -94,7 +94,7 @@ /BlackPoint [BP] /RenderingIntent (intent) >> - ] + ] CLUT based @@ -108,13 +108,13 @@ /Table [ p p p [<...>]] /RangeABC [ 0 1 0 1 0 1] /DecodeABC[ ] - /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] - % -128/500 1+127/500 0 1 -127/200 1+128/200 + /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] + % -128/500 1+127/500 0 1 -127/200 1+128/200 /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /WhitePoint [D50] /BlackPoint [BP] /RenderingIntent (intent) - ] + ] Color Rendering Dictionaries (CRD) @@ -128,7 +128,7 @@ /BlackPoint [BP] /MatrixPQR [ Bradford ] /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ] - /TransformPQR [ + /TransformPQR [ {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind @@ -137,15 +137,15 @@ /EncodeABC <...> /RangeABC <.. used for XYZ -> Lab> /EncodeLMN - /RenderTable [ p p p [<...>]] - + /RenderTable [ p p p [<...>]] + /RenderingIntent (Perceptual) - >> + >> /Current exch /ColorRendering defineresource pop The following stages are used to convert from XYZ to Lab - -------------------------------------------------------- + -------------------------------------------------------- Input is given at LMN stage on X, Y, Z @@ -158,8 +158,8 @@ { 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind ] - - + + MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn) | 0 1 0| @@ -174,17 +174,17 @@ { 116 mul 16 sub 100 div } bind { 500 mul 128 add 255 div } bind { 200 mul 128 add 255 div } bind - ] - + ] + The following stages are used to convert Lab to XYZ ---------------------------------------------------- /RangeABC [ 0 1 0 1 0 1] /DecodeABC [ { 100 mul 16 add 116 div } bind { 255 mul 128 sub 500 div } bind - { 255 mul 128 sub 200 div } bind + { 255 mul 128 sub 200 div } bind ] - + /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /DecodeLMN [ {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind @@ -200,12 +200,12 @@ PostScript algorithms discussion. ========================================================================================================= - 1D interpolation algorithm + 1D interpolation algorithm 1D interpolation (float) ------------------------ - + val2 = Domain * Value; cell0 = (int) floor(val2); @@ -219,7 +219,7 @@ y = y0 + (y1 - y0) * rest; - + PostScript code Stack ================================================ @@ -238,21 +238,21 @@ exch % tab val2 cell0 val2 ceiling cvi % tab val2 cell0 cell1 - 3 index % tab val2 cell0 cell1 tab + 3 index % tab val2 cell0 cell1 tab exch % tab val2 cell0 tab cell1 get % tab val2 cell0 y1 4 -1 roll % val2 cell0 y1 tab - 3 -1 roll % val2 y1 tab cell0 - get % val2 y1 y0 + 3 -1 roll % val2 y1 tab cell0 + get % val2 y1 y0 dup % val2 y1 y0 y0 - 3 1 roll % val2 y0 y1 y0 + 3 1 roll % val2 y0 y1 y0 sub % val2 y0 (y1-y0) 3 -1 roll % y0 (y1-y0) val2 dup % y0 (y1-y0) val2 val2 - floor cvi % y0 (y1-y0) val2 floor(val2) + floor cvi % y0 (y1-y0) val2 floor(val2) sub % y0 (y1-y0) rest mul % y0 t1 add % y @@ -266,20 +266,20 @@ // This struct holds the memory block currently being write typedef struct { - _cmsStageCLutData* Pipeline; - cmsIOHANDLER* m; + _cmsStageCLutData* Pipeline; + cmsIOHANDLER* m; - int FirstComponent; - int SecondComponent; - - const char* PreMaj; - const char* PostMaj; - const char* PreMin; - const char* PostMin; + int FirstComponent; + int SecondComponent; - int FixWhite; // Force mapping of pure white + const char* PreMaj; + const char* PostMaj; + const char* PreMin; + const char* PostMin; - cmsColorSpaceSignature ColorSpace; // ColorSpace of profile + int FixWhite; // Force mapping of pure white + + cmsColorSpaceSignature ColorSpace; // ColorSpace of profile } cmsPsSamplerCargo; @@ -299,10 +299,10 @@ cmsUInt8Number Word2Byte(cmsUInt16Number w) /* static cmsUInt8Number L2Byte(cmsUInt16Number w) -{ - int ww = w + 0x0080; +{ + int ww = w + 0x0080; - if (ww > 0xFFFF) return 0xFF; + if (ww > 0xFFFF) return 0xFF; return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF); } @@ -313,21 +313,21 @@ cmsUInt8Number L2Byte(cmsUInt16Number w) static void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b) { - _cmsIOPrintf(m, "%02x", b); - _cmsPSActualColumn += 2; + _cmsIOPrintf(m, "%02x", b); + _cmsPSActualColumn += 2; - if (_cmsPSActualColumn > MAXPSCOLS) { + if (_cmsPSActualColumn > MAXPSCOLS) { - _cmsIOPrintf(m, "\n"); - _cmsPSActualColumn = 0; - } + _cmsIOPrintf(m, "\n"); + _cmsPSActualColumn = 0; + } } // ----------------------------------------------------------------- PostScript generation // Removes offending Carriage returns -static +static char* RemoveCR(const char* txt) { static char Buffer[2048]; @@ -346,19 +346,19 @@ static void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile) { time_t timer; - cmsMLU *Description, *Copyright; - char DescASCII[256], CopyrightASCII[256]; - - time(&timer); - - Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag); - Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag); + cmsMLU *Description, *Copyright; + char DescASCII[256], CopyrightASCII[256]; - DescASCII[0] = DescASCII[255] = 0; + time(&timer); + + Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag); + Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag); + + DescASCII[0] = DescASCII[255] = 0; CopyrightASCII[0] = CopyrightASCII[255] = 0; - if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255); - if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255); + if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255); + if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255); _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n"); _cmsIOPrintf(m, "%%\n"); @@ -372,8 +372,8 @@ void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile) } -// Emits White & Black point. White point is always D50, Black point is the device -// Black point adapted to D50. +// Emits White & Black point. White point is always D50, Black point is the device +// Black point adapted to D50. static void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint) @@ -383,7 +383,7 @@ void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint) BlackPoint -> Y, BlackPoint -> Z); - _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X, + _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X, cmsD50_XYZ()->Y, cmsD50_XYZ()->Z); } @@ -414,7 +414,7 @@ void EmitIntent(cmsIOHANDLER* m, int RenderingIntent) default: intent = "Undefined"; break; } - _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent ); + _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent ); } // @@ -428,13 +428,13 @@ void EmitIntent(cmsIOHANDLER* m, int RenderingIntent) static void EmitL2Y(cmsIOHANDLER* m) { - _cmsIOPrintf(m, - "{ " + _cmsIOPrintf(m, + "{ " "100 mul 16 add 116 div " // (L * 100 + 16) / 116 - "dup 6 29 div ge " // >= 6 / 29 ? + "dup 6 29 div ge " // >= 6 / 29 ? "{ dup dup mul mul } " // yes, ^3 and done "{ 4 29 div sub 108 841 div mul } " // no, slope limiting - "ifelse } bind "); + "ifelse } bind "); } */ @@ -451,7 +451,7 @@ void EmitLab2XYZ(cmsIOHANDLER* m) _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n"); _cmsIOPrintf(m, "]\n"); _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); - _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); _cmsIOPrintf(m, "/DecodeLMN [\n"); _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); @@ -469,6 +469,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) cmsUInt32Number i; cmsFloat64Number gamma; + if (Table == NULL) return; // Error if (Table ->nEntries <= 0) return; // Empty table @@ -476,7 +477,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) if (cmsIsToneCurveLinear(Table)) return; // Check if is really an exponential. If so, emit "exp" - gamma = cmsEstimateGamma(Table, 0.001); + gamma = cmsEstimateGamma(Table, 0.001); if (gamma > 0) { _cmsIOPrintf(m, "{ %g exp } bind ", gamma); return; @@ -486,7 +487,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) // Bounds check EmitRangeCheck(m); - + // Emit intepolation code // PostScript code Stack @@ -495,12 +496,12 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) _cmsIOPrintf(m, " ["); for (i=0; i < Table->nEntries; i++) { - _cmsIOPrintf(m, "%d ", Table->Table16[i]); + _cmsIOPrintf(m, "%d ", Table->Table16[i]); } _cmsIOPrintf(m, "] "); // v tab - _cmsIOPrintf(m, "dup "); // v tab tab + _cmsIOPrintf(m, "dup "); // v tab tab _cmsIOPrintf(m, "length 1 sub "); // v tab dom _cmsIOPrintf(m, "3 -1 roll "); // tab dom v _cmsIOPrintf(m, "mul "); // tab val2 @@ -509,18 +510,18 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) _cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0 _cmsIOPrintf(m, "exch "); // tab val2 cell0 val2 _cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1 - _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab + _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab _cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1 _cmsIOPrintf(m, "get "); // tab val2 cell0 y1 _cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab - _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0 - _cmsIOPrintf(m, "get "); // val2 y1 y0 + _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0 + _cmsIOPrintf(m, "get "); // val2 y1 y0 _cmsIOPrintf(m, "dup "); // val2 y1 y0 y0 - _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0 + _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0 _cmsIOPrintf(m, "sub "); // val2 y0 (y1-y0) _cmsIOPrintf(m, "3 -1 roll "); // y0 (y1-y0) val2 _cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2 - _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2) + _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2) _cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest _cmsIOPrintf(m, "mul "); // y0 t1 _cmsIOPrintf(m, "add "); // y @@ -534,7 +535,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) static cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries) -{ +{ return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0; } @@ -542,21 +543,23 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries) // Does write a set of gamma curves static -void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) +void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) { int i; - + for( i=0; i < n; i++ ) - { - if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) { + { + if (g[i] == NULL) return; // Error + + if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) { _cmsIOPrintf(m, "dup "); } - else { - Emit1Gamma(m, g[i]); + else { + Emit1Gamma(m, g[i]); } } - + } @@ -564,7 +567,7 @@ void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) // Following code dumps a LUT onto memory stream - + // This is the sampler. Intended to work in SAMPLER_INSPECT mode, // that is, the callback will be called for each knot with @@ -574,8 +577,8 @@ void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) // // Returning a value other than 0 does terminate the sampling process // -// Each row contains Pipeline values for all but first component. So, I -// detect row changing by keeping a copy of last value of first +// Each row contains Pipeline values for all but first component. So, I +// detect row changing by keeping a copy of last value of first // component. -1 is used to mark begining of whole block. static @@ -603,7 +606,7 @@ int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Nu Out[i] = White[i]; } - + } } @@ -611,57 +614,57 @@ int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Nu // Hadle the parenthesis on rows if (In[0] != sc ->FirstComponent) { - + if (sc ->FirstComponent != -1) { _cmsIOPrintf(sc ->m, sc ->PostMin); sc ->SecondComponent = -1; - _cmsIOPrintf(sc ->m, sc ->PostMaj); + _cmsIOPrintf(sc ->m, sc ->PostMaj); } - // Begin block + // Begin block _cmsPSActualColumn = 0; - - _cmsIOPrintf(sc ->m, sc ->PreMaj); - sc ->FirstComponent = In[0]; + + _cmsIOPrintf(sc ->m, sc ->PreMaj); + sc ->FirstComponent = In[0]; } if (In[1] != sc ->SecondComponent) { - + if (sc ->SecondComponent != -1) { - _cmsIOPrintf(sc ->m, sc ->PostMin); + _cmsIOPrintf(sc ->m, sc ->PostMin); } - - _cmsIOPrintf(sc ->m, sc ->PreMin); - sc ->SecondComponent = In[1]; + + _cmsIOPrintf(sc ->m, sc ->PreMin); + sc ->SecondComponent = In[1]; } - // Dump table. + // Dump table. - for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) { + for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) { - cmsUInt16Number wWordOut = Out[i]; + cmsUInt16Number wWordOut = Out[i]; cmsUInt8Number wByteOut; // Value as byte - - // We always deal with Lab4 - - wByteOut = Word2Byte(wWordOut); - WriteByte(sc -> m, wByteOut); - } - return 1; + // We always deal with Lab4 + + wByteOut = Word2Byte(wWordOut); + WriteByte(sc -> m, wByteOut); + } + + return 1; } // Writes a Pipeline on memstream. Could be 8 or 16 bits based static -void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, +void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, const char* PostMaj, const char* PreMin, - const char* PostMin, + const char* PostMin, int FixWhite, cmsColorSpaceSignature ColorSpace) { @@ -670,25 +673,25 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, sc.FirstComponent = -1; sc.SecondComponent = -1; - sc.Pipeline = (_cmsStageCLutData *) mpe ->Data; - sc.m = m; + sc.Pipeline = (_cmsStageCLutData *) mpe ->Data; + sc.m = m; sc.PreMaj = PreMaj; sc.PostMaj= PostMaj; sc.PreMin = PreMin; - sc.PostMin = PostMin; + sc.PostMin = PostMin; sc.FixWhite = FixWhite; sc.ColorSpace = ColorSpace; _cmsIOPrintf(m, "["); - for (i=0; i < sc.Pipeline->Params->nInputs; i++) - _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); + for (i=0; i < sc.Pipeline->Params->nInputs; i++) + _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); _cmsIOPrintf(m, " [\n"); cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); - + _cmsIOPrintf(m, PostMin); _cmsIOPrintf(m, PostMaj); _cmsIOPrintf(m, "] "); @@ -702,25 +705,25 @@ static int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) { - _cmsIOPrintf(m, "[ /CIEBasedA\n"); - _cmsIOPrintf(m, " <<\n"); + _cmsIOPrintf(m, "[ /CIEBasedA\n"); + _cmsIOPrintf(m, " <<\n"); - _cmsIOPrintf(m, "/DecodeA "); + _cmsIOPrintf(m, "/DecodeA "); - Emit1Gamma(m, Curve); + Emit1Gamma(m, Curve); - _cmsIOPrintf(m, " \n"); + _cmsIOPrintf(m, " \n"); - _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); - _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); - EmitWhiteBlackD50(m, BlackPoint); - EmitIntent(m, INTENT_PERCEPTUAL); + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); - _cmsIOPrintf(m, ">>\n"); - _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); - return 1; + return 1; } @@ -729,38 +732,38 @@ int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) static int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint) { - int i; - - _cmsIOPrintf(m, "[ /CIEBasedABC\n"); - _cmsIOPrintf(m, "<<\n"); - _cmsIOPrintf(m, "/DecodeABC [ "); + int i; - EmitNGamma(m, 3, CurveSet); + _cmsIOPrintf(m, "[ /CIEBasedABC\n"); + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/DecodeABC [ "); - _cmsIOPrintf(m, "]\n"); + EmitNGamma(m, 3, CurveSet); - _cmsIOPrintf(m, "/MatrixABC [ " ); + _cmsIOPrintf(m, "]\n"); - for( i=0; i < 3; i++ ) { + _cmsIOPrintf(m, "/MatrixABC [ " ); + + for( i=0; i < 3; i++ ) { _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0], Matrix[i + 3*1], - Matrix[i + 3*2]); - } + Matrix[i + 3*2]); + } - _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "]\n"); - _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); - EmitWhiteBlackD50(m, BlackPoint); - EmitIntent(m, INTENT_PERCEPTUAL); + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); - _cmsIOPrintf(m, ">>\n"); - _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); - return 1; + return 1; } @@ -770,16 +773,15 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY const char* PreMaj; const char* PostMaj; const char* PreMin, *PostMin; - cmsStage* mpe; + cmsStage* mpe; - mpe = Pipeline ->Elements; + mpe = Pipeline ->Elements; - - switch (cmsStageInputChannels(mpe)) { + switch (cmsStageInputChannels(mpe)) { case 3: _cmsIOPrintf(m, "[ /CIEBasedDEF\n"); - PreMaj ="<"; + PreMaj ="<"; PostMaj= ">\n"; PreMin = PostMin = ""; break; @@ -797,31 +799,28 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY _cmsIOPrintf(m, "<<\n"); - if (cmsStageType(mpe) == cmsSigCurveSetElemType) { - + if (cmsStageType(mpe) == cmsSigCurveSetElemType) { + _cmsIOPrintf(m, "/DecodeDEF [ "); - EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); + EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); _cmsIOPrintf(m, "]\n"); - mpe = mpe ->Next; + mpe = mpe ->Next; } + if (cmsStageType(mpe) == cmsSigCLutElemType) { - - if (cmsStageType(mpe) == cmsSigCLutElemType) { - - _cmsIOPrintf(m, "/Table "); + _cmsIOPrintf(m, "/Table "); WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0); _cmsIOPrintf(m, "]\n"); } - + EmitLab2XYZ(m); EmitWhiteBlackD50(m, BlackPoint); EmitIntent(m, Intent); - _cmsIOPrintf(m, " >>\n"); + _cmsIOPrintf(m, " >>\n"); _cmsIOPrintf(m, "]\n"); - return 1; } @@ -829,21 +828,23 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY // Generates a curve from a gray profile static -cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) + cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) { cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); cmsHPROFILE hXYZ = cmsCreateXYZProfile(); cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE); int i; - for (i=0; i < 256; i++) { - - cmsUInt8Number Gray = (cmsUInt8Number) i; - cmsCIEXYZ XYZ; - - cmsDoTransform(xform, &Gray, &XYZ, 1); - - Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + if (Out != NULL) { + for (i=0; i < 256; i++) { + + cmsUInt8Number Gray = (cmsUInt8Number) i; + cmsCIEXYZ XYZ; + + cmsDoTransform(xform, &Gray, &XYZ, 1); + + Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + } } cmsDeleteTransform(xform); @@ -867,67 +868,68 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu cmsHPROFILE Profiles[2]; cmsCIEXYZ BlackPointAdaptedToD50; - // Does create a device-link based transform. + // Does create a device-link based transform. // The DeviceLink is next dumped as working CSA. - + InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); nChannels = T_CHANNELS(InputFormat); - - cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); - // Adjust output to Lab4 + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); + + // Adjust output to Lab4 hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); - Profiles[0] = hProfile; - Profiles[1] = hLab; + Profiles[0] = hProfile; + Profiles[1] = hLab; - xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); - cmsCloseProfile(hLab); - - if (xform == NULL) { + xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); + return 0; + } - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); - return 0; - } - // Only 1, 3 and 4 channels are allowed switch (nChannels) { - case 1: { - cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); - EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); - cmsFreeToneCurve(Gray2Y); + case 1: { + cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); + EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); + cmsFreeToneCurve(Gray2Y); } break; - case 3: + case 3: case 4: { - cmsUInt32Number OutFrm = TYPE_Lab_16; + cmsUInt32Number OutFrm = TYPE_Lab_16; cmsPipeline* DeviceLink; _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; + DeviceLink = cmsPipelineDup(v ->Lut); + if (DeviceLink == NULL) return 0; + + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); - dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); - rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); - cmsPipelineFree(DeviceLink); + cmsPipelineFree(DeviceLink); + if (rc == 0) return 0; } break; default: - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); return 0; } - + cmsDeleteTransform(xform); - + return 1; } @@ -945,23 +947,23 @@ cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe) static int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper) { - cmsColorSpaceSignature ColorSpace; + cmsColorSpaceSignature ColorSpace; int rc; cmsCIEXYZ BlackPointAdaptedToD50; ColorSpace = cmsGetColorSpace(hProfile); - + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0); if (ColorSpace == cmsSigGrayData) { - - cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); - rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); - + + cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); + rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); + } else if (ColorSpace == cmsSigRgbData) { - + cmsMAT3 Mat; int i, j; @@ -971,22 +973,22 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr for (j=0; j < 3; j++) Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; - rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, - _cmsStageGetPtrToCurveSet(Shaper), - &BlackPointAdaptedToD50); + rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, + _cmsStageGetPtrToCurveSet(Shaper), + &BlackPointAdaptedToD50); } else { - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace."); + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace."); return 0; } - - return rc; + + return rc; } -// Creates a PostScript color list from a named profile data. +// Creates a PostScript color list from a named profile data. // This is a HP extension, and it works in Lab instead of XYZ static @@ -998,11 +1000,11 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) char ColorName[32]; cmsNAMEDCOLORLIST* NamedColorList; - hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); if (xform == NULL) return 0; - NamedColorList = cmsGetNamedColorList(xform); + NamedColorList = cmsGetNamedColorList(xform); if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); @@ -1014,7 +1016,7 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) for (i=0; i < nColors; i++) { - + cmsUInt16Number In[1]; cmsCIELab Lab; @@ -1023,12 +1025,12 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; - cmsDoTransform(xform, In, &Lab, 1); + cmsDoTransform(xform, In, &Lab, 1); _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); } - + _cmsIOPrintf(m, ">>\n"); cmsDeleteTransform(xform); @@ -1039,67 +1041,67 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) // Does create a Color Space Array on XYZ colorspace for PostScript usage static -cmsUInt32Number GenerateCSA(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - cmsIOHANDLER* mem) -{ - cmsUInt32Number dwBytesUsed; - cmsPipeline* lut = NULL; - cmsStage* Matrix, *Shaper; +cmsUInt32Number GenerateCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; + cmsPipeline* lut = NULL; + cmsStage* Matrix, *Shaper; - // Is a named color profile? - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error; - } - else { + if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error; + } + else { - // Any profile class are allowed (including devicelink), but - // output (PCS) colorspace must be XYZ or Lab - cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); + // Any profile class are allowed (including devicelink), but + // output (PCS) colorspace must be XYZ or Lab + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); - if (ColorSpace != cmsSigXYZData && - ColorSpace != cmsSigLabData) { + if (ColorSpace != cmsSigXYZData && + ColorSpace != cmsSigLabData) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); - goto Error; - } + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); + goto Error; + } - // Read the lut with all necessary conversion stages - lut = _cmsReadInputLUT(hProfile, Intent); - if (lut == NULL) goto Error; + // Read the lut with all necessary conversion stages + lut = _cmsReadInputLUT(hProfile, Intent); + if (lut == NULL) goto Error; - // Tone curves + matrix can be implemented without any LUT - if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) { + // Tone curves + matrix can be implemented without any LUT + if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) { - if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error; + if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error; - } - else { - // We need a LUT for the rest - if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; - } - } + } + else { + // We need a LUT for the rest + if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; + } + } - // Done, keep memory usage - dwBytesUsed = mem ->UsedSpace; + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; - // Get rid of LUT - if (lut != NULL) cmsPipelineFree(lut); + // Get rid of LUT + if (lut != NULL) cmsPipelineFree(lut); - // Finally, return used byte count - return dwBytesUsed; + // Finally, return used byte count + return dwBytesUsed; Error: - if (lut != NULL) cmsPipelineFree(lut); - return 0; + if (lut != NULL) cmsPipelineFree(lut); + return 0; } // ------------------------------------------------------ Color Rendering Dictionary (CRD) @@ -1121,13 +1123,13 @@ Error: ================================= (WPout - BPout)*X - WPout*(BPin - BPout) - out = --------------------------------------- + out = --------------------------------------- WPout - BPin Algorithm discussion ==================== - + TransformPQR(WPin, BPin, WPout, BPout, PQR) Wpin,etc= { Xws Yws Zws Pws Qws Rws } @@ -1136,31 +1138,31 @@ Error: Algorithm Stack 0...n =========================================================== PQR BPout WPout BPin WPin - 4 index 3 get WPin PQR BPout WPout BPin WPin - div (PQR/WPin) BPout WPout BPin WPin - 2 index 3 get WPout (PQR/WPin) BPout WPout BPin WPin - mult WPout*(PQR/WPin) BPout WPout BPin WPin - - 2 index 3 get WPout WPout*(PQR/WPin) BPout WPout BPin WPin - 2 index 3 get BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin - sub (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin - mult (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - - 2 index 3 get WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - 4 index 3 get BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - 3 index 3 get BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - - sub (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - mult (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin - sub (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + 4 index 3 get WPin PQR BPout WPout BPin WPin + div (PQR/WPin) BPout WPout BPin WPin + 2 index 3 get WPout (PQR/WPin) BPout WPout BPin WPin + mult WPout*(PQR/WPin) BPout WPout BPin WPin - 3 index 3 get BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - 3 index 3 get WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + 2 index 3 get WPout WPout*(PQR/WPin) BPout WPout BPin WPin + 2 index 3 get BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin + sub (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin + mult (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + 2 index 3 get WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 4 index 3 get BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 3 index 3 get BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + sub (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + mult (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + sub (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + + 3 index 3 get BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + 3 index 3 get WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin exch - sub (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin - div - - exch pop + sub (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + div + + exch pop exch pop exch pop exch pop @@ -1172,27 +1174,27 @@ static void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) { - + if (lIsAbsolute) { - // For absolute colorimetric intent, encode back to relative - // and generate a relative Pipeline + // For absolute colorimetric intent, encode back to relative + // and generate a relative Pipeline - // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) + // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) - cmsCIEXYZ White; + cmsCIEXYZ White; - _cmsReadMediaWhitePoint(&White, hProfile); + _cmsReadMediaWhitePoint(&White, hProfile); - _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); + _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" "/TransformPQR [\n" "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" - "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", - White.X, White.Y, White.Z); + "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", + White.X, White.Y, White.Z); return; } @@ -1211,16 +1213,16 @@ void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsol "/TransformPQR [\n" "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n" "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n" - "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n"); + "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n"); } else { // BPC _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n" "/TransformPQR [\n"); - + _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul " - "2 index 3 get 2 index 3 get sub mul " + "2 index 3 get 2 index 3 get sub mul " "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub " "3 index 3 get 3 index 3 get exch sub div " "exch pop exch pop exch pop exch pop } bind\n"); @@ -1238,15 +1240,15 @@ void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsol "exch pop exch pop exch pop exch pop } bind\n]\n"); } - - + + } static void EmitXYZ2Lab(cmsIOHANDLER* m) { - _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); _cmsIOPrintf(m, "/EncodeLMN [\n"); _cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); _cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); @@ -1254,22 +1256,22 @@ void EmitXYZ2Lab(cmsIOHANDLER* m) _cmsIOPrintf(m, "]\n"); _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n"); _cmsIOPrintf(m, "/EncodeABC [\n"); - - + + _cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n"); _cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n"); _cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n"); - - + + _cmsIOPrintf(m, "]\n"); - + } // Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces // I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted // space on 3D CLUT, but since space seems not to be a problem here, 33 points -// would give a reasonable accurancy. Note also that CRD tables must operate in +// would give a reasonable accurancy. Note also that CRD tables must operate in // 8 bits. static @@ -1285,51 +1287,51 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N cmsCIEXYZ BlackPointAdaptedToD50; cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); - cmsUInt32Number InFrm = TYPE_Lab_16; - int RelativeEncodingIntent; - cmsColorSpaceSignature ColorSpace; - - - hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); - if (hLab == NULL) return 0; + cmsUInt32Number InFrm = TYPE_Lab_16; + int RelativeEncodingIntent; + cmsColorSpaceSignature ColorSpace; + + + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + if (hLab == NULL) return 0; OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); - nChannels = T_CHANNELS(OutputFormat); + nChannels = T_CHANNELS(OutputFormat); - ColorSpace = cmsGetColorSpace(hProfile); + ColorSpace = cmsGetColorSpace(hProfile); - // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. + // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. RelativeEncodingIntent = Intent; - if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) - RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; + if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) + RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; - // Use V4 Lab always - Profiles[0] = hLab; - Profiles[1] = hProfile; + // Use V4 Lab always + Profiles[0] = hLab; + Profiles[1] = hProfile; - xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, - Profiles, 2, TYPE_Lab_DBL, - OutputFormat, RelativeEncodingIntent, 0); - cmsCloseProfile(hLab); + xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, + Profiles, 2, TYPE_Lab_DBL, + OutputFormat, RelativeEncodingIntent, 0); + cmsCloseProfile(hLab); if (xform == NULL) { - - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); return 0; } // Get a copy of the internal devicelink v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; - - - // We need a CLUT - dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); - + if (DeviceLink == NULL) return 0; + + + // We need a CLUT + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); @@ -1340,22 +1342,22 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); EmitXYZ2Lab(m); - - - // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab - // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, + + + // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab + // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to // zero. This would sacrifice a bit of highlights, but failure to do so would cause // scum dot. Ouch. - + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) lFixWhite = FALSE; _cmsIOPrintf(m, "/RenderTable "); - - + + WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); - + _cmsIOPrintf(m, " %d {} bind ", nChannels); for (i=1; i < nChannels; i++) @@ -1363,7 +1365,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N _cmsIOPrintf(m, "]\n"); - + EmitIntent(m, Intent); _cmsIOPrintf(m, ">>\n"); @@ -1375,8 +1377,8 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N cmsPipelineFree(DeviceLink); cmsDeleteTransform(xform); - - return 1; + + return 1; } @@ -1395,37 +1397,37 @@ void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[]) sprintf(Buff, "%.3f", Out[j] / 65535.0); strcat(Colorant, Buff); - if (j < nColorant -1) + if (j < nColorant -1) strcat(Colorant, " "); - } + } } -// Creates a PostScript color list from a named profile data. +// Creates a PostScript color list from a named profile data. // This is a HP extension. static int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags) { - cmsHTRANSFORM xform; + cmsHTRANSFORM xform; int i, nColors, nColorant; cmsUInt32Number OutputFormat; char ColorName[32]; char Colorant[128]; - cmsNAMEDCOLORLIST* NamedColorList; + cmsNAMEDCOLORLIST* NamedColorList; + - OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); - nColorant = T_CHANNELS(OutputFormat); + nColorant = T_CHANNELS(OutputFormat); + - xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); if (xform == NULL) return 0; - NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; + NamedColorList = cmsGetNamedColorList(xform); + if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); @@ -1433,9 +1435,9 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cms _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); nColors = cmsNamedColorCount(NamedColorList); - + for (i=0; i < nColors; i++) { - + cmsUInt16Number In[1]; cmsUInt16Number Out[cmsMAXCHANNELS]; @@ -1444,7 +1446,7 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cms if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; - cmsDoTransform(xform, In, Out, 1); + cmsDoTransform(xform, In, Out, 1); BuildColorantList(Colorant, nColorant, Out); _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); } @@ -1456,140 +1458,140 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cms _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); } - cmsDeleteTransform(xform); + cmsDeleteTransform(xform); return 1; } -// This one does create a Color Rendering Dictionary. +// This one does create a Color Rendering Dictionary. // CRD are always LUT-Based, no matter if profile is // implemented as matrix-shaper. static cmsUInt32Number GenerateCRD(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, cmsUInt32Number dwFlags, - cmsIOHANDLER* mem) -{ - cmsUInt32Number dwBytesUsed; + cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile); - } + EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile); + } - // Is a named color profile? - if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { - return 0; - } - } - else { + if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } + else { - // CRD are always implemented as LUT + // CRD are always implemented as LUT - if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { - return 0; - } - } + if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } - if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { - _cmsIOPrintf(mem, "%%%%EndResource\n"); - _cmsIOPrintf(mem, "\n%% CRD End\n"); - } + _cmsIOPrintf(mem, "%%%%EndResource\n"); + _cmsIOPrintf(mem, "\n%% CRD End\n"); + } - // Done, keep memory usage - dwBytesUsed = mem ->UsedSpace; + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; - // Finally, return used byte count - return dwBytesUsed; + // Finally, return used byte count + return dwBytesUsed; - cmsUNUSED_PARAMETER(ContextID); + cmsUNUSED_PARAMETER(ContextID); } -cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, - cmsPSResourceType Type, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - cmsIOHANDLER* io) +cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, + cmsPSResourceType Type, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* io) { - cmsUInt32Number rc; + cmsUInt32Number rc; - switch (Type) { + switch (Type) { - case cmsPS_RESOURCE_CSA: - rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io); - break; - - default: - case cmsPS_RESOURCE_CRD: - rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io); - break; - } + case cmsPS_RESOURCE_CSA: + rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io); + break; - return rc; + default: + case cmsPS_RESOURCE_CRD: + rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io); + break; + } + + return rc; } cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, - cmsHPROFILE hProfile, + cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen) { - cmsIOHANDLER* mem; + cmsIOHANDLER* mem; cmsUInt32Number dwBytesUsed; // Set up the serialization engine - if (Buffer == NULL) - mem = cmsOpenIOhandlerFromNULL(ContextID); - else + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); if (!mem) return 0; - dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem); - - // Get rid of memory stream - cmsCloseIOhandler(mem); + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem); - return dwBytesUsed; + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; } // Does create a Color Space Array on XYZ colorspace for PostScript usage -cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - void* Buffer, - cmsUInt32Number dwBufferLen) +cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + void* Buffer, + cmsUInt32Number dwBufferLen) { - cmsIOHANDLER* mem; + cmsIOHANDLER* mem; cmsUInt32Number dwBytesUsed; - - if (Buffer == NULL) - mem = cmsOpenIOhandlerFromNULL(ContextID); - else + + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); if (!mem) return 0; - dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem); - - // Get rid of memory stream - cmsCloseIOhandler(mem); + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem); - return dwBytesUsed; + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; } diff --git a/thirdparty/liblcms2/src/cmssamp.c b/thirdparty/liblcms2/src/cmssamp.c index 090d96de..70e46916 100644 --- a/thirdparty/liblcms2/src/cmssamp.c +++ b/thirdparty/liblcms2/src/cmssamp.c @@ -3,22 +3,22 @@ // Little Color Management System // Copyright (c) 1998-2010 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -27,29 +27,31 @@ #include "lcms2_internal.h" +#define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) +#define cmsmax(a, b) (((a) > (b)) ? (a) : (b)) // This file contains routines for resampling and LUT optimization, black point detection -// and black preservation. +// and black preservation. // Black point detection ------------------------------------------------------------------------- -// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs +// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs static cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) { - cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsHPROFILE hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); cmsHTRANSFORM xform; cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; cmsHPROFILE hProfiles[4]; cmsUInt32Number Intents[4]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; - xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents, + xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents, States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); cmsCloseProfile(hLab); @@ -59,7 +61,7 @@ cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent // Use darker colorants to obtain black point. This works in the relative colorimetric intent and // assumes more ink results in darker colors. No ink limit is assumed. static -cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, +cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint, cmsUInt32Number dwFlags) @@ -68,28 +70,28 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, cmsHTRANSFORM xform; cmsColorSpaceSignature Space; cmsUInt32Number nChannels; - cmsUInt32Number dwFormat; + cmsUInt32Number dwFormat; cmsHPROFILE hLab; cmsCIELab Lab; - cmsCIEXYZ BlackXYZ; + cmsCIEXYZ BlackXYZ; cmsContext ContextID = cmsGetProfileContextID(hInput); - - // If the profile does not support input direction, assume Black point 0 + + // If the profile does not support input direction, assume Black point 0 if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } - + // Create a formatter which has n channels and floating point dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE); - // Try to get black by using black colorant + // Try to get black by using black colorant Space = cmsGetColorSpace(hInput); // This function returns darker colorant in 16 bits for several spaces if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) { - + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } @@ -103,21 +105,21 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, hLab = cmsCreateLab2ProfileTHR(ContextID, NULL); if (hLab == NULL) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; + return FALSE; } // Create the transform xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat, hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); cmsCloseProfile(hLab); - + if (xform == NULL) { + // Something went wrong. Get rid of open resources and return zero as black - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } - + // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); @@ -125,38 +127,37 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, Lab.a = Lab.b = 0; if (Lab.L > 50) Lab.L = 50; - // Free the resources + // Free the resources cmsDeleteTransform(xform); - + // Convert from Lab (which is now clipped) to XYZ. cmsLab2XYZ(NULL, &BlackXYZ, &Lab); - + if (BlackPoint != NULL) *BlackPoint = BlackXYZ; - + return TRUE; cmsUNUSED_PARAMETER(dwFlags); } -// Get a black point of output CMYK profile, discounting any ink-limiting embedded +// Get a black point of output CMYK profile, discounting any ink-limiting embedded // in the profile. For doing that, we use perceptual intent in input direction: // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab static cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) - -{ - cmsHTRANSFORM hRoundTrip; +{ + cmsHTRANSFORM hRoundTrip; cmsCIELab LabIn, LabOut; - cmsCIEXYZ BlackXYZ; - + cmsCIEXYZ BlackXYZ; + // Is the intent supported by the profile? if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return TRUE; } - + hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL); if (hRoundTrip == NULL) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; @@ -171,10 +172,10 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi LabOut.a = LabOut.b = 0; cmsDeleteTransform(hRoundTrip); - + // Convert it to XYZ - cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); - + cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); + if (BlackPoint != NULL) *BlackPoint = BlackXYZ; @@ -182,34 +183,43 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi } // This function shouldn't exist at all -- there is such quantity of broken -// profiles on black point tag, that we must somehow fix chromaticity to +// profiles on black point tag, that we must somehow fix chromaticity to // avoid huge tint when doing Black point compensation. This function does -// just that. There is a special flag for using black point tag, but turned -// off by default because it is bogus on most profiles. The detection algorithm -// involves to turn BP to neutral and to use only L component. - +// just that. There is a special flag for using black point tag, but turned +// off by default because it is bogus on most profiles. The detection algorithm +// involves to turn BP to neutral and to use only L component. cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) -{ +{ + cmsProfileClassSignature devClass; - // Zero for black point - if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { - - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; } - // v4 + perceptual & saturation intents does have its own black point, and it is - // well specified enough to use it. Black point tag is deprecated in V4. + // Make sure intent is adequate + if (Intent != INTENT_PERCEPTUAL && + Intent != INTENT_RELATIVE_COLORIMETRIC && + Intent != INTENT_SATURATION) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } - if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. Black point tag is deprecated in V4. + if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { // Matrix shaper share MRC & perceptual intents - if (cmsIsMatrixShaper(hProfile)) + if (cmsIsMatrixShaper(hProfile)) return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents - BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; + BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; @@ -220,13 +230,13 @@ cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfil #ifdef CMS_USE_PROFILE_BLACK_POINT_TAG // v2, v4 rel/abs colorimetric - if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && + if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && Intent == INTENT_RELATIVE_COLORIMETRIC) { cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite; cmsCIELab Lab; - // If black point is specified, then use it, + // If black point is specified, then use it, BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag); if (BlackPtr != NULL) { @@ -245,16 +255,16 @@ cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfil if (BlackPoint != NULL) *BlackPoint = TrustedBlackPoint; - + return TRUE; } } #endif - // That is about v2 profiles. + // That is about v2 profiles. // If output profile, discount ink-limiting and that's all - if (Intent == INTENT_RELATIVE_COLORIMETRIC && + if (Intent == INTENT_RELATIVE_COLORIMETRIC && (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) && (cmsGetColorSpace(hProfile) == cmsSigCmykData)) return BlackPointUsingPerceptualBlack(BlackPoint, hProfile); @@ -264,3 +274,299 @@ cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfil } + +// --------------------------------------------------------------------------------------------------------- + +// Least Squares Fit of a Quadratic Curve to Data +// http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html + +static +cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[]) +{ + double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; + double sum_y = 0, sum_yx = 0, sum_yx2 = 0; + double d, a, b, c; + int i; + cmsMAT3 m; + cmsVEC3 v, res; + + if (n < 4) return 0; + + for (i=0; i < n; i++) { + + double xn = x[i]; + double yn = y[i]; + + sum_x += xn; + sum_x2 += xn*xn; + sum_x3 += xn*xn*xn; + sum_x4 += xn*xn*xn*xn; + + sum_y += yn; + sum_yx += yn*xn; + sum_yx2 += yn*xn*xn; + } + + _cmsVEC3init(&m.v[0], n, sum_x, sum_x2); + _cmsVEC3init(&m.v[1], sum_x, sum_x2, sum_x3); + _cmsVEC3init(&m.v[2], sum_x2, sum_x3, sum_x4); + + _cmsVEC3init(&v, sum_y, sum_yx, sum_yx2); + + if (!_cmsMAT3solve(&res, &m, &v)) return 0; + + + a = res.n[2]; + b = res.n[1]; + c = res.n[0]; + + if (fabs(a) < 1.0E-10) { + + return cmsmin(0, cmsmax(50, -c/b )); + } + else { + + d = b*b - 4.0 * a * c; + if (d <= 0) { + return 0; + } + else { + + double rt = (-b + sqrt(d)) / (2.0 * a); + + return cmsmax(0, cmsmin(50, rt)); + } + } + +} + +/* +static +cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) +{ + int i; + cmsFloat64Number last; + + last = Table[n-1]; + + for (i = n-2; i >= 0; --i) { + + if (Table[i] > last) + + return FALSE; + else + last = Table[i]; + + } + + return TRUE; +} +*/ + +// Calculates the black point of a destination profile. +// This algorithm comes from the Adobe paper disclosing its black point compensation method. +cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsColorSpaceSignature ColorSpace; + cmsHTRANSFORM hRoundTrip = NULL; + cmsCIELab InitialLab, destLab, Lab; + cmsFloat64Number inRamp[256], outRamp[256]; + cmsFloat64Number MinL, MaxL; + cmsBool NearlyStraightMidrange = TRUE; + cmsFloat64Number yRamp[256]; + cmsFloat64Number x[256], y[256]; + cmsFloat64Number lo, hi; + int n, l; + cmsProfileClassSignature devClass; + + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Make sure intent is adequate + if (Intent != INTENT_PERCEPTUAL && + Intent != INTENT_RELATIVE_COLORIMETRIC && + Intent != INTENT_SATURATION) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. Black point tag is deprecated in V4. + if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && + (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { + + // Matrix shaper share MRC & perceptual intents + if (cmsIsMatrixShaper(hProfile)) + return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); + + // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents + BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; + BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; + BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; + return TRUE; + } + + + // Check if the profile is lut based and gray, rgb or cmyk (7.2 in Adobe's document) + ColorSpace = cmsGetColorSpace(hProfile); + if (!cmsIsCLUT(hProfile, Intent, LCMS_USED_AS_OUTPUT ) || + (ColorSpace != cmsSigGrayData && + ColorSpace != cmsSigRgbData && + ColorSpace != cmsSigCmykData)) { + + // In this case, handle as input case + return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); + } + + // It is one of the valid cases!, use Adobe algorithm + + + // Set a first guess, that should work on good profiles. + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + cmsCIEXYZ IniXYZ; + + // calculate initial Lab as source black point + if (!cmsDetectBlackPoint(&IniXYZ, hProfile, Intent, dwFlags)) { + return FALSE; + } + + // convert the XYZ to lab + cmsXYZ2Lab(NULL, &InitialLab, &IniXYZ); + + } else { + + // set the initial Lab to zero, that should be the black point for perceptual and saturation + InitialLab.L = 0; + InitialLab.a = 0; + InitialLab.b = 0; + } + + + // Step 2 + // ====== + + // Create a roundtrip. Define a Transform BT for all x in L*a*b* + hRoundTrip = CreateRoundtripXForm(hProfile, Intent); + if (hRoundTrip == NULL) return FALSE; + + // Compute ramps + + for (l=0; l < 256; l++) { + + Lab.L = (cmsFloat64Number) (l * 100.0) / 255.0; + Lab.a = cmsmin(50, cmsmax(-50, InitialLab.a)); + Lab.b = cmsmin(50, cmsmax(-50, InitialLab.b)); + + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + + inRamp[l] = Lab.L; + outRamp[l] = destLab.L; + } + + // Make monotonic + for (l = 254; l > 0; --l) { + outRamp[l] = cmsmin(outRamp[l], outRamp[l+1]); + } + + // Check + if (! (outRamp[0] < outRamp[255])) { + + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // Test for mid range straight (only on relative colorimetric) + + NearlyStraightMidrange = TRUE; + MinL = outRamp[0]; MaxL = outRamp[255]; + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + for (l=0; l < 256; l++) { + + if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) || + (fabs(inRamp[l] - outRamp[l]) < 4.0 ))) + NearlyStraightMidrange = FALSE; + } + + // If the mid range is straight (as determined above) then the + // DestinationBlackPoint shall be the same as initialLab. + // Otherwise, the DestinationBlackPoint shall be determined + // using curve fitting. + + if (NearlyStraightMidrange) { + + cmsLab2XYZ(NULL, BlackPoint, &InitialLab); + cmsDeleteTransform(hRoundTrip); + return TRUE; + } + } + + + // curve fitting: The round-trip curve normally looks like a nearly constant section at the black point, + // with a corner and a nearly straight line to the white point. + + for (l=0; l < 256; l++) { + + yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL); + } + + // find the black point using the least squares error quadratic curve fitting + + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + lo = 0.1; + hi = 0.5; + } + else { + + // Perceptual and saturation + lo = 0.03; + hi = 0.25; + } + + // Capture shadow points for the fitting. + n = 0; + for (l=0; l < 256; l++) { + + cmsFloat64Number ff = yRamp[l]; + + if (ff >= lo && ff < hi) { + x[n] = inRamp[l]; + y[n] = yRamp[l]; + n++; + } + } + + + // No suitable points + if (n < 3 ) { + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // fit and get the vertex of quadratic curve + Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); + + if (Lab.L < 0.0) { // clip to zero L* if the vertex is negative + Lab.L = 0; + } + + Lab.a = InitialLab.a; + Lab.b = InitialLab.b; + + cmsLab2XYZ(NULL, BlackPoint, &Lab); + + cmsDeleteTransform(hRoundTrip); + return TRUE; +} diff --git a/thirdparty/liblcms2/src/cmssm.c b/thirdparty/liblcms2/src/cmssm.c index e5a6b0d5..e41cb68b 100644 --- a/thirdparty/liblcms2/src/cmssm.c +++ b/thirdparty/liblcms2/src/cmssm.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -36,7 +36,7 @@ // alpha = Hab // theta = L* -#define SECTORS 16 // number of divisions in alpha and theta +#define SECTORS 16 // number of divisions in alpha and theta // Spherical coordinates typedef struct { @@ -47,7 +47,7 @@ typedef struct { } cmsSpherical; -typedef enum { +typedef enum { GP_EMPTY, GP_SPECIFIED, GP_MODELED @@ -101,7 +101,7 @@ static cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x) { cmsFloat64Number a; - + // Deal with undefined case if (x == 0.0 && y == 0.0) return 0; @@ -120,20 +120,20 @@ void ToSpherical(cmsSpherical* sp, const cmsVEC3* v) { cmsFloat64Number L, a, b; - + L = v ->n[VX]; a = v ->n[VY]; b = v ->n[VZ]; - + sp ->r = sqrt( L*L + a*a + b*b ); if (sp ->r == 0) { sp ->alpha = sp ->theta = 0; return; } - - sp ->alpha = _cmsAtan2(a, b); - sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L); + + sp ->alpha = _cmsAtan2(a, b); + sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L); } @@ -153,7 +153,7 @@ void ToCartesian(cmsVEC3* v, const cmsSpherical* sp) cos_theta = cos((M_PI * sp ->theta) / 180.0); a = sp ->r * sin_theta * sin_alpha; - b = sp ->r * sin_theta * cos_alpha; + b = sp ->r * sin_theta * cos_alpha; L = sp ->r * cos_theta; v ->n[VX] = L; @@ -166,14 +166,14 @@ void ToCartesian(cmsVEC3* v, const cmsSpherical* sp) // The limits are the centers of each sector, so static void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta) -{ - *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) ); - *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) ); +{ + *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) ); + *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) ); - if (*alpha >= SECTORS) - *alpha = SECTORS-1; - if (*theta >= SECTORS) - *theta = SECTORS-1; + if (*alpha >= SECTORS) + *alpha = SECTORS-1; + if (*theta >= SECTORS) + *theta = SECTORS-1; } @@ -183,19 +183,19 @@ void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b) { _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]); - _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX], - b ->n[VY] - a ->n[VY], - b ->n[VZ] - a ->n[VZ]); + _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX], + b ->n[VY] - a ->n[VY], + b ->n[VZ] - a ->n[VZ]); } -// Evaluate parametric line +// Evaluate parametric line static void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t) { p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX]; p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY]; - p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ]; + p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ]; } @@ -217,7 +217,7 @@ static cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2) { cmsFloat64Number a, b, c, d, e, D; - cmsFloat64Number sc, sN, sD; + cmsFloat64Number sc, sN, sD; cmsFloat64Number tc, tN, tD; cmsVEC3 w0; @@ -271,9 +271,9 @@ cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2 } } else if (tN > tD) { // tc > 1 => the t=1 edge is visible - + tN = tD; - + // recompute sc for this edge if ((-d + b) < 0.0) sN = 0; @@ -302,7 +302,7 @@ cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID) { cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB)); if (gbd == NULL) return NULL; - + gbd -> ContextID = ContextID; return (cmsHANDLE) gbd; @@ -310,9 +310,9 @@ cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID) void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) -{ +{ cmsGDB* gbd = (cmsGDB*) hGBD; - if (hGBD != NULL) + if (hGBD != NULL) _cmsFree(gbd->ContextID, (void*) gbd); } @@ -321,20 +321,20 @@ void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) static cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) { - cmsVEC3 v; + cmsVEC3 v; int alpha, theta; // Housekeeping _cmsAssert(gbd != NULL); - _cmsAssert(Lab != NULL); - _cmsAssert(sp != NULL); + _cmsAssert(Lab != NULL); + _cmsAssert(sp != NULL); - // Center L* by substracting half of its domain, that's 50 + // Center L* by substracting half of its domain, that's 50 _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b); - + // Convert to spherical coordinates ToSpherical(sp, &v); - + if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) { cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range"); return NULL; @@ -342,7 +342,7 @@ cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) // On which sector it falls? QuantizeToSector(sp, &alpha, &theta); - + if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) { cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range"); return NULL; @@ -352,7 +352,7 @@ cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) return &gbd ->Gamut[theta][alpha]; } -// Add a point to gamut descriptor. Point to add is in Lab color space. +// Add a point to gamut descriptor. Point to add is in Lab color space. // GBD is centered on a=b=0 and L*=50 cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) { @@ -388,7 +388,7 @@ cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) // Check if a given point falls inside gamut cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) { - cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDB* gbd = (cmsGDB*) hGBD; cmsGDBPoint* ptr; cmsSpherical sp; @@ -406,7 +406,7 @@ cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) // ----------------------------------------------------------------------------------------------------------------------- -// Find near sectors. The list of sectors found is returned on Close[]. +// Find near sectors. The list of sectors found is returned on Close[]. // The function returns the number of sectors as well. // 24 9 10 11 12 @@ -416,21 +416,21 @@ cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) // 20 19 18 17 16 // // Those are the relative movements -// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, +// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, // {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1}, // {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0}, // {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1}, // {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}}; -static -const struct _spiral { - +static +const struct _spiral { + int AdvX, AdvY; - - } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1}, - {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, - {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2}, + + } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1}, + {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, + {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2}, {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} }; #define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral)) @@ -439,7 +439,8 @@ static int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) { int nSectors = 0; - int i, a, t; + int a, t; + cmsUInt32Number i; cmsGDBPoint* pt; for (i=0; i < NSTEPS; i++) { @@ -453,14 +454,14 @@ int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) // Cycle at the begin if (a < 0) a = SECTORS + a; - if (t < 0) t = SECTORS + t; + if (t < 0) t = SECTORS + t; pt = &gbd ->Gamut[t][a]; - + if (pt -> Type != GP_EMPTY) { Close[nSectors++] = pt; - } + } } return nSectors; @@ -470,17 +471,17 @@ int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) // Interpolate a missing sector. Method identifies whatever this is top, bottom or mid static cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) -{ +{ cmsSpherical sp; cmsVEC3 Lab; cmsVEC3 Centre; cmsLine ray; int nCloseSectors; - cmsGDBPoint* Close[NSTEPS]; + cmsGDBPoint* Close[NSTEPS + 1]; cmsSpherical closel, templ; cmsLine edge; int k, m; - + // Is that point already specified? if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE; @@ -488,10 +489,10 @@ cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) nCloseSectors = FindNearSectors(gbd, alpha, theta, Close); - // Find a central point on the sector + // Find a central point on the sector sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS); sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS); - sp.r = 50.0; + sp.r = 50.0; // Convert to Cartesian ToCartesian(&Lab, &sp); @@ -510,28 +511,28 @@ cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) for(m = k+1; m < nCloseSectors; m++) { cmsVEC3 temp, a1, a2; - + // A line from sector to sector ToCartesian(&a1, &Close[k]->p); ToCartesian(&a2, &Close[m]->p); LineOf2Points(&edge, &a1, &a2); - // Find a line + // Find a line ClosestLineToLine(&temp, &ray, &edge); // Convert to spherical ToSpherical(&templ, &temp); - - if ( templ.r > closel.r && - templ.theta >= (theta*180.0/SECTORS) && + + if ( templ.r > closel.r && + templ.theta >= (theta*180.0/SECTORS) && templ.theta <= ((theta+1)*180.0/SECTORS) && templ.alpha >= (alpha*360.0/SECTORS) && templ.alpha <= ((alpha+1)*360.0/SECTORS)) { - closel = templ; - } + closel = templ; + } } } @@ -553,13 +554,13 @@ cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) _cmsAssert(hGBD != NULL); // Interpolate black - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE; } // Interpolate white - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE; } @@ -567,7 +568,7 @@ cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) // Interpolate Mid for (theta = 1; theta < SECTORS; theta++) { - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE; } @@ -600,34 +601,34 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) fprintf (fp, "#VRML V2.0 utf8\n"); - // set the viewing orientation and distance + // set the viewing orientation and distance fprintf (fp, "DEF CamTest Group {\n"); - fprintf (fp, "\tchildren [\n"); - fprintf (fp, "\t\tDEF Cameras Group {\n"); - fprintf (fp, "\t\t\tchildren [\n"); - fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n"); - fprintf (fp, "\t\t\t\t\tposition 0 0 340\n"); - fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n"); - fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n"); - fprintf (fp, "\t\t\t\t}\n"); - fprintf (fp, "\t\t\t]\n"); - fprintf (fp, "\t\t},\n"); - fprintf (fp, "\t]\n"); - fprintf (fp, "}\n"); + fprintf (fp, "\tchildren [\n"); + fprintf (fp, "\t\tDEF Cameras Group {\n"); + fprintf (fp, "\t\t\tchildren [\n"); + fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n"); + fprintf (fp, "\t\t\t\t\tposition 0 0 340\n"); + fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n"); + fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t]\n"); + fprintf (fp, "\t\t},\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); - // Output the background stuff + // Output the background stuff fprintf (fp, "Background {\n"); fprintf (fp, "\tskyColor [\n"); fprintf (fp, "\t\t.5 .5 .5\n"); fprintf (fp, "\t]\n"); fprintf (fp, "}\n"); - // Output the shape stuff + // Output the shape stuff fprintf (fp, "Transform {\n"); fprintf (fp, "\tscale .3 .3 .3\n"); fprintf (fp, "\tchildren [\n"); - // Draw the axes as a shape: + // Draw the axes as a shape: fprintf (fp, "\t\tShape {\n"); fprintf (fp, "\t\t\tappearance Appearance {\n"); fprintf (fp, "\t\t\t\tmaterial Material {\n"); @@ -651,7 +652,7 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) fprintf (fp, "\t\t\t}\n"); fprintf (fp, "\t\t}\n"); - + fprintf (fp, "\t\tShape {\n"); fprintf (fp, "\t\t\tappearance Appearance {\n"); fprintf (fp, "\t\t\t\tmaterial Material {\n"); @@ -661,8 +662,8 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) fprintf (fp, "\t\t\t\t}\n"); fprintf (fp, "\t\t\t}\n"); fprintf (fp, "\t\t\tgeometry PointSet {\n"); - - // fill in the points here + + // fill in the points here fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); fprintf (fp, "\t\t\t\t\tpoint [\n"); @@ -677,7 +678,7 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]); - if ((j == SECTORS - 1) && (i == SECTORS - 1)) + if ((j == SECTORS - 1) && (i == SECTORS - 1)) fprintf (fp, "]\n"); else fprintf (fp, ",\n"); @@ -688,7 +689,7 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) - // fill in the face colors + // fill in the face colors fprintf (fp, "\t\t\t\tcolor Color {\n"); fprintf (fp, "\t\t\t\t\tcolor [\n"); @@ -696,30 +697,30 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) for (j=0; j < SECTORS; j++) { cmsVEC3 v; - + pt = &gbd ->Gamut[i][j]; - + ToCartesian(&v, &pt ->p); - if (pt ->Type == GP_EMPTY) + if (pt ->Type == GP_EMPTY) fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0); else if (pt ->Type == GP_MODELED) fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5); - else { + else { fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0); - } + } - if ((j == SECTORS - 1) && (i == SECTORS - 1)) + if ((j == SECTORS - 1) && (i == SECTORS - 1)) fprintf (fp, "]\n"); else fprintf (fp, ",\n"); } fprintf (fp, "\t\t\t}\n"); - + fprintf (fp, "\t\t\t}\n"); fprintf (fp, "\t\t}\n"); diff --git a/thirdparty/liblcms2/src/cmstypes.c b/thirdparty/liblcms2/src/cmstypes.c index 28f06d5d..60c09ef8 100644 --- a/thirdparty/liblcms2/src/cmstypes.c +++ b/thirdparty/liblcms2/src/cmstypes.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -26,14 +26,14 @@ #include "lcms2_internal.h" -// Tag Serialization ----------------------------------------------------------------------------- +// Tag Serialization ----------------------------------------------------------------------------- // This file implements every single tag and tag type as described in the ICC spec. Some types // have been deprecated, like ncl and Data. There is no implementation for those types as there // are no profiles holding them. The programmer can also extend this list by defining his own types // by using the appropiate plug-in. There are three types of plug ins regarding that. First type // allows to define new tags using any existing type. Next plug-in type allows to define new types -// and the third one is very specific: allows to extend the number of elements in the multiprofile -// elements special type. +// and the third one is very specific: allows to extend the number of elements in the multiprocessing +// elements special type. //-------------------------------------------------------------------------------------------------- // Some broken types @@ -55,59 +55,54 @@ typedef struct _cmsTagTypeLinkedList_st { #define DUP_FN(x) Type_##x##_Dup // Helper macro to define a handler. Callbacks do have a fixed naming convention. -#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x) } +#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 } // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention -#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree } +#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } -// Register a new type handler. This routine is shared between normal types and MPE +// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head static -cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) { cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; - _cmsTagTypeLinkedList *pt, *Anterior = NULL; + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); + _cmsTagTypeLinkedList *pt; // Calling the function with NULL as plug-in would unregister the plug in. if (Data == NULL) { - LinkedList[DefaultListCount-1].Next = NULL; + // There is no need to set free the memory, as pool is destroyed as a whole. + ctx ->TagTypes = NULL; return TRUE; } - pt = Anterior = LinkedList; - while (pt != NULL) { - - if (Plugin->Handler.Signature == pt -> Handler.Signature) { - pt ->Handler = Plugin ->Handler; // Replace old behaviour. - // Note that since no memory is allocated, unregister does not - // reset this action. - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - - // Registering happens in plug-in memory pool - pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList)); + // Registering happens in plug-in memory pool. + pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); if (pt == NULL) return FALSE; - pt ->Handler = Plugin ->Handler; - pt ->Next = NULL; - - if (Anterior) - Anterior -> Next = pt; + pt ->Handler = Plugin ->Handler; + pt ->Next = ctx ->TagTypes; + ctx ->TagTypes = pt; + return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// made by plug-ins and then the built-in defaults. static -cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList) +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) { _cmsTagTypeLinkedList* pt; - for (pt = LinkedList; + for (pt = PluginLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + for (pt = DefaultLinkedList; pt != NULL; pt = pt ->Next) { @@ -125,7 +120,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* cmsUInt32Number i; _cmsAssert(io != NULL); - _cmsAssert(Array != NULL); + _cmsAssert(!(Array == NULL && n > 0)); for (i=0; i < n; i++) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE; @@ -134,6 +129,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } +// Auxiliar to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { @@ -158,20 +154,20 @@ cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) } // To deal with position tables -typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, +typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag); -// Helper function to deal with position tables as decribed in several addendums to ICC spec 4.2 -// A table of n elements is written, where first comes n records containing offsets and sizes and +// Helper function to deal with position tables as decribed in ICC spec 4.3 +// A table of n elements is readed, where first comes n records containing offsets and sizes and // then a block containing the data itself. This allows to reuse same data in more than one entry static -cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - cmsUInt32Number Count, - cmsUInt32Number BaseOffset, +cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, void *Cargo, PositionTableEntryFn ElementFn) { @@ -179,10 +175,10 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; // Let's take the offsets to each element - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; for (i=0; i < Count; i++) { @@ -204,10 +200,10 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, // Success if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); - if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); return TRUE; -Error: +Error: if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); return FALSE; @@ -215,11 +211,11 @@ Error: // Same as anterior, but for write position tables static -cmsBool WritePositionTable(struct _cms_typehandler_struct* self, +cmsBool WritePositionTable(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number SizeOfTag, - cmsUInt32Number Count, - cmsUInt32Number BaseOffset, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, void *Cargo, PositionTableEntryFn ElementFn) { @@ -228,19 +224,19 @@ cmsBool WritePositionTable(struct _cms_typehandler_struct* self, cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; // Create table - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; - + // Keep starting position of curve offsets DirectoryPos = io ->Tell(io); // Write a fake directory to be filled latter on for (i=0; i < Count; i++) { - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size } @@ -248,13 +244,13 @@ cmsBool WritePositionTable(struct _cms_typehandler_struct* self, for (i=0; i < Count; i++) { Before = io ->Tell(io); - ElementOffsets[i] = Before - BaseOffset; + ElementOffsets[i] = Before - BaseOffset; // Callback to write... if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error; // Now the size - ElementSizes[i] = io ->Tell(io) - Before; + ElementSizes[i] = io ->Tell(io) - Before; } // Write the directory @@ -262,8 +258,8 @@ cmsBool WritePositionTable(struct _cms_typehandler_struct* self, if (!io ->Seek(io, DirectoryPos)) goto Error; for (i=0; i < Count; i++) { - if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; - if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; } if (!io ->Seek(io, CurrentPos)) goto Error; @@ -284,7 +280,7 @@ Error: // ******************************************************************************** //The XYZType contains an array of three encoded values for the XYZ tristimulus -//values. Tristimulus values must be non-negative. The signed encoding allows for +//values. Tristimulus values must be non-negative. The signed encoding allows for //implementation optimizations by minimizing the number of fixed formats. @@ -345,7 +341,7 @@ cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data) // ******************************************************************************** // Type chromaticity. Only one value is allowed // ******************************************************************************** -// The chromaticity tag type provides basic chromaticity data and type of +// The chromaticity tag type provides basic chromaticity data and type of // phosphors or colorants of a monitor to applications and utilities. static @@ -399,8 +395,8 @@ Error: static cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io) { - if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE; - if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE; + if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE; + if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE; return TRUE; } @@ -420,13 +416,14 @@ cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHAND return TRUE; cmsUNUSED_PARAMETER(nItems); - cmsUNUSED_PARAMETER(self); + cmsUNUSED_PARAMETER(self); } static void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) { return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE)); + cmsUNUSED_PARAMETER(n); } @@ -441,12 +438,12 @@ void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigColorantOrderType // ******************************************************************************** -// This is an optional tag which specifies the laydown order in which colorants will -// be printed on an n-colorant device. The laydown order may be the same as the -// channel generation order listed in the colorantTableTag or the channel order of a -// colour space such as CMYK, in which case this tag is not needed. When this is not -// the case (for example, ink-towers sometimes use the order KCMY), this tag may be -// used to specify the laydown order of the colorants. +// This is an optional tag which specifies the laydown order in which colorants will +// be printed on an n-colorant device. The laydown order may be the same as the +// channel generation order listed in the colorantTableTag or the channel order of a +// colour space such as CMYK, in which case this tag is not needed. When this is not +// the case (for example, ink-towers sometimes use the order KCMY), this tag may be +// used to specify the laydown order of the colorants. static @@ -480,7 +477,7 @@ void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHAN static cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr; + cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr; cmsUInt32Number i, sz, Count; // Get the length @@ -488,10 +485,10 @@ cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIO if (ColorantOrder[i] != 0xFF) Count++; } - if (!_cmsWriteUInt32Number(io, Count)) return FALSE; + if (!_cmsWriteUInt32Number(io, Count)) return FALSE; sz = Count * sizeof(cmsUInt8Number); - if (!io -> Write(io, sz, ColorantOrder)) return FALSE; + if (!io -> Write(io, sz, ColorantOrder)) return FALSE; return TRUE; @@ -517,7 +514,7 @@ void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr // ******************************************************************************** // Type cmsSigS15Fixed16ArrayType // ******************************************************************************** -// This type represents an array of generic 4-byte/32-bit fixed point quantity. +// This type represents an array of generic 4-byte/32-bit fixed point quantity. // The number of values is determined from the size of the tag. static @@ -537,7 +534,7 @@ void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i _cmsFree(self ->ContextID, array_double); return NULL; - } + } } *nItems = n; @@ -552,7 +549,7 @@ cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER for (i=0; i < nItems; i++) { - if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE; } return TRUE; @@ -576,7 +573,7 @@ void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) // ******************************************************************************** // Type cmsSigU16Fixed16ArrayType // ******************************************************************************** -// This type represents an array of generic 4-byte/32-bit quantity. +// This type represents an array of generic 4-byte/32-bit quantity. // The number of values is determined from the size of the tag. @@ -617,7 +614,7 @@ cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5); - if (!_cmsWriteUInt32Number(io, v)) return FALSE; + if (!_cmsWriteUInt32Number(io, v)) return FALSE; } return TRUE; @@ -642,9 +639,9 @@ void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigSignatureType // ******************************************************************************** // -// The signatureType contains a four-byte sequence, Sequences of less than four -// characters are padded at the end with spaces, 20h. -// Typically this type is used for registered tags that can be displayed on many +// The signatureType contains a four-byte sequence, Sequences of less than four +// characters are padded at the end with spaces, 20h. +// Typically this type is used for registered tags that can be displayed on many // development systems as a sequence of four characters. static @@ -664,8 +661,8 @@ void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io static cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsSignature* SigPtr = (cmsSignature*) Ptr; - + cmsSignature* SigPtr = (cmsSignature*) Ptr; + return _cmsWriteUInt32Number(io, *SigPtr); cmsUNUSED_PARAMETER(nItems); @@ -689,8 +686,8 @@ void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigTextType // ******************************************************************************** // -// The textType is a simple text structure that contains a 7-bit ASCII text string. -// The length of the string is obtained by subtracting 8 from the element size portion +// The textType is a simple text structure that contains a 7-bit ASCII text string. +// The length of the string is obtained by subtracting 8 from the element size portion // of the tag itself. This string must be terminated with a 00h byte. static @@ -711,12 +708,12 @@ void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); if (Text == NULL) goto Error; - if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error; + if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error; // Make sure text is properly ended Text[SizeOfTag] = 0; *nItems = 1; - + // Keep the result if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; @@ -724,7 +721,7 @@ void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms return (void*) mlu; Error: - if (mlu != NULL) + if (mlu != NULL) cmsMLUfree(mlu); if (Text != NULL) _cmsFree(self ->ContextID, Text); @@ -736,17 +733,19 @@ Error: static cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsMLU* mlu = (cmsMLU*) Ptr; + cmsMLU* mlu = (cmsMLU*) Ptr; cmsUInt32Number size; cmsBool rc; char* Text; - + // Get the size of the string. Note there is an extra "\0" at the end size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); if (size == 0) return FALSE; // Cannot be zero! // Create memory Text = (char*) _cmsMalloc(self ->ContextID, size); + if (Text == NULL) return FALSE; + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); // Write it, including separator @@ -781,11 +780,11 @@ void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr) static cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data) { - if (ICCVersion >= 4.0) + if (ICCVersion >= 4.0) return cmsSigMultiLocalizedUnicodeType; - + return cmsSigTextType; - + cmsUNUSED_PARAMETER(Data); } @@ -802,7 +801,7 @@ void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms cmsUInt32Number LenOfData; *nItems = 0; - + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; LenOfData = SizeOfTag - sizeof(cmsUInt32Number); @@ -818,13 +817,13 @@ void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms } if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) { - + _cmsFree(self ->ContextID, BinData); return NULL; } *nItems = 1; - + return (void*) BinData; } @@ -833,7 +832,7 @@ static cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsICCData* BinData = (cmsICCData*) Ptr; - + if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE; return io ->Write(io, BinData ->len, BinData ->data); @@ -883,7 +882,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND SizeOfTag -= sizeof(cmsUInt32Number); // Check for size - if (SizeOfTag < AsciiCount) return NULL; + if (SizeOfTag < AsciiCount) return NULL; // All seems Ok, allocate the container mlu = cmsMLUalloc(self ->ContextID, 1); @@ -904,11 +903,11 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; _cmsFree(self ->ContextID, (void*) Text); Text = NULL; - + // Skip Unicode code if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done; - if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done; - if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; SizeOfTag -= 2* sizeof(cmsUInt32Number); if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; @@ -919,13 +918,13 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); // Skip ScriptCode code if present. Some buggy profiles does have less - // data that stricttly required. We need to skip it as this type may come + // data that stricttly required. We need to skip it as this type may come // embedded in other types. - + if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done; - if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done; + if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done; // Skip rest of tag for (i=0; i < 67; i++) { @@ -958,17 +957,17 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // Used below for writting zeroes memset(Filler, 0, sizeof(Filler)); - + // Get the len of string len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); - + // From ICC3.4: It has been found that textDescriptionType can contain misaligned data //(see clause 4.1 for the definition of “aligned”). Because the Unicode language // code and Unicode count immediately follow the ASCII description, their // alignment is not correct if the ASCII count is not a multiple of four. The // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and // writing software must be written carefully in order to handle these alignment - // problems. + // problems. // Compute an aligned size len_aligned = _cmsALIGNLONG(len); @@ -988,11 +987,11 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t)); if (Wide == NULL) goto Error; - // Get both representations. + // Get both representations. cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); } - + // * cmsUInt32Number count; * Description length // * cmsInt8Number desc[count] * NULL terminated ascii string // * cmsUInt32Number ucLangCode; * UniCode language code @@ -1001,26 +1000,26 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // * cmsUInt16Number scCode; * ScriptCode code // * cmsUInt8Number scCount; * ScriptCode count // * cmsInt8Number scDesc[67]; * ScriptCode Description - - if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error; - if (!io ->Write(io, len, Text)) goto Error; - if (!io ->Write(io, len_filler_alignment, Filler)) goto Error; + + if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error; + if (!io ->Write(io, len, Text)) goto Error; + if (!io ->Write(io, len_filler_alignment, Filler)) goto Error; if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode - + // This part is tricky: we need an aligned tag size, and the ScriptCode part // takes 70 bytes, so we need 2 extra bytes to do the alignment - if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error; + if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error; // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t) - if (!_cmsWriteWCharArray(io, len, Wide)) goto Error; - if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error; + if (!_cmsWriteWCharArray(io, len, Wide)) goto Error; + if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error; // ScriptCode Code & count (unused) - if (!_cmsWriteUInt16Number(io, 0)) goto Error; - if (!_cmsWriteUInt8Number(io, 0)) goto Error; - + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + if (!_cmsWriteUInt8Number(io, 0)) goto Error; + if (!io ->Write(io, 67, Filler)) goto Error; rc = TRUE; @@ -1059,11 +1058,11 @@ void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr) static cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data) { - if (ICCVersion >= 4.0) + if (ICCVersion >= 4.0) return cmsSigMultiLocalizedUnicodeType; - + return cmsSigTextDescriptionType; - + cmsUNUSED_PARAMETER(Data); } @@ -1077,21 +1076,22 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm { cmsUInt32Number Count; cmsToneCurve* NewGamma; - cmsUInt16Number Linear[2] = { 0, 0xffff }; - - + *nItems = 0; if (!_cmsReadUInt32Number(io, &Count)) return NULL; switch (Count) { case 0: // Linear. + { + cmsFloat64Number SingleGamma = 1.0; - NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear); - if (!NewGamma) return NULL; - *nItems = 1; - return NewGamma; - + NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); + if (!NewGamma) return NULL; + *nItems = 1; + return NewGamma; + } + case 1: // Specified as the exponent of gamma function { cmsUInt16Number SingleGammaFixed; @@ -1106,10 +1106,13 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm default: // Curve + if (Count > 0x7FFF) + return NULL; // This is to prevent bad guys for doing bad things + NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); if (!NewGamma) return NULL; - if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL; + if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL; *nItems = 1; return NewGamma; @@ -1129,13 +1132,13 @@ cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io // Single gamma, preserve number cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]); - if (!_cmsWriteUInt32Number(io, 1)) return FALSE; + if (!_cmsWriteUInt32Number(io, 1)) return FALSE; if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE; return TRUE; - + } - if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE; + if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE; return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16); cmsUNUSED_PARAMETER(nItems); @@ -1178,6 +1181,7 @@ cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Dat if (ICCVersion < 4.0) return cmsSigCurveType; if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves + if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves return cmsSigParametricCurveType; } @@ -1205,7 +1209,7 @@ void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDL for (i=0; i < n; i++) { - if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL; + if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL; } NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params); @@ -1215,32 +1219,38 @@ void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDL cmsUNUSED_PARAMETER(SizeOfTag); } - + static cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsToneCurve* Curve = (cmsToneCurve*) Ptr; - int i, nParams; + int i, nParams, typen; static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; - - if (Curve ->nSegments > 1 || Curve -> Segments[0].Type < 1) { + typen = Curve -> Segments[0].Type; - cmsSignalError(self->ContextID, 0, "Multisegment or Inverted parametric curves cannot be written"); + if (Curve ->nSegments > 1 || typen < 1) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written"); return FALSE; } - nParams = ParamsByType[Curve ->Segments[0].Type]; - + if (typen > 5) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve"); + return FALSE; + } + + nParams = ParamsByType[typen]; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE; if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved for (i=0; i < nParams; i++) { - if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE; + if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE; } - + return TRUE; cmsUNUSED_PARAMETER(nItems); @@ -1271,14 +1281,14 @@ void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigDateTimeType // ******************************************************************************** -// A 12-byte value representation of the time and date, where the byte usage is assigned -// as specified in table 1. The actual values are encoded as 16-bit unsigned integers +// A 12-byte value representation of the time and date, where the byte usage is assigned +// as specified in table 1. The actual values are encoded as 16-bit unsigned integers // (uInt16Number - see 5.1.6). // -// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time +// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local -// time to UTC when setting these values. Programmes that display these values may show -// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or +// time to UTC when setting these values. Programmes that display these values may show +// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or // display both UTC and local versions of the dateTimeNumber. static @@ -1292,7 +1302,7 @@ void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (NewDateTime == NULL) return NULL; if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL; - + _cmsDecodeDateTimeNumber(×tamp, NewDateTime); *nItems = 1; @@ -1339,7 +1349,7 @@ void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr) /* The measurementType information refers only to the internal profile data and is -meant to provide profile makers an alternative to the default measurement +meant to provide profile makers an alternative to the default measurement specifications. */ @@ -1348,6 +1358,9 @@ void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* { cmsICCMeasurementConditions mc; + + memset(&mc, 0, sizeof(mc)); + if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL; if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL; if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL; @@ -1365,7 +1378,7 @@ static cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr; - + if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE; if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE; if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE; @@ -1397,7 +1410,7 @@ void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigMultiLocalizedUnicodeType // ******************************************************************************** // -// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from +// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance) // @@ -1406,7 +1419,7 @@ static void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { cmsMLU* mlu; - cmsUInt32Number Count, RecLen, NumOfWchar; + cmsUInt32Number Count, RecLen, NumOfWchar; cmsUInt32Number SizeOfHeader; cmsUInt32Number Len, Offset; cmsUInt32Number i; @@ -1414,8 +1427,8 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition; *nItems = 0; - if (!_cmsReadUInt32Number(io, &Count)) return NULL; - if (!_cmsReadUInt32Number(io, &RecLen)) return NULL; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (!_cmsReadUInt32Number(io, &RecLen)) return NULL; if (RecLen != 12) { @@ -1433,11 +1446,11 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU for (i=0; i < Count; i++) { - if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error; - if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error; + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error; + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error; // Now deal with Len and offset. - if (!_cmsReadUInt32Number(io, &Len)) goto Error; + if (!_cmsReadUInt32Number(io, &Len)) goto Error; if (!_cmsReadUInt32Number(io, &Offset)) goto Error; // Check for overflow @@ -1445,9 +1458,9 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU // True begin of the string BeginOfThisString = Offset - SizeOfHeader - 8; - + // Ajust to wchar_t elements - mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number); // To guess maximum size, add offset + len @@ -1458,13 +1471,19 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU // Now read the remaining of tag and fill all strings. Substract the directory SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + if (SizeOfTag == 0) + { + Block = NULL; + NumOfWchar = 0; - Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); - if (Block == NULL) goto Error; - - NumOfWchar = SizeOfTag / sizeof(wchar_t); - - if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; + } + else + { + Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); + if (Block == NULL) goto Error; + NumOfWchar = SizeOfTag / sizeof(wchar_t); + if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; + } mlu ->MemPool = Block; mlu ->PoolSize = SizeOfTag; @@ -1473,9 +1492,9 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU *nItems = 1; return (void*) mlu; -Error: +Error: if (mlu) cmsMLUfree(mlu); - return NULL; + return NULL; } static @@ -1489,28 +1508,28 @@ cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (Ptr == NULL) { // Empty placeholder - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; return TRUE; } - - if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; - if (!_cmsWriteUInt32Number(io, 12)) return FALSE; - + + if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase); for (i=0; i < mlu ->UsedEntries; i++) { Len = mlu ->Entries[i].Len; Offset = mlu ->Entries[i].StrW; - + Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t); Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8; - if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; - if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; if (!_cmsWriteUInt32Number(io, Len)) return FALSE; - if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; + if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; } if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; @@ -1533,7 +1552,7 @@ void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUIn static void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsMLUfree((cmsMLU*) Ptr); return; @@ -1575,10 +1594,10 @@ cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Da } /* -This structure represents a colour transform using tables of 8-bit precision. -This type contains four processing elements: a 3 by 3 matrix (which shall be -the identity matrix unless the input colour space is XYZ), a set of one dimensional -input tables, a multidimensional lookup table, and a set of one dimensional output +This structure represents a colour transform using tables of 8-bit precision. +This type contains four processing elements: a 3 by 3 matrix (which shall be +the identity matrix unless the input colour space is XYZ), a set of one dimensional +input tables, a multidimensional lookup table, and a set of one dimensional output tables. Data is processed using these elements via the following sequence: (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables) @@ -1593,16 +1612,16 @@ Byte Position Field Length (bytes) Content Encoded as... // Read 8 bit tables as gamma functions -static +static cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels) { - cmsStage* mpe; cmsUInt8Number* Temp = NULL; int i, j; cmsToneCurve* Tables[cmsMAXCHANNELS]; if (nChannels > cmsMAXCHANNELS) return FALSE; - + if (nChannels <= 0) return FALSE; + memset(Tables, 0, sizeof(Tables)); Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256); @@ -1622,14 +1641,12 @@ cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut } _cmsFree(ContextID, Temp); + Temp = NULL; + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; - mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); - if (mpe == NULL) goto Error; - - cmsPipelineInsertStage(lut, cmsAT_END, mpe); - - for (i=0; i < nChannels; i++) + for (i=0; i < nChannels; i++) cmsFreeToneCurve(Tables[i]); return TRUE; @@ -1640,7 +1657,7 @@ Error: } if (Temp) _cmsFree(ContextID, Temp); - return FALSE; + return FALSE; } @@ -1655,21 +1672,30 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number if (Tables) { - if (Tables ->TheCurves[i]->nEntries != 256) { - cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); - return FALSE; + // Usual case of identity curves + if ((Tables ->TheCurves[i]->nEntries == 2) && + (Tables->TheCurves[i]->Table16[0] == 0) && + (Tables->TheCurves[i]->Table16[1] == 65535)) { + + for (j=0; j < 256; j++) { + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE; + } } + else + if (Tables ->TheCurves[i]->nEntries != 256) { + cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); + return FALSE; + } + else + for (j=0; j < 256; j++) { - } + if (Tables != NULL) + val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); + else + val = (cmsUInt8Number) j; - for (j=0; j < 256; j++) { - - if (Tables != NULL) - val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); - else - val = (cmsUInt8Number) j; - - if (!_cmsWriteUInt8Number(io, val)) return FALSE; + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } } } return TRUE; @@ -1678,7 +1704,7 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number // Check overflow static -unsigned int uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) +cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) { cmsUInt32Number rv = 1, rc; @@ -1690,18 +1716,18 @@ unsigned int uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) rv *= a; // Check for overflow - if (rv > UINT_MAX / a) return 0; + if (rv > UINT_MAX / a) return (cmsUInt32Number) -1; } - + rc = rv * n; - if (rv != rc / n) return 0; + if (rv != rc / n) return (cmsUInt32Number) -1; return rc; } -// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. +// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. @@ -1711,21 +1737,21 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; cmsUInt8Number* Temp = NULL; cmsPipeline* NewLUT = NULL; - cmsStage *mpemat, *mpeclut; - cmsUInt32Number nTabSize, i; + cmsUInt32Number nTabSize, i; cmsFloat64Number Matrix[3*3]; *nItems = 0; - + if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error; if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error; if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error; + if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least + // Padding if (!_cmsReadUInt8Number(io, NULL)) goto Error; // Do some checking - if (InputChannels > cmsMAXCHANNELS) goto Error; if (OutputChannels > cmsMAXCHANNELS) goto Error; @@ -1744,34 +1770,38 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; - + // Only operates if not identity... if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); - if (mpemat == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; } - + // Get input tables if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; - + // Get 3D CLUT. Check the overflow.... nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (cmsUInt32Number) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *PtrW, *T; - cmsUInt32Number Tsize; - - Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number); - + PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); if (T == NULL) goto Error; - Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); - if (Temp == NULL) goto Error; + Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); + if (Temp == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } - if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error; + if (io ->Read(io, Temp, nTabSize, 1) != 1) { + _cmsFree(self ->ContextID, T); + _cmsFree(self ->ContextID, Temp); + goto Error; + } for (i = 0; i < nTabSize; i++) { @@ -1780,17 +1810,15 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms _cmsFree(self ->ContextID, Temp); Temp = NULL; - - mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); - if (mpeclut == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) + goto Error; _cmsFree(self ->ContextID, T); } // Get output tables if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error; - + *nItems = 1; return NewLUT; @@ -1885,18 +1913,19 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); + if (nTabSize == (cmsUInt32Number) -1) return FALSE; if (nTabSize > 0) { - // The 3D CLUT. - if (clut != NULL) { + // The 3D CLUT. + if (clut != NULL) { - for (j=0; j < nTabSize; j++) { + for (j=0; j < nTabSize; j++) { - val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); - if (!_cmsWriteUInt8Number(io, val)) return FALSE; + val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } } } - } // The postlinearization table if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; @@ -1918,7 +1947,7 @@ void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUI static void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsPipelineFree((cmsPipeline*) Ptr); return; @@ -1930,10 +1959,9 @@ void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) // ******************************************************************************** // Read 16 bit tables as gamma functions -static +static cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries) { - cmsStage* mpe; int i; cmsToneCurve* Tables[cmsMAXCHANNELS]; @@ -1941,8 +1969,9 @@ cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lu if (nEntries <= 0) return TRUE; // Check for malicious profiles + if (nEntries < 2) return FALSE; if (nChannels > cmsMAXCHANNELS) return FALSE; - + // Init table to zero memset(Tables, 0, sizeof(Tables)); @@ -1956,12 +1985,10 @@ cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lu // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) - mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); - if (mpe == NULL) goto Error; + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; - cmsPipelineInsertStage(lut, cmsAT_END, mpe); - - for (i=0; i < nChannels; i++) + for (i=0; i < nChannels; i++) cmsFreeToneCurve(Tables[i]); return TRUE; @@ -1971,7 +1998,7 @@ Error: if (Tables[i]) cmsFreeToneCurve(Tables[i]); } - return FALSE; + return FALSE; } static @@ -1980,19 +2007,17 @@ cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCu int j; cmsUInt32Number i; cmsUInt16Number val; - int nEntries = 256; + int nEntries; + + _cmsAssert(Tables != NULL); nEntries = Tables->TheCurves[0]->nEntries; - + for (i=0; i < Tables ->nCurves; i++) { for (j=0; j < nEntries; j++) { - if (Tables != NULL) - val = Tables->TheCurves[i]->Table16[j]; - else - val = _cmsQuantizeVal(j, nEntries); - + val = Tables->TheCurves[i]->Table16[j]; if (!_cmsWriteUInt16Number(io, val)) return FALSE; } } @@ -2006,17 +2031,16 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm { cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; cmsPipeline* NewLUT = NULL; - cmsStage *mpemat, *mpeclut; cmsUInt32Number nTabSize; cmsFloat64Number Matrix[3*3]; cmsUInt16Number InputEntries, OutputEntries; - + *nItems = 0; if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum - + // Padding if (!_cmsReadUInt8Number(io, NULL)) return NULL; @@ -2041,23 +2065,24 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm // Only operates on 3 channels - if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); - if (mpemat == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; } - if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL; + if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; + if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error; + + if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error; + if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least - // Get input tables if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; // Get 3D CLUT nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (cmsUInt32Number) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *T; @@ -2067,16 +2092,13 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm if (!_cmsReadUInt16Array(io, nTabSize, T)) { _cmsFree(self ->ContextID, T); - goto Error; - } - - mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); - if (mpeclut == NULL) { - _cmsFree(self ->ContextID, T); goto Error; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { + _cmsFree(self ->ContextID, T); + goto Error; + } _cmsFree(self ->ContextID, T); } @@ -2094,7 +2116,7 @@ Error: cmsUNUSED_PARAMETER(SizeOfTag); } -// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. +// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. // Some empty defaults are created for missing parts static @@ -2106,7 +2128,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; _cmsStageMatrixData* MatMPE = NULL; _cmsStageCLutData* clut = NULL; - int InputChannels, OutputChannels, clutPoints; + int i, InputChannels, OutputChannels, clutPoints; // Disassemble the LUT into components. mpe = NewLUT -> Elements; @@ -2115,18 +2137,18 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io MatMPE = (_cmsStageMatrixData*) mpe ->Data; mpe = mpe -> Next; } - + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; mpe = mpe -> Next; } - + if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { clut = (_cmsStageCLutData*) mpe -> Data; mpe = mpe ->Next; } - + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; mpe = mpe -> Next; @@ -2140,7 +2162,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io InputChannels = cmsPipelineInputChannels(NewLUT); OutputChannels = cmsPipelineOutputChannels(NewLUT); - + if (clut == NULL) clutPoints = 0; else @@ -2153,7 +2175,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (MatMPE != NULL) { - + if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; @@ -2181,14 +2203,14 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (PreMPE != NULL) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; } else { - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; } if (PostMPE != NULL) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; } else { - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; - + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + } // The prelinearization table @@ -2196,21 +2218,34 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (PreMPE != NULL) { if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; } + else { + for (i=0; i < InputChannels; i++) { + + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } nTabSize = uipow(OutputChannels, clutPoints, InputChannels); - + if (nTabSize == (cmsUInt32Number) -1) return FALSE; if (nTabSize > 0) { - // The 3D CLUT. - if (clut != NULL) { - if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; - } + // The 3D CLUT. + if (clut != NULL) { + if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; + } } // The postlinearization table if (PostMPE != NULL) { if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; } + else { + for (i=0; i < OutputChannels; i++) { + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } return TRUE; @@ -2228,7 +2263,7 @@ void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsU static void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsPipelineFree((cmsPipeline*) Ptr); return; @@ -2250,7 +2285,7 @@ cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms cmsFloat64Number dOff[3]; cmsStage* Mat; - // Go to address + // Go to address if (!io -> Seek(io, Offset)) return NULL; // Read the Matrix @@ -2267,7 +2302,7 @@ cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; - + Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); return Mat; @@ -2281,7 +2316,7 @@ cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms static cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels) { - cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; cmsUInt8Number Precision; cmsStage* CLUT; @@ -2290,8 +2325,12 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI if (!io -> Seek(io, Offset)) return NULL; if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; - for (i=0; i < cmsMAXCHANNELS; i++) + + for (i=0; i < cmsMAXCHANNELS; i++) { + + if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least GridPoints[i] = gridPoints8[i]; + } if (!_cmsReadUInt8Number(io, &Precision)) return NULL; @@ -2307,27 +2346,30 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI // Precision can be 1 or 2 bytes if (Precision == 1) { - cmsUInt8Number v; - + cmsUInt8Number v; + for (i=0; i < Data ->nEntries; i++) { - if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; - Data ->Tab.T[i] = FROM_8_TO_16(v); + if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; + Data ->Tab.T[i] = FROM_8_TO_16(v); } - - } - else - if (Precision == 2) { - - if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL; - } - else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); - return NULL; - } - - return CLUT; + } + else + if (Precision == 2) { + + if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { + cmsStageFree(CLUT); + return NULL; + } + } + else { + cmsStageFree(CLUT); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return NULL; + } + + return CLUT; } static @@ -2336,7 +2378,7 @@ cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDL cmsTagTypeSignature BaseType; cmsUInt32Number nItems; - BaseType = _cmsReadTypeBase(io); + BaseType = _cmsReadTypeBase(io); switch (BaseType) { case cmsSigCurveType: @@ -2345,7 +2387,7 @@ cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDL case cmsSigParametricCurveType: return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); - default: + default: { char String[5]; @@ -2360,7 +2402,7 @@ cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDL // Read a set of curves from specific offset static cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) -{ +{ cmsToneCurve* Curves[cmsMAXCHANNELS]; cmsUInt32Number i; cmsStage* Lin = NULL; @@ -2368,39 +2410,40 @@ cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (nCurves > cmsMAXCHANNELS) return FALSE; if (!io -> Seek(io, Offset)) return FALSE; - - for (i=0; i < nCurves; i++) + + for (i=0; i < nCurves; i++) Curves[i] = NULL; for (i=0; i < nCurves; i++) { - Curves[i] = ReadEmbeddedCurve(self, io); + Curves[i] = ReadEmbeddedCurve(self, io); if (Curves[i] == NULL) goto Error; - if (!_cmsReadAlignment(io)) goto Error; + if (!_cmsReadAlignment(io)) goto Error; + } - + Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); - + Error: - for (i=0; i < nCurves; i++) + for (i=0; i < nCurves; i++) cmsFreeToneCurve(Curves[i]); return Lin; } -// LutAtoB type +// LutAtoB type -// This structure represents a colour transform. The type contains up to five processing -// elements which are stored in the AtoBTag tag in the following order: a set of one -// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, +// This structure represents a colour transform. The type contains up to five processing +// elements which are stored in the AtoBTag tag in the following order: a set of one +// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, // a multidimensional lookup table, and a set of one dimensional output curves. // Data are processed using these elements via the following sequence: // //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). // /* -It is possible to use any or all of these processing elements. At least one processing element +It is possible to use any or all of these processing elements. At least one processing element must be included.Only the following combinations are allowed: B @@ -2414,14 +2457,13 @@ static void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { cmsUInt32Number BaseOffset; - cmsUInt8Number inputChan; // Number of input channels - cmsUInt8Number outputChan; // Number of output channels - cmsUInt32Number offsetB; // Offset to first "B" curve - cmsUInt32Number offsetMat; // Offset to matrix - cmsUInt32Number offsetM; // Offset to first "M" curve - cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT cmsUInt32Number offsetA; // Offset to first "A" curve - cmsStage* mpe; cmsPipeline* NewLUT = NULL; @@ -2429,9 +2471,9 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; - + if (!_cmsReadUInt16Number(io, NULL)) return NULL; - + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; @@ -2443,32 +2485,35 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c if (NewLUT == NULL) return NULL; if (offsetA!= 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan); - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) + goto Error; } if (offsetC != 0) { - mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; } if (offsetM != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) + goto Error; } - if (offsetMat != 0) { - mpe = ReadMatrix(self, io, BaseOffset + offsetMat); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (offsetMat != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; } - if (offsetB != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (offsetB != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) + goto Error; } - + *nItems = 1; return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; cmsUNUSED_PARAMETER(SizeOfTag); } @@ -2476,7 +2521,7 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c // Write a set of curves static cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) -{ +{ _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; // Write the Matrix @@ -2513,7 +2558,7 @@ cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms // Write a set of curves static cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) -{ +{ cmsUInt32Number i, n; cmsTagTypeSignature CurrentType; cmsToneCurve** Curves; @@ -2527,7 +2572,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // If this is a table-based curve, use curve type even on V4 CurrentType = Type; - if (Curves[i] ->nSegments == 0) + if ((Curves[i] ->nSegments == 0)|| + ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) CurrentType = cmsSigCurveType; else if (Curves[i] ->Segments[0].Type < 0) @@ -2545,13 +2591,13 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; break; - default: + default: { char String[5]; _cmsTagSignature2String(String, (cmsTagSignature) Type); cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); - } + } return FALSE; } @@ -2566,17 +2612,17 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, static cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) { - cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. - cmsUInt32Number i; + cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt32Number i; _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; if (CLUT ->HasFloatValues) { - cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); + cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); return FALSE; } memset(gridPoints, 0, sizeof(gridPoints)); - for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) + for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; @@ -2591,16 +2637,16 @@ cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUIn for (i=0; i < CLUT->nEntries; i++) { - if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; + if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; } } - else + else if (Precision == 2) { if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; } else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); return FALSE; } @@ -2628,10 +2674,10 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (Lut ->Elements != NULL) if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, - cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, + cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); return FALSE; @@ -2661,7 +2707,7 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io offsetA = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; } - + if (CLUT != NULL) { offsetC = io ->Tell(io) - BaseOffset; if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; @@ -2672,7 +2718,7 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io offsetM = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; } - + if (Matrix != NULL) { offsetMat = io ->Tell(io) - BaseOffset; if (!WriteMatrix(self, io, Matrix)) return FALSE; @@ -2683,7 +2729,7 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io offsetB = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; } - + CurrentPos = io ->Tell(io); if (!io ->Seek(io, DirectoryPos)) return FALSE; @@ -2695,7 +2741,7 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; if (!io ->Seek(io, CurrentPos)) return FALSE; - + return TRUE; cmsUNUSED_PARAMETER(nItems); @@ -2713,7 +2759,7 @@ void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cms static void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsPipelineFree((cmsPipeline*) Ptr); return; @@ -2721,20 +2767,19 @@ void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) } -// LutBToA type +// LutBToA type static void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { - cmsUInt8Number inputChan; // Number of input channels - cmsUInt8Number outputChan; // Number of output channels + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels cmsUInt32Number BaseOffset; // Actual position in file - cmsUInt32Number offsetB; // Offset to first "B" curve - cmsUInt32Number offsetMat; // Offset to matrix - cmsUInt32Number offsetM; // Offset to first "M" curve - cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT cmsUInt32Number offsetA; // Offset to first "A" curve - cmsStage* mpe; cmsPipeline* NewLUT = NULL; @@ -2745,7 +2790,7 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c // Padding if (!_cmsReadUInt16Number(io, NULL)) return NULL; - + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; @@ -2755,34 +2800,37 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c // Allocates an empty LUT NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); if (NewLUT == NULL) return NULL; - - if (offsetB != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + + if (offsetB != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) + goto Error; } - if (offsetMat != 0) { - mpe = ReadMatrix(self, io, BaseOffset + offsetMat); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (offsetMat != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; } if (offsetM != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) + goto Error; } if (offsetC != 0) { - mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; } if (offsetA!= 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan); - if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) + goto Error; } *nItems = 1; return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; cmsUNUSED_PARAMETER(SizeOfTag); } @@ -2810,25 +2858,25 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) - if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, - cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); return FALSE; } inputChan = cmsPipelineInputChannels(Lut); outputChan = cmsPipelineOutputChannels(Lut); - + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; if (!_cmsWriteUInt16Number(io, 0)) return FALSE; DirectoryPos = io ->Tell(io); - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; - if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; if (!_cmsWriteUInt32Number(io, 0)) return FALSE; if (!_cmsWriteUInt32Number(io, 0)) return FALSE; if (!_cmsWriteUInt32Number(io, 0)) return FALSE; @@ -2838,7 +2886,7 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i offsetA = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; } - + if (CLUT != NULL) { offsetC = io ->Tell(io) - BaseOffset; if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; @@ -2849,10 +2897,10 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i offsetM = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; } - + if (Matrix != NULL) { offsetMat = io ->Tell(io) - BaseOffset; - if (!WriteMatrix(self, io, Matrix)) return FALSE; + if (!WriteMatrix(self, io, Matrix)) return FALSE; } if (B != NULL) { @@ -2860,7 +2908,7 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i offsetB = io ->Tell(io) - BaseOffset; if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; } - + CurrentPos = io ->Tell(io); if (!io ->Seek(io, DirectoryPos)) return FALSE; @@ -2872,7 +2920,7 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; if (!io ->Seek(io, CurrentPos)) return FALSE; - + return TRUE; cmsUNUSED_PARAMETER(nItems); @@ -2891,7 +2939,7 @@ void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cms static void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsPipelineFree((cmsPipeline*) Ptr); return; @@ -2904,8 +2952,8 @@ void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigColorantTableType // ******************************************************************************** /* -The purpose of this tag is to identify the colorants used in the profile by a -unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous +The purpose of this tag is to identify the colorants used in the profile by a +unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous value. The first colorant listed is the colorant of the first device channel of a lut tag. The second colorant listed is the colorant of the second device channel of a lut tag, and so on. @@ -2917,7 +2965,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER cmsUInt32Number i, Count; cmsNAMEDCOLORLIST* List; char Name[34]; - cmsUInt16Number PCS[3]; + cmsUInt16Number PCS[3]; if (!_cmsReadUInt32Number(io, &Count)) return NULL; @@ -2935,8 +2983,8 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; - + if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; + } *nItems = 1; @@ -2956,7 +3004,7 @@ Error: static cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; int i, nColors; nColors = cmsNamedColorCount(NamedColorList); @@ -2966,7 +3014,7 @@ cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHAN for (i=0; i < nColors; i++) { char root[33]; - cmsUInt16Number PCS[3]; + cmsUInt16Number PCS[3]; if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; root[32] = 0; @@ -2986,7 +3034,7 @@ static void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) { cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; - return (void*) cmsDupNamedColorList(nc); + return (void*) cmsDupNamedColorList(nc); cmsUNUSED_PARAMETER(n); cmsUNUSED_PARAMETER(self); @@ -2995,7 +3043,7 @@ void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* P static void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); return; @@ -3007,26 +3055,26 @@ void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigNamedColor2Type // ******************************************************************************** // -//The namedColor2Type is a count value and array of structures that provide color -//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional -//device representation of the color are given. Both representations are 16-bit values. -//The device representation corresponds to the header’s “color space of data” field. +//The namedColor2Type is a count value and array of structures that provide color +//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional +//device representation of the color are given. Both representations are 16-bit values. +//The device representation corresponds to the header’s “color space of data” field. //This representation should be consistent with the “number of device components” //field in the namedColor2Type. If this field is 0, device coordinates are not provided. -//The PCS representation corresponds to the header’s PCS field. The PCS representation -//is always provided. Color names are fixed-length, 32-byte fields including null -//termination. In order to maintain maximum portability, it is strongly recommended +//The PCS representation corresponds to the header’s PCS field. The PCS representation +//is always provided. Color names are fixed-length, 32-byte fields including null +//termination. In order to maintain maximum portability, it is strongly recommended //that special characters of the 7-bit ASCII set not be used. static void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { - cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use - cmsUInt32Number count; // Count of named colors - cmsUInt32Number nDeviceCoords; // Num of device coordinates - char prefix[32]; // Prefix for each color name - char suffix[32]; // Suffix for each color name + cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use + cmsUInt32Number count; // Count of named colors + cmsUInt32Number nDeviceCoords; // Num of device coordinates + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name cmsNAMEDCOLORLIST* v; cmsUInt32Number i; @@ -3081,8 +3129,8 @@ static cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; - char prefix[32]; // Prefix for each color name - char suffix[32]; // Suffix for each color name + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name int i, nColors; nColors = cmsNamedColorCount(NamedColorList); @@ -3107,7 +3155,7 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; if (!io ->Write(io, 32 , Root)) return FALSE; - if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; + if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; } @@ -3131,7 +3179,7 @@ void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, static void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); return; @@ -3143,11 +3191,11 @@ void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigProfileSequenceDescType // ******************************************************************************** -// This type is an array of structures, each of which contains information from the -// header fields and tags from the original profiles which were combined to create -// the final profile. The order of the structures is the order in which the profiles -// were combined and includes a structure for the final profile. This provides a -// description of the profile sequence from source to destination, +// This type is an array of structures, each of which contains information from the +// header fields and tags from the original profiles which were combined to create +// the final profile. The order of the structures is the order in which the profiles +// were combined and includes a structure for the final profile. This provides a +// description of the profile sequence from source to destination, // typically used with the DeviceLink profile. static @@ -3156,19 +3204,19 @@ cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature BaseType; cmsUInt32Number nItems; - BaseType = _cmsReadTypeBase(io); + BaseType = _cmsReadTypeBase(io); switch (BaseType) { case cmsSigTextType: if (*mlu) cmsMLUfree(*mlu); *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); - return (*mlu != NULL); + return (*mlu != NULL); case cmsSigTextDescriptionType: if (*mlu) cmsMLUfree(*mlu); *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); - return (*mlu != NULL); + return (*mlu != NULL); /* TBD: Size is needed for MLU, and we have no idea on which is the available size @@ -3189,48 +3237,52 @@ void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOH { cmsSEQ* OutSeq; cmsUInt32Number i, Count; - + *nItems = 0; - - if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; SizeOfTag -= sizeof(cmsUInt32Number); - + OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); if (OutSeq == NULL) return NULL; OutSeq ->n = Count; - + // Get structures as well for (i=0; i < Count; i++) { - + cmsPSEQDESC* sec = &OutSeq -> seq[i]; - if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; + if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; SizeOfTag -= sizeof(cmsUInt64Number); - if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL; - if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL; + if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error; + if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error; } *nItems = 1; return OutSeq; + +Error: + cmsFreeProfileSequenceDescription(OutSeq); + return NULL; } @@ -3239,8 +3291,8 @@ void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOH static cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) { - if (self ->ICCVersion < 0x4000000) { - + if (self ->ICCVersion < 0x4000000) { + if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; return Type_Text_Description_Write(self, io, Text, 1); } @@ -3258,21 +3310,21 @@ cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cm cmsUInt32Number i; if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; - + for (i=0; i < Seq ->n; i++) { cmsPSEQDESC* sec = &Seq -> seq[i]; if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; - if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE; + if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; - - if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; - if (!SaveDescription(self, io, sec ->Model)) return FALSE; + + if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; + if (!SaveDescription(self, io, sec ->Model)) return FALSE; } - - return TRUE; + + return TRUE; cmsUNUSED_PARAMETER(nItems); } @@ -3280,7 +3332,7 @@ cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cm static void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ +{ return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); cmsUNUSED_PARAMETER(n); @@ -3289,7 +3341,7 @@ void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const v static void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); return; @@ -3301,23 +3353,23 @@ void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* P // Type cmsSigProfileSequenceIdType // ******************************************************************************** /* -In certain workflows using ICC Device Link Profiles, it is necessary to identify the +In certain workflows using ICC Device Link Profiles, it is necessary to identify the original profiles that were combined to create the Device Link Profile. -This type is an array of structures, each of which contains information for +This type is an array of structures, each of which contains information for identification of a profile used in a sequence */ static -cmsBool ReadSeqID(struct _cms_typehandler_struct* self, +cmsBool ReadSeqID(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag) { cmsSEQ* OutSeq = (cmsSEQ*) Cargo; cmsPSEQDESC* seq = &OutSeq ->seq[n]; - + if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; @@ -3339,7 +3391,7 @@ void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHAN BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); // Get table count - if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; SizeOfTag -= sizeof(cmsUInt32Number); // Allocate an empty structure @@ -3362,18 +3414,18 @@ void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHAN static -cmsBool WriteSeqID(struct _cms_typehandler_struct* self, +cmsBool WriteSeqID(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag) { cmsSEQ* Seq = (cmsSEQ*) Cargo; - + if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; // Store here the MLU - if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; + if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; return TRUE; @@ -3388,13 +3440,13 @@ cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsI // Keep the base offset BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); - + // This is the table count if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; // This is the position table and content if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; - + return TRUE; cmsUNUSED_PARAMETER(nItems); @@ -3402,7 +3454,7 @@ cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsI static void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) -{ +{ return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); cmsUNUSED_PARAMETER(n); @@ -3411,7 +3463,7 @@ void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const voi static void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) -{ +{ cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); return; @@ -3487,7 +3539,7 @@ cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; - // Then black generation + // Then black generation if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; @@ -3496,7 +3548,7 @@ cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io Text = (char*) _cmsMalloc(self ->ContextID, TextSize); if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; - if (!io ->Write(io, TextSize, Text)) return FALSE; + if (!io ->Write(io, TextSize, Text)) return FALSE; _cmsFree(self ->ContextID, Text); return TRUE; @@ -3525,11 +3577,11 @@ static void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) { cmsUcrBg* Src = (cmsUcrBg*) Ptr; - + if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); if (Src ->Desc) cmsMLUfree(Src ->Desc); - + _cmsFree(self ->ContextID, Ptr); } @@ -3559,12 +3611,12 @@ cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* i cmsUInt32Number Count; char* Text; - if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; - + if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; + if (!_cmsReadUInt32Number(io, &Count)) return FALSE; if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; - if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; + if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; Text = (char*) _cmsMalloc(self ->ContextID, Count+1); if (Text == NULL) return FALSE; @@ -3575,28 +3627,28 @@ cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* i } Text[Count] = 0; - + cmsMLUsetASCII(mlu, "PS", Section, Text); _cmsFree(self ->ContextID, Text); *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); - return TRUE; + return TRUE; } static cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) { cmsUInt32Number TextSize; - char* Text; - + char* Text; + TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); Text = (char*) _cmsMalloc(self ->ContextID, TextSize); - if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; + if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; - if (!io ->Write(io, TextSize, Text)) return FALSE; + if (!io ->Write(io, TextSize, Text)) return FALSE; _cmsFree(self ->ContextID, Text); return TRUE; @@ -3613,7 +3665,7 @@ void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; - + *nItems = 1; return (void*) mlu; @@ -3655,7 +3707,7 @@ void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cm static void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ +{ cmsMLUfree((cmsMLU*) Ptr); return; @@ -3674,12 +3726,12 @@ void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io { cmsScreening* sc = NULL; cmsUInt32Number i; - + sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); if (sc == NULL) return NULL; *nItems = 0; - + if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; @@ -3688,8 +3740,8 @@ void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io for (i=0; i < sc ->nChannels; i++) { - if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; - if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; } @@ -3699,7 +3751,7 @@ void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io return (void*) sc; Error: - if (sc != NULL) + if (sc != NULL) _cmsFree(self ->ContextID, sc); return NULL; @@ -3711,9 +3763,9 @@ Error: static cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsScreening* sc = (cmsScreening* ) Ptr; + cmsScreening* sc = (cmsScreening* ) Ptr; cmsUInt32Number i; - + if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; @@ -3750,20 +3802,20 @@ void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) // Type cmsSigViewingConditionsType // ******************************************************************************** // -//This type represents a set of viewing condition parameters including: -//CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’ +//This type represents a set of viewing condition parameters including: +//CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’ //surround tristimulus values. static void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { cmsICCViewingConditions* vc = NULL; - + vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); if (vc == NULL) return NULL; *nItems = 0; - + if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; @@ -3773,7 +3825,7 @@ void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHAN return (void*) vc; Error: - if (vc != NULL) + if (vc != NULL) _cmsFree(self ->ContextID, vc); return NULL; @@ -3785,8 +3837,8 @@ Error: static cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; - + cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; + if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; @@ -3830,7 +3882,7 @@ void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUI static void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) -{ +{ cmsStageFree((cmsStage*) Ptr); return; @@ -3846,16 +3898,16 @@ void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) // Read an embedded segmented curve static cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) -{ +{ cmsCurveSegSignature ElementSig; cmsUInt32Number i, j; cmsUInt16Number nSegments; cmsCurveSegment* Segments; cmsToneCurve* Curve; cmsFloat32Number PrevBreak = -1E22F; // - infinite - + // Take signature and channels for each element. - if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; // That should be a segmented curve if (ElementSig != cmsSigSegmentedCurve) return NULL; @@ -3884,11 +3936,11 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; if (!_cmsReadUInt32Number(io, NULL)) goto Error; - + switch (ElementSig) { case cmsSigFormulaCurveSeg: { - + cmsUInt16Number Type; cmsUInt32Number ParamsByType[] = {4, 5, 5 }; @@ -3930,7 +3982,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); } - return NULL; + return NULL; } } @@ -3950,10 +4002,10 @@ Error: static -cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, +cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag) { cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; @@ -4013,10 +4065,10 @@ cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) cmsCurveSegment* Segments = g ->Segments; cmsUInt32Number nSegments = g ->nSegments; - if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; - if (!_cmsWriteUInt16Number(io, 0)) goto Error; + if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; + if (!_cmsWriteUInt16Number(io, 0)) goto Error; // Write the break-points for (i=0; i < nSegments - 1; i++) { @@ -4058,7 +4110,7 @@ cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) for (j=0; j < ParamsByType[Type]; j++) { if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; } - } + } // It seems there is no need to align. Code is here, and for safety commented out // if (!_cmsWriteAlignment(io)) goto Error; @@ -4072,10 +4124,10 @@ Error: static -cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, +cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag) { _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; @@ -4089,7 +4141,7 @@ cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, // Write a curve, checking first for validity static cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ +{ cmsUInt32Number BaseOffset; cmsStage* mpe = (cmsStage*) Ptr; _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; @@ -4099,8 +4151,8 @@ cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* // Write the header. Since those are curves, input and output channels are same if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; - - if (!WritePositionTable(self, io, 0, + + if (!WritePositionTable(self, io, 0, mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; @@ -4121,14 +4173,14 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io { cmsStage* mpe; cmsUInt16Number InputChans, OutputChans; - cmsUInt32Number nElems, i; + cmsUInt32Number nElems, i; cmsFloat64Number* Matrix; cmsFloat64Number* Offsets; if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - + nElems = InputChans * OutputChans; // Input and output chans may be ANY (up to 0xffff) @@ -4137,7 +4189,7 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); if (Offsets == NULL) { - + _cmsFree(self ->ContextID, Matrix); return NULL; } @@ -4146,7 +4198,7 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io cmsFloat32Number v; - if (!_cmsReadFloat32Number(io, &v)) return NULL; + if (!_cmsReadFloat32Number(io, &v)) return NULL; Matrix[i] = v; } @@ -4155,7 +4207,7 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io cmsFloat32Number v; - if (!_cmsReadFloat32Number(io, &v)) return NULL; + if (!_cmsReadFloat32Number(io, &v)) return NULL; Offsets[i] = v; } @@ -4178,13 +4230,13 @@ cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER cmsStage* mpe = (cmsStage*) Ptr; _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; - if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; nElems = mpe ->InputChannels * mpe ->OutputChannels; for (i=0; i < nElems; i++) { - if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; } @@ -4192,10 +4244,10 @@ cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER if (Matrix ->Offset == NULL) { - if (!_cmsWriteFloat32Number(io, 0)) return FALSE; + if (!_cmsWriteFloat32Number(io, 0)) return FALSE; } else { - if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; } } @@ -4215,13 +4267,16 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Dimensions8[16]; cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; _cmsStageCLutData* clut; - + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - + + if (InputChans == 0) goto Error; + if (OutputChans == 0) goto Error; + if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) goto Error; - + // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i]; @@ -4233,11 +4288,11 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Read the data clut = (_cmsStageCLutData*) mpe ->Data; for (i=0; i < clut ->nEntries; i++) { - + if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error; } - *nItems = 1; + *nItems = 1; return mpe; Error: @@ -4251,7 +4306,7 @@ Error: // Write a CLUT in floating point static cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ +{ cmsUInt8Number Dimensions8[16]; cmsUInt32Number i; cmsStage* mpe = (cmsStage*) Ptr; @@ -4259,7 +4314,7 @@ cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* // Check for maximum number of channels if (mpe -> InputChannels > 15) return FALSE; - + // Only floats are supported in MPE if (clut ->HasFloatValues == FALSE) return FALSE; @@ -4268,13 +4323,13 @@ cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* memset(Dimensions8, 0, sizeof(Dimensions8)); - for (i=0; i < mpe ->InputChannels; i++) + for (i=0; i < mpe ->InputChannels; i++) Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; if (!io ->Write(io, 16, Dimensions8)) return FALSE; for (i=0; i < clut ->nEntries; i++) { - + if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; } @@ -4289,28 +4344,29 @@ cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* // This is the list of built-in MPE types static _cmsTagTypeLinkedList SupportedMPEtypes[] = { -{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[1] }, // Ignore those elements for now -{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[2] }, // (That's what the spec says) +{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now +{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says) {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, }; -#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList)) +_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; static -cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, +cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Cargo, - cmsUInt32Number n, + cmsUInt32Number n, cmsUInt32Number SizeOfTag) { cmsStageSignature ElementSig; cmsTagTypeHandler* TypeHandler; - cmsStage *mpe = NULL; cmsUInt32Number nItems; cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + // Take signature and channels for each element. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; @@ -4319,14 +4375,14 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, if (!_cmsReadUInt32Number(io, NULL)) return FALSE; // Read diverse MPE types - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - // An unknown element was found. + // An unknown element was found. cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); return FALSE; } @@ -4336,11 +4392,8 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, if (TypeHandler ->ReadPtr != NULL) { // This is a real element which should be read and processed - mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag); - if (mpe == NULL) return FALSE; - - // All seems ok, insert element - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) + return FALSE; } return TRUE; @@ -4353,7 +4406,7 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, // This is the main dispatcher for MPE static void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -{ +{ cmsUInt16Number InputChans, OutputChans; cmsUInt32Number ElementCount; cmsPipeline *NewLUT = NULL; @@ -4364,8 +4417,8 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU // Read channels and element count if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + // Allocates an empty LUT NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); if (NewLUT == NULL) return NULL; @@ -4390,7 +4443,7 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU // This one is a liitle bit more complex, so we don't use position tables this time. static cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) -{ +{ cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; int inputChan, outputChan; cmsUInt32Number ElemCount; @@ -4399,6 +4452,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v cmsPipeline* Lut = (cmsPipeline*) Ptr; cmsStage* Elem = Lut ->Elements; cmsTagTypeHandler* TypeHandler; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); @@ -4406,10 +4460,10 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v outputChan = cmsPipelineOutputChannels(Lut); ElemCount = cmsPipelineStageCount(Lut); - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; // Write the head @@ -4421,7 +4475,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v // Write a fake directory to be filled latter on for (i=0; i < ElemCount; i++) { - if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size } @@ -4432,20 +4486,20 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v ElementSig = Elem ->Type; - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - // An unknow element was found. + // An unknow element was found. cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); goto Error; } - if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; - if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; Before = io ->Tell(io); if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; if (!_cmsWriteAlignment(io)) goto Error; @@ -4461,8 +4515,8 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v if (!io ->Seek(io, DirectoryPos)) goto Error; for (i=0; i < ElemCount; i++) { - if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; - if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; } if (!io ->Seek(io, CurrentPos)) goto Error; @@ -4491,7 +4545,7 @@ void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUIn static void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) -{ +{ cmsPipelineFree((cmsPipeline*) Ptr); return; @@ -4516,9 +4570,9 @@ typedef struct { static -void *Type_vcgt_Read(struct _cms_typehandler_struct* self, - cmsIOHANDLER* io, - cmsUInt32Number* nItems, +void *Type_vcgt_Read(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { cmsUInt32Number TagType, n, i; @@ -4528,7 +4582,7 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, // Read tag type if (!_cmsReadUInt32Number(io, &TagType)) return NULL; - + // Allocate space for the array Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); if (Curves == NULL) return NULL; @@ -4537,7 +4591,7 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, switch (TagType) { // Gamma is stored as a table - case cmsVideoCardGammaTableType: + case cmsVideoCardGammaTableType: { cmsUInt16Number nChannels, nElems, nBytes; @@ -4546,16 +4600,16 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, if (nChannels != 3) { cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); - goto Error; + goto Error; } // Get Table element count and bytes per element if (!_cmsReadUInt16Number(io, &nElems)) goto Error; if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; - - // Adobe's quirk fixup. Fixing broken profiles... - if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) - nBytes = 2; + + // Adobe's quirk fixup. Fixing broken profiles... + if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) + nBytes = 2; // Populate tone curves @@ -4586,17 +4640,17 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, // Unsupported default: cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); - goto Error; + goto Error; } } // For all 3 channels } break; // In this case, gamma is stored as a formula - case cmsVideoCardGammaFormulaType: + case cmsVideoCardGammaFormulaType: { _cmsVCGTGAMMA Colorant[3]; - + // Populate tone curves for (n=0; n < 3; n++) { @@ -4605,16 +4659,16 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; - + // Parametric curve type 5 is: // Y = (aX + b)^Gamma + e | X >= d // Y = cX + f | X < d // vcgt formula is: // Y = (Max – Min) * (X ^ Gamma) + Min - + // So, the translation is - // a = (Max – Min) ^ ( 1 / Gamma) + // a = (Max – Min) ^ ( 1 / Gamma) // e = Min // b=c=d=f=0 @@ -4625,7 +4679,7 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, Params[4] = 0; Params[5] = Colorant[n].Min; Params[6] = 0; - + Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); if (Curves[n] == NULL) goto Error; } @@ -4633,7 +4687,7 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, break; // Unsupported - default: + default: cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); goto Error; } @@ -4663,7 +4717,7 @@ cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsGetToneCurveParametricType(Curves[1]) == 5 && cmsGetToneCurveParametricType(Curves[2]) == 5) { - if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; // Save parameters for (i=0; i < 3; i++) { @@ -4683,10 +4737,10 @@ cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, else { // Always store as a table of 256 words - if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; - if (!_cmsWriteUInt16Number(io, 3)) return FALSE; - if (!_cmsWriteUInt16Number(io, 256)) return FALSE; - if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; + if (!_cmsWriteUInt16Number(io, 256)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; for (i=0; i < 3; i++) { for (j=0; j < 256; j++) { @@ -4694,7 +4748,7 @@ cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); - if (!_cmsWriteUInt16Number(io, n)) return FALSE; + if (!_cmsWriteUInt16Number(io, n)) return FALSE; } } } @@ -4731,6 +4785,443 @@ void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) _cmsFree(self ->ContextID, Ptr); } + +// ******************************************************************************** +// Type cmsSigDictType +// ******************************************************************************** + +// Single column of the table can point to wchar or MLUC elements. Holds arrays of data +typedef struct { + cmsContext ContextID; + cmsUInt32Number *Offsets; + cmsUInt32Number *Sizes; +} _cmsDICelem; + +typedef struct { + _cmsDICelem Name, Value, DisplayName, DisplayValue; + +} _cmsDICarray; + +// Allocate an empty array element +static +cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) +{ + e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); + if (e->Offsets == NULL) return FALSE; + + e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); + if (e->Sizes == NULL) { + + _cmsFree(ContextID, e -> Offsets); + return FALSE; + } + + e ->ContextID = ContextID; + return TRUE; +} + +// Free an array element +static +void FreeElem(_cmsDICelem* e) +{ + if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); + if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); + e->Offsets = e ->Sizes = NULL; +} + +// Get rid of whole array +static +void FreeArray( _cmsDICarray* a) +{ + if (a ->Name.Offsets != NULL) FreeElem(&a->Name); + if (a ->Value.Offsets != NULL) FreeElem(&a ->Value); + if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName); + if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue); +} + + +// Allocate whole array +static +cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) +{ + // Empty values + memset(a, 0, sizeof(_cmsDICarray)); + + // On depending on record size, create column arrays + if (!AllocElem(ContextID, &a ->Name, Count)) goto Error; + if (!AllocElem(ContextID, &a ->Value, Count)) goto Error; + + if (Length > 16) { + if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error; + + } + if (Length > 24) { + if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error; + } + return TRUE; + +Error: + FreeArray(a); + return FALSE; +} + +// Read one element +static +cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset) +{ + if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; + if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; + + // An offset of zero has special meaning and shal be preserved + if (e ->Offsets[i] > 0) + e ->Offsets[i] += BaseOffset; + return TRUE; +} + + +static +cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number i; + + // Read column arrays + for (i=0; i < Count; i++) { + + if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; + if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; + + if (Length > 16) { + + if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; + + } + + if (Length > 24) { + + if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; + } + } + return TRUE; +} + + +// Write one element +static +cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i) +{ + if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE; + if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE; + + return TRUE; +} + +static +cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) +{ + cmsUInt32Number i; + + for (i=0; i < Count; i++) { + + if (!WriteOneElem(io, &a -> Name, i)) return FALSE; + if (!WriteOneElem(io, &a -> Value, i)) return FALSE; + + if (Length > 16) { + + if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE; + } + + if (Length > 24) { + + if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE; + } + } + + return TRUE; +} + +static +cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr) +{ + + cmsUInt32Number nChars; + + // Special case for undefined strings (see ICC Votable + // Proposal Submission, Dictionary Type and Metadata TAG Definition) + if (e -> Offsets[i] == 0) { + + *wcstr = NULL; + return TRUE; + } + + if (!io -> Seek(io, e -> Offsets[i])) return FALSE; + + nChars = e ->Sizes[i] / sizeof(cmsUInt16Number); + + + *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t)); + if (*wcstr == NULL) return FALSE; + + if (!_cmsReadWCharArray(io, nChars, *wcstr)) { + _cmsFree(e ->ContextID, *wcstr); + return FALSE; + } + + // End of string marker + (*wcstr)[nChars] = 0; + return TRUE; +} + +static +cmsUInt32Number mywcslen(const wchar_t *s) +{ + const wchar_t *p; + + p = s; + while (*p) + p++; + + return (cmsUInt32Number)(p - s); +} + +static +cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number Before = io ->Tell(io); + cmsUInt32Number n; + + e ->Offsets[i] = Before - BaseOffset; + + if (wcstr == NULL) { + e ->Sizes[i] = 0; + e ->Offsets[i] = 0; + return TRUE; + } + + n = mywcslen(wcstr); + if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE; + + e ->Sizes[i] = io ->Tell(io) - Before; + return TRUE; +} + +static +cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu) +{ + cmsUInt32Number nItems = 0; + + // A way to get null MLUCs + if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) { + + *mlu = NULL; + return TRUE; + } + + if (!io -> Seek(io, e -> Offsets[i])) return FALSE; + + *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]); + return *mlu != NULL; +} + +static +cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number Before; + + // Special case for undefined strings (see ICC Votable + // Proposal Submission, Dictionary Type and Metadata TAG Definition) + if (mlu == NULL) { + e ->Sizes[i] = 0; + e ->Offsets[i] = 0; + return TRUE; + } + + Before = io ->Tell(io); + e ->Offsets[i] = Before - BaseOffset; + + if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; + + e ->Sizes[i] = io ->Tell(io) - Before; + return TRUE; +} + + +static +void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsHANDLE hDict; + cmsUInt32Number i, Count, Length; + cmsUInt32Number BaseOffset; + _cmsDICarray a; + wchar_t *NameWCS = NULL, *ValueWCS = NULL; + cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; + cmsBool rc; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Get name-value record count + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Get rec length + if (!_cmsReadUInt32Number(io, &Length)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Check for valid lengths + if (Length != 16 && Length != 24 && Length != 32) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length); + return NULL; + } + + // Creates an empty dictionary + hDict = cmsDictAlloc(self -> ContextID); + if (hDict == NULL) return NULL; + + // On depending on record size, create column arrays + if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; + + // Read column arrays + if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; + + // Seek to each element and read it + for (i=0; i < Count; i++) { + + if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error; + if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error; + + if (Length > 16) { + if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error; + } + + if (Length > 24) { + if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; + } + + if (NameWCS == NULL || ValueWCS == NULL) { + + cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); + rc = FALSE; + } + else { + + rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); + } + + if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); + if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); + if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); + if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); + + if (!rc) goto Error; + } + + FreeArray(&a); + *nItems = 1; + return (void*) hDict; + +Error: + FreeArray(&a); + cmsDictFree(hDict); + return NULL; +} + + +static +cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsHANDLE hDict = (cmsHANDLE) Ptr; + const cmsDICTentry* p; + cmsBool AnyName, AnyValue; + cmsUInt32Number i, Count, Length; + cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset; + _cmsDICarray a; + + if (hDict == NULL) return FALSE; + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Let's inspect the dictionary + Count = 0; AnyName = FALSE; AnyValue = FALSE; + for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) { + + if (p ->DisplayName != NULL) AnyName = TRUE; + if (p ->DisplayValue != NULL) AnyValue = TRUE; + Count++; + } + + Length = 16; + if (AnyName) Length += 8; + if (AnyValue) Length += 8; + + if (!_cmsWriteUInt32Number(io, Count)) return FALSE; + if (!_cmsWriteUInt32Number(io, Length)) return FALSE; + + // Keep starting position of offsets table + DirectoryPos = io ->Tell(io); + + // Allocate offsets array + if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error; + + // Write a fake directory to be filled latter on + if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; + + // Write each element. Keep track of the size as well. + p = cmsDictGetEntryList(hDict); + for (i=0; i < Count; i++) { + + if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error; + if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error; + + if (p ->DisplayName != NULL) { + if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error; + } + + if (p ->DisplayValue != NULL) { + if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error; + } + + p = cmsDictNextEntry(p); + } + + // Write the directory + CurrentPos = io ->Tell(io); + if (!io ->Seek(io, DirectoryPos)) goto Error; + + if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; + + if (!io ->Seek(io, CurrentPos)) goto Error; + + FreeArray(&a); + return TRUE; + +Error: + FreeArray(&a); + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDictDup((cmsHANDLE) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsDictFree((cmsHANDLE) Ptr); + cmsUNUSED_PARAMETER(self); +} + + // ******************************************************************************** // Type support main routines // ******************************************************************************** @@ -4768,29 +5259,101 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = { {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] }, {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] }, {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] }, +{TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] }, {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } }; -#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) - -// Both kind of plug-ins share same structure -cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data) + +_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; + + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagTypeList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src, + int loc) { - return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); + _cmsTagTypePluginChunkType newHead = { NULL }; + _cmsTagTypeLinkedList* entry; + _cmsTagTypeLinkedList* Anterior = NULL; + _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; + + // Walk the list copying all nodes + for (entry = head->TagTypes; + entry != NULL; + entry = entry ->Next) { + + _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TagTypes == NULL) + newHead.TagTypes = newEntry; + } + + ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); } -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data) + +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) { - return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, TagTypePlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } +} + +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, MPEPlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } + +} + + +// Both kind of plug-ins share same structure +cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) +{ + return RegisterTypesPlugin(id, Data, TagTypePlugin); +} + +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) +{ + return RegisterTypesPlugin(id, Data,MPEPlugin); } // Wrapper for tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig) +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) { - return GetHandler(sig, SupportedTagTypes); + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); + + return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); } - + // ******************************************************************************** // Tag support main routines // ******************************************************************************** @@ -4806,21 +5369,21 @@ typedef struct _cmsTagLinkedList_st { // This is the list of built-in tags static _cmsTagLinkedList SupportedTags[] = { - { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, + { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, - + // Allow corbis and its broken XYZ type { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, - + { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, - { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, + { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, @@ -4861,89 +5424,138 @@ static _cmsTagLinkedList SupportedTags[] = { { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, - { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, - { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, - { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, - { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, - { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, - { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, + { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, + { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, + { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, + { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, + { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, + { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, - { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, - { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, + { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, + { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, - { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, - { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, - { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, - { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, - { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, - { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, - { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, - { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, - - { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, - { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, + { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, + { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, + { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, + { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, + { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, + { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, + { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, + { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, + + { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, + { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, + + { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, + { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, + { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, + { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, + { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL} - { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, - { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, - { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL} }; /* Not supported Why - ======================= ========================================= - cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! - cmsSigNamedColorTag ==> Deprecated - cmsSigDataTag ==> Ancient, unused - cmsSigDeviceSettingsTag ==> Deprecated, useless -*/ + ======================= ========================================= + cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! + cmsSigNamedColorTag ==> Deprecated + cmsSigDataTag ==> Ancient, unused + cmsSigDeviceSettingsTag ==> Deprecated, useless +*/ -#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) -cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data) +_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTagPluginChunkType newHead = { NULL }; + _cmsTagLinkedList* entry; + _cmsTagLinkedList* Anterior = NULL; + _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; + + // Walk the list copying all nodes + for (entry = head->Tag; + entry != NULL; + entry = entry ->Next) { + + _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Tag == NULL) + newHead.Tag = newEntry; + } + + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); +} + +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + DupTagList(ctx, src); + } + else { + static _cmsTagPluginChunkType TagPluginChunk = { NULL }; + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); + } + +} + +cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginTag* Plugin = (cmsPluginTag*) Data; - _cmsTagLinkedList *pt, *Anterior; - + _cmsTagLinkedList *pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); if (Data == NULL) { - - SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL; + + TagPluginChunk->Tag = NULL; return TRUE; } - pt = Anterior = SupportedTags; - while (pt != NULL) { - - if (Plugin->Signature == pt -> Signature) { - pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - - pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList)); + pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); if (pt == NULL) return FALSE; pt ->Signature = Plugin ->Signature; - pt ->Descriptor = Plugin ->Descriptor; - pt ->Next = NULL; - - if (Anterior != NULL) Anterior -> Next = pt; + pt ->Descriptor = Plugin ->Descriptor; + pt ->Next = TagPluginChunk ->Tag; + TagPluginChunk ->Tag = pt; + return TRUE; } // Return a descriptor for a given tag or NULL -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig) +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) { _cmsTagLinkedList* pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); - for (pt = SupportedTags; + for (pt = TagPluginChunk->Tag; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } + + for (pt = SupportedTags; pt != NULL; pt = pt ->Next) { diff --git a/thirdparty/liblcms2/src/cmsvirt.c b/thirdparty/liblcms2/src/cmsvirt.c index 807bd223..b324c990 100644 --- a/thirdparty/liblcms2/src/cmsvirt.c +++ b/thirdparty/liblcms2/src/cmsvirt.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -35,7 +35,7 @@ cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) cmsMLU *DescriptionMLU, *CopyrightMLU; cmsBool rc = FALSE; cmsContext ContextID = cmsGetProfileContextID(hProfile); - + DescriptionMLU = cmsMLUalloc(ContextID, 1); CopyrightMLU = cmsMLUalloc(ContextID, 1); @@ -45,8 +45,8 @@ cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error; if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error; - if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; - + if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; + rc = TRUE; Error: @@ -57,7 +57,7 @@ Error: cmsMLUfree(CopyrightMLU); return rc; } - + static cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) @@ -72,10 +72,10 @@ cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) Seq->seq[0].deviceModel = (cmsSignature) 0; #ifdef CMS_DONT_USE_INT64 - Seq->seq[0].attributes[0] = 0; - Seq->seq[0].attributes[1] = 0; + Seq->seq[0].attributes[0] = 0; + Seq->seq[0].attributes[1] = 0; #else - Seq->seq[0].attributes = 0; + Seq->seq[0].attributes = 0; #endif Seq->seq[0].technology = (cmsTechnologySignature) 0; @@ -84,11 +84,11 @@ cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model); if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error; - + rc = TRUE; Error: - if (Seq) + if (Seq) cmsFreeProfileSequenceDescription(Seq); return rc; @@ -103,7 +103,7 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, const cmsCIExyYTRIPLE* Primaries, cmsToneCurve* const TransferFunction[3]) { - cmsHPROFILE hICC; + cmsHPROFILE hICC; cmsMAT3 MColorants; cmsCIEXYZTRIPLE Colorants; cmsCIExyY MaxWhite; @@ -114,13 +114,13 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigRgbData); cmsSetPCS(hICC, cmsSigXYZData); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); // Implement profile using following tags: @@ -137,7 +137,7 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II) // 10 cmsSigChromaticityTag - + if (!SetTextTags(hICC, L"RGB built-in")) goto Error; if (WhitePoint) { @@ -145,9 +145,9 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; cmsxyY2XYZ(&WhitePointXYZ, WhitePoint); - _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); + _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); - // This is a V4 tag, but many CMM does read and understand it no matter which version + // This is a V4 tag, but many CMM does read and understand it no matter which version if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error; } @@ -157,8 +157,8 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, MaxWhite.y = WhitePoint -> y; MaxWhite.Y = 1.0; - if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; - + if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; + Colorants.Red.X = MColorants.v[0].n[0]; Colorants.Red.Y = MColorants.v[1].n[0]; Colorants.Red.Z = MColorants.v[2].n[0]; @@ -178,10 +178,27 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, if (TransferFunction) { - + + // Tries to minimize space. Thanks to Richard Hughes for this nice idea if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; - if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; - if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + + if (TransferFunction[1] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; + } + + if (TransferFunction[2] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + } } if (Primaries) { @@ -212,18 +229,18 @@ cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, const cmsToneCurve* TransferFunction) { cmsHPROFILE hICC; - cmsCIEXYZ tmp; + cmsCIEXYZ tmp; hICC = cmsCreateProfilePlaceholder(ContextID); if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigGrayData); cmsSetPCS(hICC, cmsSigXYZData); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); // Implement profile using following tags: @@ -232,7 +249,7 @@ cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, // 2 cmsSigMediaWhitePointTag // 3 cmsSigGrayTRCTag - // This conforms a standard Gray DisplayProfile + // This conforms a standard Gray DisplayProfile // Fill-in the tags @@ -274,20 +291,19 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, { cmsHPROFILE hICC; cmsPipeline* Pipeline; - cmsStage* Lin; int nChannels; hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) + if (!hICC) return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); cmsSetPCS(hICC, ColorSpace); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); // Set up channels nChannels = cmsChannelsOf(ColorSpace); @@ -298,14 +314,12 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, // Copy tables to Pipeline - Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions); - if (Lin == NULL) goto Error; + if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions))) + goto Error; - cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin); - - // Create tags - if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; - if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; + // Create tags + if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; + if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; // Pipeline is already on virtual profile @@ -315,6 +329,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, return hICC; Error: + cmsPipelineFree(Pipeline); if (hICC) cmsCloseProfile(hICC); @@ -330,13 +345,13 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature Co // Ink-limiting algorithm // -// Sum = C + M + Y + K -// If Sum > InkLimit +// Sum = C + M + Y + K +// If Sum > InkLimit // Ratio= 1 - (Sum - InkLimit) / (C + M + Y) -// if Ratio <0 +// if Ratio <0 // Ratio=0 -// endif -// Else +// endif +// Else // Ratio=1 // endif // @@ -354,7 +369,7 @@ int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Nu InkLimit = (InkLimit * 655.35); SumCMY = In[0] + In[1] + In[2]; - SumCMYK = SumCMY + In[3]; + SumCMYK = SumCMY + In[3]; if (SumCMYK > InkLimit) { @@ -375,7 +390,7 @@ int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Nu // This is a devicelink operating in CMYK for ink-limiting -cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, +cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit) { @@ -383,7 +398,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, cmsPipeline* LUT; cmsStage* CLUT; int nChannels; - + if (ColorSpace != cmsSigCmykData) { cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); return NULL; @@ -391,7 +406,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (Limit < 0.0 || Limit > 400) { - cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); + cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); if (Limit < 0) Limit = 0; if (Limit > 400) Limit = 400; @@ -401,37 +416,38 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); cmsSetPCS(hICC, ColorSpace); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a Pipeline with 3D grid only LUT = cmsPipelineAlloc(ContextID, 4, 4); if (LUT == NULL) goto Error; - + nChannels = cmsChannelsOf(ColorSpace); - + CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL); if (CLUT == NULL) goto Error; if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)); - cmsPipelineInsertStage(LUT, cmsAT_END, CLUT); - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) || + !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) || + !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels))) + goto Error; // Create tags if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error; if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error; - + // cmsPipeline is already on virtual profile cmsPipelineFree(LUT); @@ -457,9 +473,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature Colo // Creates a fake Lab identity. cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) { - cmsHPROFILE hProfile; + cmsHPROFILE hProfile; cmsPipeline* LUT = NULL; - + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); if (hProfile == NULL) return NULL; @@ -475,7 +491,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIE LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -503,13 +520,13 @@ cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint) // Creates a fake Lab V4 identity. cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) { - cmsHPROFILE hProfile; + cmsHPROFILE hProfile; cmsPipeline* LUT = NULL; - + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); if (hProfile == NULL) return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); cmsSetDeviceClass(hProfile, cmsSigAbstractClass); cmsSetColorSpace(hProfile, cmsSigLabData); @@ -521,7 +538,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -548,13 +566,13 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint) // Creates a fake XYZ identity cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) { - cmsHPROFILE hProfile; + cmsHPROFILE hProfile; cmsPipeline* LUT = NULL; - + hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); if (hProfile == NULL) return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); cmsSetDeviceClass(hProfile, cmsSigAbstractClass); cmsSetColorSpace(hProfile, cmsSigXYZData); @@ -566,7 +584,8 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -615,12 +634,12 @@ cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) Parameters[1] = 1. / 1.055; Parameters[2] = 0.055 / 1.055; Parameters[3] = 1. / 12.92; - Parameters[4] = 0.04045; + Parameters[4] = 0.04045; return cmsBuildParametricToneCurve(ContextID, 4, Parameters); } -// Create the ICC virtual profile for sRGB space +// Create the ICC virtual profile for sRGB space cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) { cmsCIExyY D65; @@ -631,11 +650,11 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) }; cmsToneCurve* Gamma22[3]; cmsHPROFILE hsRGB; - + cmsWhitePointFromTemp(&D65, 6504); Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); if (Gamma22[0] == NULL) return NULL; - + hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); cmsFreeToneCurve(Gamma22[0]); if (hsRGB == NULL) return NULL; @@ -672,31 +691,31 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O cmsCIELCh LChIn, LChOut; cmsCIEXYZ XYZ; LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; - + cmsLabEncoded2Float(&LabIn, In); - + cmsLab2LCh(&LChIn, &LabIn); // Do some adjusts on LCh - + LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; LChOut.C = LChIn.C + bchsw -> Saturation; LChOut.h = LChIn.h + bchsw -> Hue; - - + + cmsLCh2Lab(&LabOut, &LChOut); // Move white point in Lab cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); - + // Back to encoded cmsFloat2LabEncoded(Out, &LabOut); - + return TRUE; } @@ -705,101 +724,103 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O // contrast, Saturation and white point displacement cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, - int nLUTPoints, - cmsFloat64Number Bright, - cmsFloat64Number Contrast, - cmsFloat64Number Hue, - cmsFloat64Number Saturation, - int TempSrc, - int TempDest) + int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest) { - cmsHPROFILE hICC; - cmsPipeline* Pipeline; - BCHSWADJUSTS bchsw; - cmsCIExyY WhitePnt; - cmsStage* CLUT; - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - int i; + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + BCHSWADJUSTS bchsw; + cmsCIExyY WhitePnt; + cmsStage* CLUT; + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + bchsw.Brightness = Bright; + bchsw.Contrast = Contrast; + bchsw.Hue = Hue; + bchsw.Saturation = Saturation; + + cmsWhitePointFromTemp(&WhitePnt, TempSrc ); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + + cmsWhitePointFromTemp(&WhitePnt, TempDest); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; - bchsw.Brightness = Bright; - bchsw.Contrast = Contrast; - bchsw.Hue = Hue; - bchsw.Saturation = Saturation; - - cmsWhitePointFromTemp(&WhitePnt, TempSrc ); - cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); - cmsWhitePointFromTemp(&WhitePnt, TempDest); - cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); - - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; - + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - cmsSetDeviceClass(hICC, cmsSigAbstractClass); - cmsSetColorSpace(hICC, cmsSigLabData); - cmsSetPCS(hICC, cmsSigLabData); + // Creates a Pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) { + cmsCloseProfile(hICC); + return NULL; + } - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; + CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); + if (CLUT == NULL) return NULL; - - // Creates a Pipeline with 3D grid only - Pipeline = cmsPipelineAlloc(ContextID, 3, 3); - if (Pipeline == NULL) { - cmsCloseProfile(hICC); - return NULL; - } - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; - CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); - if (CLUT == NULL) return NULL; - - - if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { + if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { - // Shouldn't reach here - cmsPipelineFree(Pipeline); - cmsCloseProfile(hICC); - return NULL; - } + // Shouldn't reach here + goto Error; + } - cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { + goto Error; + } - // Create tags - - if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; - - cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); + // Create tags + if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; - cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); - - // Pipeline is already on virtual profile - cmsPipelineFree(Pipeline); + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); - // Ok, done - return hICC; + cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + // Ok, done + return hICC; + +Error: + cmsPipelineFree(Pipeline); + cmsCloseProfile(hICC); + return NULL; } CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, - cmsFloat64Number Bright, + cmsFloat64Number Bright, cmsFloat64Number Contrast, cmsFloat64Number Hue, cmsFloat64Number Saturation, - int TempSrc, + int TempSrc, int TempDest) { return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest); } -// Creates a fake NULL profile. This profile return 1 channel as always 0. +// Creates a fake NULL profile. This profile return 1 channel as always 0. // Is useful only for gamut checking tricks cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) { - cmsHPROFILE hProfile; + cmsHPROFILE hProfile; cmsPipeline* LUT = NULL; cmsStage* PostLin; cmsToneCurve* EmptyTab; @@ -809,11 +830,11 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) if (!hProfile) // can't allocate return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); + + if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; - if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; - cmsSetDeviceClass(hProfile, cmsSigOutputClass); cmsSetColorSpace(hProfile, cmsSigGrayData); @@ -823,16 +844,17 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) LUT = cmsPipelineAlloc(ContextID, 1, 1); if (LUT == NULL) goto Error; - EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); + EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); cmsFreeToneCurve(EmptyTab); - cmsPipelineInsertStage(LUT, cmsAT_END, PostLin); + if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin)) + goto Error; if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; - cmsPipelineFree(LUT); + cmsPipelineFree(LUT); return hProfile; Error: @@ -861,14 +883,14 @@ int IsPCS(cmsColorSpaceSignature ColorSpace) static -void FixColorSpaces(cmsHPROFILE hProfile, - cmsColorSpaceSignature ColorSpace, +void FixColorSpaces(cmsHPROFILE hProfile, + cmsColorSpaceSignature ColorSpace, cmsColorSpaceSignature PCS, cmsUInt32Number dwFlags) { if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { - if (IsPCS(ColorSpace) && IsPCS(PCS)) { + if (IsPCS(ColorSpace) && IsPCS(PCS)) { cmsSetDeviceClass(hProfile, cmsSigAbstractClass); cmsSetColorSpace(hProfile, ColorSpace); @@ -880,7 +902,7 @@ void FixColorSpaces(cmsHPROFILE hProfile, cmsSetDeviceClass(hProfile, cmsSigOutputClass); cmsSetPCS(hProfile, ColorSpace); - cmsSetColorSpace(hProfile, PCS); + cmsSetColorSpace(hProfile, PCS); return; } @@ -908,7 +930,7 @@ static cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) { _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - cmsHPROFILE hICC = NULL; + cmsHPROFILE hICC = NULL; int i, nColors; cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; @@ -922,7 +944,7 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) cmsSetPCS(hICC, cmsSigLabData); // Tag profile with information - if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; + if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; Original = cmsGetNamedColorList(xform); if (Original == NULL) goto Error; @@ -931,9 +953,14 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) nc2 = cmsDupNamedColorList(Original); if (nc2 == NULL) goto Error; - // Colorant count now depends on the output space + // Colorant count now depends on the output space nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); + // Make sure we have proper formatters + cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX, + FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace)) + | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace))); + // Apply the transfor to colorants. for (i=0; i < nColors; i++) { cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); @@ -963,8 +990,9 @@ typedef struct { static const cmsAllowedLUT AllowedLUTTypes[] = { - { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, @@ -987,17 +1015,17 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { if (n > Tab ->nTypes) return FALSE; - if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; + if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; } return (n == Tab ->nTypes); } -static +static const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) { - int n; + cmsUInt32Number n; for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) { @@ -1011,7 +1039,7 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa return NULL; } - + // Does convert a transform into a device link profile cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) @@ -1025,12 +1053,13 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat cmsContext ContextID = cmsGetTransformContextID(hTransform); const cmsAllowedLUT* AllowedLUT; cmsTagSignature DestinationTag; + cmsProfileClassSignature deviceClass; _cmsAssert(hTransform != NULL); - + // Get the first mpe to check for named color mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); - + // Check if is a named color transform if (mpe != NULL) { @@ -1046,22 +1075,24 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat // Time to fix the Lab2/Lab4 issue. if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID))) + goto Error; } // On the output side too if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)); + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; } - + hProfile = cmsCreateProfilePlaceholder(ContextID); - if (!hProfile) goto Error; // can't allocate - + if (!hProfile) goto Error; // can't allocate + cmsSetProfileVersion(hProfile, Version); - FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); + FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); // Optimize the LUT and precalculate a devicelink @@ -1074,8 +1105,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); + deviceClass = cmsGetDeviceClass(hProfile); - if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) + if (deviceClass == cmsSigOutputClass) DestinationTag = cmsSigBToA0Tag; else DestinationTag = cmsSigAToB0Tag; @@ -1084,12 +1116,12 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (dwFlags & cmsFLAGS_FORCE_CLUT) AllowedLUT = NULL; else - AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); if (AllowedLUT == NULL) { // Try to optimize - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1098,14 +1130,16 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (AllowedLUT == NULL) { dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed - if (cmsPipelineStageCount(LUT) == 1) { + if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) + goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); - } + if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) + goto Error; AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1116,16 +1150,16 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat } - if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) + if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); - + // Tag profile with information - if (!SetTextTags(hProfile, L"devicelink")) goto Error; - - // Store result + if (!SetTextTags(hProfile, L"devicelink")) goto Error; + + // Store result if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; - - + + if (xform -> InputColorant != NULL) { if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error; } @@ -1133,16 +1167,28 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (xform -> OutputColorant != NULL) { if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; } - - if (xform ->Sequence != NULL) { + + if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) { if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; } - cmsPipelineFree(LUT); + // Set the white point + if (deviceClass == cmsSigInputClass) { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error; + } + else { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error; + } + + + // Per 7.2.15 in spec 4.3 + cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent); + + cmsPipelineFree(LUT); return hProfile; Error: - if (LUT != NULL) cmsPipelineFree(LUT); + if (LUT != NULL) cmsPipelineFree(LUT); cmsCloseProfile(hProfile); return NULL; } diff --git a/thirdparty/liblcms2/src/cmswtpnt.c b/thirdparty/liblcms2/src/cmswtpnt.c index 6319984c..e657b132 100644 --- a/thirdparty/liblcms2/src/cmswtpnt.c +++ b/thirdparty/liblcms2/src/cmswtpnt.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -47,63 +47,63 @@ const cmsCIExyY* CMSEXPORT cmsD50_xyY(void) // Obtains WhitePoint from Temperature cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) { - cmsFloat64Number x, y; - cmsFloat64Number T, T2, T3; - // cmsFloat64Number M1, M2; + cmsFloat64Number x, y; + cmsFloat64Number T, T2, T3; + // cmsFloat64Number M1, M2; - _cmsAssert(WhitePoint != NULL); + _cmsAssert(WhitePoint != NULL); - T = TempK; - T2 = T*T; // Square - T3 = T2*T; // Cube + T = TempK; + T2 = T*T; // Square + T3 = T2*T; // Cube - // For correlated color temperature (T) between 4000K and 7000K: + // For correlated color temperature (T) between 4000K and 7000K: - if (T >= 4000. && T <= 7000.) - { - x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; - } - else - // or for correlated color temperature (T) between 7000K and 25000K: + if (T >= 4000. && T <= 7000.) + { + x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; + } + else + // or for correlated color temperature (T) between 7000K and 25000K: - if (T > 7000.0 && T <= 25000.0) - { - x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); - return FALSE; - } + if (T > 7000.0 && T <= 25000.0) + { + x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); + return FALSE; + } - // Obtain y(x) + // Obtain y(x) - y = -3.000*(x*x) + 2.870*x - 0.275; + y = -3.000*(x*x) + 2.870*x - 0.275; - // wave factors (not used, but here for futures extensions) + // wave factors (not used, but here for futures extensions) - // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); - // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); + // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); + // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); - WhitePoint -> x = x; - WhitePoint -> y = y; - WhitePoint -> Y = 1.0; + WhitePoint -> x = x; + WhitePoint -> y = y; + WhitePoint -> Y = 1.0; - return TRUE; + return TRUE; } typedef struct { - cmsFloat64Number mirek; // temp (in microreciprocal kelvin) - cmsFloat64Number ut; // u coord of intersection w/ blackbody locus - cmsFloat64Number vt; // v coord of intersection w/ blackbody locus - cmsFloat64Number tt; // slope of ISOTEMPERATURE. line + cmsFloat64Number mirek; // temp (in microreciprocal kelvin) + cmsFloat64Number ut; // u coord of intersection w/ blackbody locus + cmsFloat64Number vt; // v coord of intersection w/ blackbody locus + cmsFloat64Number tt; // slope of ISOTEMPERATURE. line } ISOTEMPERATURE; static ISOTEMPERATURE isotempdata[] = { -// {Mirek, Ut, Vt, Tt } +// {Mirek, Ut, Vt, Tt } {0, 0.18006, 0.26352, -0.24341}, {10, 0.18066, 0.26589, -0.25479}, {20, 0.18133, 0.26846, -0.26876}, @@ -143,50 +143,50 @@ static ISOTEMPERATURE isotempdata[] = { // Robertson's method cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint) { - int j; - cmsFloat64Number us,vs; - cmsFloat64Number uj,vj,tj,di,dj,mi,mj; - cmsFloat64Number xs, ys; + cmsUInt32Number j; + cmsFloat64Number us,vs; + cmsFloat64Number uj,vj,tj,di,dj,mi,mj; + cmsFloat64Number xs, ys; - _cmsAssert(WhitePoint != NULL); + _cmsAssert(WhitePoint != NULL); _cmsAssert(TempK != NULL); - di = mi = 0; - xs = WhitePoint -> x; - ys = WhitePoint -> y; + di = mi = 0; + xs = WhitePoint -> x; + ys = WhitePoint -> y; - // convert (x,y) to CIE 1960 (u,WhitePoint) + // convert (x,y) to CIE 1960 (u,WhitePoint) - us = (2*xs) / (-xs + 6*ys + 1.5); - vs = (3*ys) / (-xs + 6*ys + 1.5); + us = (2*xs) / (-xs + 6*ys + 1.5); + vs = (3*ys) / (-xs + 6*ys + 1.5); - for (j=0; j < NISO; j++) { + for (j=0; j < NISO; j++) { - uj = isotempdata[j].ut; - vj = isotempdata[j].vt; - tj = isotempdata[j].tt; - mj = isotempdata[j].mirek; + uj = isotempdata[j].ut; + vj = isotempdata[j].vt; + tj = isotempdata[j].tt; + mj = isotempdata[j].mirek; - dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj); + dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj); - if ((j != 0) && (di/dj < 0.0)) { + if ((j != 0) && (di/dj < 0.0)) { - // Found a match - *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); - return TRUE; - } + // Found a match + *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); + return TRUE; + } - di = dj; - mi = mj; - } + di = dj; + mi = mj; + } - // Not found - return FALSE; + // Not found + return FALSE; } -// Compute chromatic adaptation matrix using Chad as cone matrix +// Compute chromatic adaptation matrix using Chad as cone matrix static cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, @@ -195,7 +195,7 @@ cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, const cmsMAT3* Chad) { - + cmsMAT3 Chad_Inv; cmsVEC3 ConeSourceXYZ, ConeSourceRGB; cmsVEC3 ConeDestXYZ, ConeDestRGB; @@ -226,41 +226,41 @@ cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, _cmsMAT3per(&Tmp, &Cone, Chad); _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); - return TRUE; + return TRUE; } // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll // The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll) { - cmsMAT3 LamRigg = {{ // Bradford matrix - {{ 0.8951, 0.2664, -0.1614 }}, - {{ -0.7502, 1.7135, 0.0367 }}, - {{ 0.0389, -0.0685, 1.0296 }} - }}; + cmsMAT3 LamRigg = {{ // Bradford matrix + {{ 0.8951, 0.2664, -0.1614 }}, + {{ -0.7502, 1.7135, 0.0367 }}, + {{ 0.0389, -0.0685, 1.0296 }} + }}; - if (ConeMatrix == NULL) - ConeMatrix = &LamRigg; + if (ConeMatrix == NULL) + ConeMatrix = &LamRigg; - return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix); + return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix); } // Same as anterior, but assuming D50 destination. White point is given in xyY static cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) { - cmsCIEXYZ Dn; - cmsMAT3 Bradford; - cmsMAT3 Tmp; + cmsCIEXYZ Dn; + cmsMAT3 Bradford; + cmsMAT3 Tmp; - cmsxyY2XYZ(&Dn, SourceWhitePt); + cmsxyY2XYZ(&Dn, SourceWhitePt); - if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE; + if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE; - Tmp = *r; - _cmsMAT3per(r, &Bradford, &Tmp); + Tmp = *r; + _cmsMAT3per(r, &Bradford, &Tmp); - return TRUE; + return TRUE; } // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ @@ -278,74 +278,74 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) // cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) { - cmsVEC3 WhitePoint, Coef; - cmsMAT3 Result, Primaries; - cmsFloat64Number xn, yn; - cmsFloat64Number xr, yr; - cmsFloat64Number xg, yg; - cmsFloat64Number xb, yb; + cmsVEC3 WhitePoint, Coef; + cmsMAT3 Result, Primaries; + cmsFloat64Number xn, yn; + cmsFloat64Number xr, yr; + cmsFloat64Number xg, yg; + cmsFloat64Number xb, yb; - xn = WhitePt -> x; - yn = WhitePt -> y; - xr = Primrs -> Red.x; - yr = Primrs -> Red.y; - xg = Primrs -> Green.x; - yg = Primrs -> Green.y; - xb = Primrs -> Blue.x; - yb = Primrs -> Blue.y; + xn = WhitePt -> x; + yn = WhitePt -> y; + xr = Primrs -> Red.x; + yr = Primrs -> Red.y; + xg = Primrs -> Green.x; + yg = Primrs -> Green.y; + xb = Primrs -> Blue.x; + yb = Primrs -> Blue.y; - // Build Primaries matrix - _cmsVEC3init(&Primaries.v[0], xr, xg, xb); - _cmsVEC3init(&Primaries.v[1], yr, yg, yb); - _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); + // Build Primaries matrix + _cmsVEC3init(&Primaries.v[0], xr, xg, xb); + _cmsVEC3init(&Primaries.v[1], yr, yg, yb); + _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); - // Result = Primaries ^ (-1) inverse matrix - if (!_cmsMAT3inverse(&Primaries, &Result)) - return FALSE; + // Result = Primaries ^ (-1) inverse matrix + if (!_cmsMAT3inverse(&Primaries, &Result)) + return FALSE; - _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); + _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); - // Across inverse primaries ... - _cmsMAT3eval(&Coef, &Result, &WhitePoint); + // Across inverse primaries ... + _cmsMAT3eval(&Coef, &Result, &WhitePoint); - // Give us the Coefs, then I build transformation matrix - _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); - _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); - _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); + // Give us the Coefs, then I build transformation matrix + _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); + _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); + _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); - return _cmsAdaptMatrixToD50(r, WhitePt); - + return _cmsAdaptMatrixToD50(r, WhitePt); + } // Adapts a color to a given illuminant. Original color is expected to have -// a SourceWhitePt white point. -cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, - const cmsCIEXYZ* SourceWhitePt, - const cmsCIEXYZ* Illuminant, - const cmsCIEXYZ* Value) +// a SourceWhitePt white point. +cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, + const cmsCIEXYZ* SourceWhitePt, + const cmsCIEXYZ* Illuminant, + const cmsCIEXYZ* Value) { - cmsMAT3 Bradford; - cmsVEC3 In, Out; + cmsMAT3 Bradford; + cmsVEC3 In, Out; - _cmsAssert(Result != NULL); - _cmsAssert(SourceWhitePt != NULL); - _cmsAssert(Illuminant != NULL); - _cmsAssert(Value != NULL); + _cmsAssert(Result != NULL); + _cmsAssert(SourceWhitePt != NULL); + _cmsAssert(Illuminant != NULL); + _cmsAssert(Value != NULL); - if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; + if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; - _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); - _cmsMAT3eval(&Out, &Bradford, &In); + _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); + _cmsMAT3eval(&Out, &Bradford, &In); - Result -> X = Out.n[0]; - Result -> Y = Out.n[1]; - Result -> Z = Out.n[2]; + Result -> X = Out.n[0]; + Result -> Y = Out.n[1]; + Result -> Z = Out.n[2]; - return TRUE; + return TRUE; } diff --git a/thirdparty/liblcms2/src/cmsxform.c b/thirdparty/liblcms2/src/cmsxform.c index 7f5cc947..56afede2 100644 --- a/thirdparty/liblcms2/src/cmsxform.c +++ b/thirdparty/liblcms2/src/cmsxform.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -29,44 +29,120 @@ // Transformations stuff // ----------------------------------------------------------------------- -// Alarm codes for 16-bit transformations, because the fixed range of containers there are -// no values left to mark out of gamut. volatile is C99 per 6.2.5 -static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS]; -static volatile cmsFloat64Number GlobalAdaptationState = 0; +#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 + +// The Context0 observer adaptation state. +_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + +// Init and duplicate observer adaptation state +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AdaptationStateContext]; + } + else { + from = &AdaptationStateChunk; + } + + ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); +} + + +// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all +// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. +cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) +{ + cmsFloat64Number prev; + _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); + + // Get previous value for return + prev = ptr ->AdaptationState; + + // Set the value if d is positive or zero + if (d >= 0.0) { + + ptr ->AdaptationState = d; + } + + // Always return previous value + return prev; +} + // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) -{ - cmsFloat64Number OldVal = GlobalAdaptationState; - - if (d >= 0) - GlobalAdaptationState = d; - - return OldVal; +{ + return cmsSetAdaptationStateTHR(NULL, d); } -// Alarm codes are always global -void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) -{ - int i; +// ----------------------------------------------------------------------- +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. + +#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + +// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be +// encoded in 16 bits. +void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. +// Values are meant to be encoded in 16 bits. +void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +{ _cmsAssert(NewAlarm != NULL); - for (i=0; i < cmsMAXCHANNELS; i++) - Alarm[i] = NewAlarm[i]; + cmsSetAlarmCodesTHR(NULL, NewAlarm); } -// You can get the codes cas well void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) -{ - int i; - +{ _cmsAssert(OldAlarm != NULL); - - for (i=0; i < cmsMAXCHANNELS; i++) - OldAlarm[i] = Alarm[i]; + cmsGetAlarmCodesTHR(NULL, OldAlarm); } + +// Init and duplicate alarm codes +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AlarmCodesContext]; + } + else { + from = &AlarmCodesChunk; + } + + ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); +} + +// ----------------------------------------------------------------------- + // Get rid of transform resources void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) { @@ -89,20 +165,35 @@ void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) if (p ->Sequence) cmsFreeProfileSequenceDescription(p ->Sequence); - LCMS_FREE_LOCK(&p->rwlock); + if (p ->UserData) + p ->FreeUserData(p ->ContextID, p ->UserData); + _cmsFree(p ->ContextID, (void *) p); } -// Apply transform +// Apply transform. void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, const void* InputBuffer, - void* OutputBuffer, + void* OutputBuffer, cmsUInt32Number Size) { _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; - p -> xform(p, InputBuffer, OutputBuffer, Size); + p -> xform(p, InputBuffer, OutputBuffer, Size, Size); +} + + +// Apply transform. +void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, cmsUInt32Number Stride) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + + p -> xform(p, InputBuffer, OutputBuffer, Size, Stride); } @@ -113,7 +204,7 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, static void FloatXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -126,7 +217,7 @@ void FloatXFORM(_cmsTRANSFORM* p, for (i=0; i < Size; i++) { - accum = p -> FromInputFloat(p, fIn, accum, Size); + accum = p -> FromInputFloat(p, fIn, accum, Stride); // Any gamut chack to do? if (p ->GamutCheck != NULL) { @@ -144,17 +235,41 @@ void FloatXFORM(_cmsTRANSFORM* p, } else { // No, proceed normally - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + cmsPipelineEvalFloat(fIn, fOut, p -> Lut); } } else { // No gamut check at all - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + cmsPipelineEvalFloat(fIn, fOut, p -> Lut); } // Back to asked representation - output = p -> ToOutputFloat(p, fOut, output, Size); + output = p -> ToOutputFloat(p, fOut, output, Stride); + } +} + + +static +void NullFloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number Size, + cmsUInt32Number Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; + + for (i=0; i < n; i++) { + + accum = p -> FromInputFloat(p, fIn, accum, Stride); + output = p -> ToOutputFloat(p, fIn, output, Stride); } } @@ -164,7 +279,8 @@ void FloatXFORM(_cmsTRANSFORM* p, static void NullXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, + cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -177,8 +293,8 @@ void NullXFORM(_cmsTRANSFORM* p, for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); - output = p -> ToOutput(p, wIn, output, Size); + accum = p -> FromInput(p, wIn, accum, Stride); + output = p -> ToOutput(p, wIn, output, Stride); } } @@ -187,7 +303,7 @@ void NullXFORM(_cmsTRANSFORM* p, static void PrecalculatedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { register cmsUInt8Number* accum; register cmsUInt8Number* output; @@ -196,42 +312,45 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p, accum = (cmsUInt8Number*) in; output = (cmsUInt8Number*) out; - n = Size; + n = Size; for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - output = p -> ToOutput(p, wOut, output, Size); + accum = p -> FromInput(p, wIn, accum, Stride); + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + output = p -> ToOutput(p, wOut, output, Stride); } } -// Auxiliar: Handle precalculated gamut check +// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. static -void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, - const cmsUInt16Number wIn[], +void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, + const cmsUInt16Number wIn[], cmsUInt16Number wOut[]) { cmsUInt16Number wOutOfGamut; - p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data); + p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data); if (wOutOfGamut >= 1) { cmsUInt16Number i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); - for (i=0; i < p ->Lut->OutputChannels; i++) - wOut[i] = Alarm[i]; + for (i=0; i < p ->Lut->OutputChannels; i++) { + + wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; + } } else - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); } // Gamut check, No caché, 16 bits. static void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -244,24 +363,24 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); TransformOnePixelWithGamutCheck(p, wIn, wOut); - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } } -// No gamut check, Caché, 16 bits, +// No gamut check, Caché, 16 bits, static void CachedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; cmsUInt32Number i, n; - cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; accum = (cmsUInt8Number*) in; output = (cmsUInt8Number*) out; @@ -271,36 +390,28 @@ void CachedXFORM(_cmsTRANSFORM* p, memset(wIn, 0, sizeof(wIn)); memset(wOut, 0, sizeof(wOut)); - - LCMS_READ_LOCK(&p ->rwlock); - memmove(CacheIn, p ->CacheIn, sizeof(CacheIn)); - memmove(CacheOut, p ->CacheOut, sizeof(CacheOut)); - LCMS_UNLOCK(&p ->rwlock); + // Get copy of zero cache + memcpy(&Cache, &p ->Cache, sizeof(Cache)); for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); - if (memcmp(wIn, CacheIn, sizeof(CacheIn)) == 0) { + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { - memmove(wOut, CacheOut, sizeof(CacheOut)); + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); } - else { + else { - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - memmove(CacheIn, wIn, sizeof(CacheIn)); - memmove(CacheOut, wOut, sizeof(CacheOut)); + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); } - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } - - LCMS_WRITE_LOCK(&p ->rwlock); - memmove(p->CacheIn, CacheIn, sizeof(CacheIn)); - memmove(p->CacheOut, CacheOut, sizeof(CacheOut)); - LCMS_UNLOCK(&p ->rwlock); } @@ -308,13 +419,13 @@ void CachedXFORM(_cmsTRANSFORM* p, static void CachedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; cmsUInt32Number i, n; - cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; accum = (cmsUInt8Number*) in; output = (cmsUInt8Number*) out; @@ -324,75 +435,241 @@ void CachedXFORMGamutCheck(_cmsTRANSFORM* p, memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - memmove(CacheIn, p ->CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(CacheOut, p ->CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); - + // Get copy of zero cache + memcpy(&Cache, &p ->Cache, sizeof(Cache)); for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); - - if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) { - memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + accum = p -> FromInput(p, wIn, accum, Stride); + + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); } - else { + else { TransformOnePixelWithGamutCheck(p, wIn, wOut); - memmove(CacheIn, wIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(CacheOut, wOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); } - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } - LCMS_WRITE_LOCK(&p ->rwlock); - memmove(p->CacheIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(p->CacheOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); +} + +// ------------------------------------------------------------------------------------------------------------- + +// List of used-defined transform factories +typedef struct _cmsTransformCollection_st { + + _cmsTransformFactory Factory; + struct _cmsTransformCollection_st *Next; + +} _cmsTransformCollection; + +// The linked list head +_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginTransformList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTransformPluginChunkType newHead = { NULL }; + _cmsTransformCollection* entry; + _cmsTransformCollection* Anterior = NULL; + _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; + + // Walk the list copying all nodes + for (entry = head->TransformCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TransformCollection == NULL) + newHead.TransformCollection = newEntry; + } + + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); +} + +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginTransformList(ctx, src); + } + else { + static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); + } } - -// Allocate transform struct and set it to defaults -static -_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags) +// Register new ways to transform +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { + cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; + _cmsTransformCollection* fl; + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); + + if (Data == NULL) { + + // Free the chain. Memory is safely freed at exit + ctx->TransformCollection = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->Factory == NULL) return FALSE; + + + fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->Factory = Plugin ->Factory; + + // Keep linked list + fl ->Next = ctx->TransformCollection; + ctx->TransformCollection = fl; + + // All is ok + return TRUE; +} + + +void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn) +{ + _cmsAssert(CMMcargo != NULL); + CMMcargo ->UserData = ptr; + CMMcargo ->FreeUserData = FreePrivateDataFn; +} + +// returns the pointer defined by the plug-in to store private data +void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo) +{ + _cmsAssert(CMMcargo != NULL); + return CMMcargo ->UserData; +} + +// returns the current formatters +void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput) +{ + _cmsAssert(CMMcargo != NULL); + if (FromInput) *FromInput = CMMcargo ->FromInput; + if (ToOutput) *ToOutput = CMMcargo ->ToOutput; +} + +void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput) +{ + _cmsAssert(CMMcargo != NULL); + if (FromInput) *FromInput = CMMcargo ->FromInputFloat; + if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat; +} + + +// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper +// for separated transforms. If this is the case, +static +_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); + _cmsTransformCollection* Plugin; + // Allocate needed memory _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); if (!p) return NULL; + // Store the proposed pipeline + p ->Lut = lut; + + // Let's see if any plug-in want to do the transform by itself + for (Plugin = ctx ->TransformCollection; + Plugin != NULL; + Plugin = Plugin ->Next) { + + if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) { + + // Last plugin in the declaration order takes control. We just keep + // the original parameters as a logging. + // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default + // an optimized transform is not reusable. The plug-in can, however, change + // the flags and make it suitable. + + p ->ContextID = ContextID; + p ->InputFormat = *InputFormat; + p ->OutputFormat = *OutputFormat; + p ->dwOriginalFlags = *dwFlags; + + // Fill the formatters just in case the optimized routine is interested. + // No error is thrown if the formatter doesn't exist. It is up to the optimization + // factory to decide what to do in those cases. + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + + return p; + } + } + + // Not suitable for the transform plug-in, let's check the pipeline plug-in + if (p ->Lut != NULL) + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) { + if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. - p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { - + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); _cmsFree(ContextID, p); return NULL; } - // Float transforms don't use caché, always are non-NULL - p ->xform = FloatXFORM; + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullFloatXFORM; + } + else { + // Float transforms don't use caché, always are non-NULL + p ->xform = FloatXFORM; + } + } else { - if (InputFormat == 0 && OutputFormat == 0) { + if (*InputFormat == 0 && *OutputFormat == 0) { p ->FromInput = p ->ToOutput = NULL; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; } else { int BytesPerPixelInput; - p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (p ->FromInput == NULL || p ->ToOutput == NULL) { @@ -402,26 +679,26 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo } BytesPerPixelInput = T_BYTES(p ->InputFormat); - if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) - dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; } - if (dwFlags & cmsFLAGS_NULLTRANSFORM) { + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { p ->xform = NullXFORM; } else { - if (dwFlags & cmsFLAGS_NOCACHE) { + if (*dwFlags & cmsFLAGS_NOCACHE) { - if (dwFlags & cmsFLAGS_GAMUTCHECK) + if (*dwFlags & cmsFLAGS_GAMUTCHECK) p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché else p ->xform = PrecalculatedXFORM; // No caché, no gamut check } else { - if (dwFlags & cmsFLAGS_GAMUTCHECK) + if (*dwFlags & cmsFLAGS_GAMUTCHECK) p ->xform = CachedXFORMGamutCheck; // Gamut check, caché else p ->xform = CachedXFORM; // No gamut check, caché @@ -430,54 +707,64 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo } } - - // Create a mutex for shared memory - LCMS_CREATE_LOCK(&p->rwlock); - - p ->InputFormat = InputFormat; - p ->OutputFormat = OutputFormat; - p ->dwOriginalFlags = dwFlags; + p ->InputFormat = *InputFormat; + p ->OutputFormat = *OutputFormat; + p ->dwOriginalFlags = *dwFlags; p ->ContextID = ContextID; + p ->UserData = NULL; return p; } static -cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output) -{ - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut; - cmsColorSpaceSignature PostColorSpace; +cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output) +{ + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut; + cmsColorSpaceSignature PostColorSpace; int i; - if (hProfiles[0] == NULL) return FALSE; + if (nProfiles <= 0) return FALSE; + if (hProfiles[0] == NULL) return FALSE; *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]); for (i=0; i < nProfiles; i++) { + cmsProfileClassSignature cls; cmsHPROFILE hProfile = hProfiles[i]; int lIsInput = (PostColorSpace != cmsSigXYZData) && (PostColorSpace != cmsSigLabData); - if (hProfile == NULL) return FALSE; + if (hProfile == NULL) return FALSE; - if (lIsInput) { + cls = cmsGetDeviceClass(hProfile); + + if (cls == cmsSigNamedColorClass) { + + ColorSpaceIn = cmsSig1colorData; + ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile); + } + else + if (lIsInput || (cls == cmsSigLinkClass)) { ColorSpaceIn = cmsGetColorSpace(hProfile); ColorSpaceOut = cmsGetPCS(hProfile); } - else { - + else + { ColorSpaceIn = cmsGetPCS(hProfile); ColorSpaceOut = cmsGetColorSpace(hProfile); } - PostColorSpace = ColorSpaceOut; - } + if (i==0) + *Input = ColorSpaceIn; + + PostColorSpace = ColorSpaceOut; + } *Output = PostColorSpace; - return TRUE; + return TRUE; } // Check colorspace @@ -498,97 +785,124 @@ cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwForm // ---------------------------------------------------------------------------------------------------------------- +static +void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) +{ + if (src == NULL) { + wtPt ->X = cmsD50X; + wtPt ->Y = cmsD50Y; + wtPt ->Z = cmsD50Z; + } + else { + wtPt ->X = src->X; + wtPt ->Y = src->Y; + wtPt ->Z = src->Z; + } + +} + // New to lcms 2.0 -- have all parameters available. cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, - cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], + cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], cmsFloat64Number AdaptationStates[], cmsHPROFILE hGamutProfile, - cmsUInt32Number nGamutPCSposition, + cmsUInt32Number nGamutPCSposition, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags) { - _cmsTRANSFORM* xform; - cmsBool FloatTransform; + _cmsTRANSFORM* xform; cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature ExitColorSpace; cmsPipeline* Lut; cmsUInt32Number LastIntent = Intents[nProfiles-1]; + // If it is a fake transform + if (dwFlags & cmsFLAGS_NULLTRANSFORM) + { + return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags); + } + // If gamut check is requested, make sure we have a gamut profile if (dwFlags & cmsFLAGS_GAMUTCHECK) { if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; } - // On floating point transforms, inhibit optimizations - FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)); - + // On floating point transforms, inhibit cache if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) dwFlags |= cmsFLAGS_NOCACHE; // Mark entry/exit spaces - if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) { - cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform"); - return NULL; - } + if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) { + cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform"); + return NULL; + } // Check if proper colorspaces - if (!IsProperColorSpace(EntryColorSpace, InputFormat)) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform"); + if (!IsProperColorSpace(EntryColorSpace, InputFormat)) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform"); return NULL; } if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); return NULL; } // Create a pipeline with all transformations Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); if (Lut == NULL) { - cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles"); + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles"); return NULL; } - // Optimize the LUT if possible - _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); + // Check channel count + if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || + (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { + cmsPipelineFree(Lut); + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); + return NULL; + } // All seems ok - xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags); + xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); if (xform == NULL) { - cmsPipelineFree(Lut); return NULL; } // Keep values xform ->EntryColorSpace = EntryColorSpace; xform ->ExitColorSpace = ExitColorSpace; - xform ->Lut = Lut; + xform ->RenderingIntent = Intents[nProfiles-1]; + // Take white points + SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag)); + SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag)); + // Create a gamut check LUT if requested - if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) - xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles, - BPC, Intents, - AdaptationStates, - nGamutPCSposition, + if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) + xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles, + BPC, Intents, + AdaptationStates, + nGamutPCSposition, hGamutProfile); // Try to read input and output colorant table if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) { - // Input table can only come in this way. + // Input table can only come in this way. xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag)); } - // Output is a little bit more complex. + // Output is a little bit more complex. if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) { - // This tag may exist only on devicelink profiles. + // This tag may exist only on devicelink profiles. if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) { // It may be NULL if error @@ -600,36 +914,35 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) { xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)); - } + } } // Store the sequence of profiles if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) { xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles); } - else + else xform ->Sequence = NULL; // If this is a cached transform, init first value, which is zero (16 bits only) if (!(dwFlags & cmsFLAGS_NOCACHE)) { - memset(&xform ->CacheIn, 0, sizeof(xform ->CacheIn)); + memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn)); if (xform ->GamutCheck != NULL) { - TransformOnePixelWithGamutCheck(xform, xform ->CacheIn, xform->CacheOut); + TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut); } else { - xform ->Lut ->Eval16Fn(xform ->CacheIn, xform->CacheOut, xform -> Lut->Data); + xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data); } } - return (cmsHTRANSFORM) xform; + return (cmsHTRANSFORM) xform; } // Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes. - cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, cmsHPROFILE hProfiles[], cmsUInt32Number nProfiles, @@ -651,7 +964,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, for (i=0; i < nProfiles; i++) { BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; Intents[i] = Intent; - AdaptationStates[i] = GlobalAdaptationState; + AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); } @@ -692,7 +1005,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, { cmsHPROFILE hArray[2]; - + hArray[0] = Input; hArray[1] = Output; @@ -719,7 +1032,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, cmsUInt32Number nIntent, cmsUInt32Number ProofingIntent, cmsUInt32Number dwFlags) -{ +{ cmsHPROFILE hArray[4]; cmsUInt32Number Intents[4]; cmsBool BPC[4]; @@ -730,13 +1043,13 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile; Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; - - Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState; - if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); + + if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); - - return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation, + + return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation, ProofingProfile, 1, InputFormat, OutputFormat, dwFlags); } @@ -751,7 +1064,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, cmsUInt32Number ProofingIntent, cmsUInt32Number dwFlags) { - return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile), + return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile), InputProfile, InputFormat, OutputProfile, @@ -772,28 +1085,42 @@ cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform) return xform -> ContextID; } +// Grab the input/output formats +cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + if (xform == NULL) return 0; + return xform->InputFormat; +} + +cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + + if (xform == NULL) return 0; + return xform->OutputFormat; +} // For backwards compatibility -cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, - cmsUInt32Number InputFormat, +cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat) { _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; cmsFormatter16 FromInput, ToOutput; - cmsUInt32Number BytesPerPixelInput; + // We only can afford to change formatters if previous transform is at least 16 bits - BytesPerPixelInput = T_BYTES(xform ->InputFormat); if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) { cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision"); return FALSE; } - FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (FromInput == NULL || ToOutput == NULL) { @@ -803,7 +1130,7 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, xform ->InputFormat = InputFormat; xform ->OutputFormat = OutputFormat; - xform ->FromInput = FromInput; - xform ->ToOutput = ToOutput; + xform ->FromInput = FromInput; + xform ->ToOutput = ToOutput; return TRUE; } diff --git a/thirdparty/liblcms2/src/lcms2.def b/thirdparty/liblcms2/src/lcms2.def index d4075021..a1f69c42 100644 --- a/thirdparty/liblcms2/src/lcms2.def +++ b/thirdparty/liblcms2/src/lcms2.def @@ -1,300 +1,341 @@ -LIBRARY LCMS2.DLL - -EXPORTS - -_cms15Fixed16toDouble = _cms15Fixed16toDouble -_cms8Fixed8toDouble = _cms8Fixed8toDouble -cmsAdaptToIlluminant = cmsAdaptToIlluminant -_cmsAdjustEndianess16 = _cmsAdjustEndianess16 -_cmsAdjustEndianess32 = _cmsAdjustEndianess32 -_cmsAdjustEndianess64 = _cmsAdjustEndianess64 -cmsAllocNamedColorList = cmsAllocNamedColorList -cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription -cmsAppendNamedColor = cmsAppendNamedColor -cmsBFDdeltaE = cmsBFDdeltaE -cmsBuildGamma = cmsBuildGamma -cmsBuildParametricToneCurve = cmsBuildParametricToneCurve -cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve -cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16 -cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat -_cmsCalloc = _cmsCalloc -cmsChannelsOf = cmsChannelsOf -cmsCIE2000DeltaE = cmsCIE2000DeltaE -cmsCIE94DeltaE = cmsCIE94DeltaE -cmsCIECAM02Done = cmsCIECAM02Done -cmsCIECAM02Forward = cmsCIECAM02Forward -cmsCIECAM02Init = cmsCIECAM02Init -cmsCIECAM02Reverse = cmsCIECAM02Reverse -cmsCloseIOhandler = cmsCloseIOhandler -cmsCloseProfile = cmsCloseProfile -cmsCMCdeltaE = cmsCMCdeltaE -cmsCreate_sRGBProfile = cmsCreate_sRGBProfile -cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR -cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile -cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR -cmsCreateExtendedTransform = cmsCreateExtendedTransform -cmsCreateGrayProfile = cmsCreateGrayProfile -cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR -cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink -cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR -cmsCreateLab2Profile = cmsCreateLab2Profile -cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR -cmsCreateLab4Profile = cmsCreateLab4Profile -cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR -cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink -cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR -cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform -cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR -cmsCreateNULLProfile = cmsCreateNULLProfile -cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR -cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder -cmsCreateProofingTransform = cmsCreateProofingTransform -cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR -cmsCreateRGBProfile = cmsCreateRGBProfile -cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR -cmsCreateTransform = cmsCreateTransform -cmsCreateTransformTHR = cmsCreateTransformTHR -cmsCreateXYZProfile = cmsCreateXYZProfile -cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR -cmsD50_xyY = cmsD50_xyY -cmsD50_XYZ = cmsD50_XYZ -_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber -_cmsDefaultICCintents = _cmsDefaultICCintents -cmsDeleteTransform = cmsDeleteTransform -cmsDeltaE = cmsDeltaE -cmsDetectBlackPoint = cmsDetectBlackPoint -cmsDetectTAC = cmsDetectTAC -cmsDesaturateLab = cmsDesaturateLab -cmsDoTransform = cmsDoTransform -_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16 -_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8 -_cmsDupMem = _cmsDupMem -cmsDupNamedColorList = cmsDupNamedColorList -cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription -cmsDupToneCurve = cmsDupToneCurve -_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber -cmsEstimateGamma = cmsEstimateGamma -cmsEvalToneCurve16 = cmsEvalToneCurve16 -cmsEvalToneCurveFloat = cmsEvalToneCurveFloat -cmsfilelength = cmsfilelength -cmsFloat2LabEncoded = cmsFloat2LabEncoded -cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2 -cmsFloat2XYZEncoded = cmsFloat2XYZEncoded -cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile -cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile -_cmsFree = _cmsFree -cmsFreeNamedColorList = cmsFreeNamedColorList -cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription -cmsFreeToneCurve = cmsFreeToneCurve -cmsFreeToneCurveTriple = cmsFreeToneCurveTriple -cmsGBDAlloc = cmsGBDAlloc -cmsGBDFree = cmsGBDFree -cmsGDBAddPoint = cmsGDBAddPoint -cmsGDBCheckPoint = cmsGDBCheckPoint -cmsGDBCompute = cmsGDBCompute -cmsGetAlarmCodes = cmsGetAlarmCodes -cmsGetColorSpace = cmsGetColorSpace -cmsGetDeviceClass = cmsGetDeviceClass -cmsGetEncodedICCversion = cmsGetEncodedICCversion -cmsGetHeaderAttributes = cmsGetHeaderAttributes -cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime -cmsGetHeaderFlags = cmsGetHeaderFlags -cmsGetHeaderManufacturer = cmsGetHeaderManufacturer -cmsGetHeaderModel = cmsGetHeaderModel -cmsGetHeaderProfileID = cmsGetHeaderProfileID -cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent -cmsGetNamedColorList = cmsGetNamedColorList -cmsGetPCS = cmsGetPCS -cmsGetPostScriptColorResource = cmsGetPostScriptColorResource -cmsGetPostScriptCRD = cmsGetPostScriptCRD -cmsGetPostScriptCSA = cmsGetPostScriptCSA -cmsGetProfileInfo = cmsGetProfileInfo -cmsGetProfileInfoASCII = cmsGetProfileInfoASCII -cmsGetProfileContextID = cmsGetProfileContextID -cmsGetProfileVersion = cmsGetProfileVersion -cmsGetSupportedIntents = cmsGetSupportedIntents -cmsGetTagCount = cmsGetTagCount -cmsGetTagSignature = cmsGetTagSignature -cmsGetTransformContextID = cmsGetTransformContextID -_cmsICCcolorSpace = _cmsICCcolorSpace -_cmsIOPrintf = _cmsIOPrintf -cmsIsCLUT = cmsIsCLUT -cmsIsIntentSupported = cmsIsIntentSupported -cmsIsMatrixShaper = cmsIsMatrixShaper -cmsIsTag = cmsIsTag -cmsIsToneCurveDescending = cmsIsToneCurveDescending -cmsIsToneCurveLinear = cmsIsToneCurveLinear -cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic -cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment -cmsGetToneCurveParametricType = cmsGetToneCurveParametricType -cmsIT8Alloc = cmsIT8Alloc -cmsIT8DefineDblFormat = cmsIT8DefineDblFormat -cmsIT8EnumDataFormat = cmsIT8EnumDataFormat -cmsIT8EnumProperties = cmsIT8EnumProperties -cmsIT8Free = cmsIT8Free -cmsIT8GetData = cmsIT8GetData -cmsIT8GetDataDbl = cmsIT8GetDataDbl -cmsIT8FindDataFormat = cmsIT8FindDataFormat -cmsIT8GetDataRowCol = cmsIT8GetDataRowCol -cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl -cmsIT8GetPatchName = cmsIT8GetPatchName -cmsIT8GetProperty = cmsIT8GetProperty -cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl -cmsIT8GetSheetType = cmsIT8GetSheetType -cmsIT8LoadFromFile = cmsIT8LoadFromFile -cmsIT8LoadFromMem = cmsIT8LoadFromMem -cmsIT8SaveToFile = cmsIT8SaveToFile -cmsIT8SaveToMem = cmsIT8SaveToMem -cmsIT8SetComment = cmsIT8SetComment -cmsIT8SetData = cmsIT8SetData -cmsIT8SetDataDbl = cmsIT8SetDataDbl -cmsIT8SetDataFormat = cmsIT8SetDataFormat -cmsIT8SetDataRowCol = cmsIT8SetDataRowCol -cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl -cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl -cmsIT8SetPropertyHex = cmsIT8SetPropertyHex -cmsIT8SetPropertyStr = cmsIT8SetPropertyStr -cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked -cmsIT8SetSheetType = cmsIT8SetSheetType -cmsIT8SetTable = cmsIT8SetTable -cmsIT8SetTableByLabel = cmsIT8SetTableByLabel -cmsIT8TableCount = cmsIT8TableCount -cmsJoinToneCurve = cmsJoinToneCurve -cmsLab2LCh = cmsLab2LCh -cmsLab2XYZ = cmsLab2XYZ -cmsLabEncoded2Float = cmsLabEncoded2Float -cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2 -cmsLCh2Lab = cmsLCh2Lab -_cmsLCMScolorSpace = _cmsLCMScolorSpace -cmsLinkTag = cmsLinkTag -cmsPipelineAlloc = cmsPipelineAlloc -cmsPipelineCat = cmsPipelineCat -cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages -cmsPipelineDup = cmsPipelineDup -cmsPipelineStageCount = cmsPipelineStageCount -cmsPipelineEval16 = cmsPipelineEval16 -cmsPipelineEvalFloat = cmsPipelineEvalFloat -cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat -cmsPipelineFree = cmsPipelineFree -cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage -cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage -cmsPipelineInputChannels = cmsPipelineInputChannels -cmsPipelineInsertStage = cmsPipelineInsertStage -cmsPipelineOutputChannels = cmsPipelineOutputChannels -cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag -_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters -cmsPipelineUnlinkStage = cmsPipelineUnlinkStage -_cmsMalloc = _cmsMalloc -_cmsMallocZero = _cmsMallocZero -_cmsMAT3eval = _cmsMAT3eval -_cmsMAT3identity = _cmsMAT3identity -_cmsMAT3inverse = _cmsMAT3inverse -_cmsMAT3isIdentity = _cmsMAT3isIdentity -_cmsMAT3per = _cmsMAT3per -_cmsMAT3solve = _cmsMAT3solve -cmsMD5computeID = cmsMD5computeID -cmsMLUalloc = cmsMLUalloc -cmsMLUdup = cmsMLUdup -cmsMLUfree = cmsMLUfree -cmsMLUgetASCII = cmsMLUgetASCII -cmsMLUgetTranslation = cmsMLUgetTranslation -cmsMLUgetWide = cmsMLUgetWide -cmsMLUsetASCII = cmsMLUsetASCII -cmsMLUsetWide = cmsMLUsetWide -cmsStageAllocCLut16bit = cmsStageAllocCLut16bit -cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular -cmsStageAllocCLutFloat = cmsStageAllocCLutFloat -cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular -cmsStageAllocToneCurves = cmsStageAllocToneCurves -cmsStageAllocIdentity = cmsStageAllocIdentity -cmsStageAllocMatrix = cmsStageAllocMatrix -_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder -cmsStageDup = cmsStageDup -cmsStageFree = cmsStageFree -cmsStageNext = cmsStageNext -cmsStageInputChannels = cmsStageInputChannels -cmsStageOutputChannels = cmsStageOutputChannels -cmsStageSampleCLut16bit = cmsStageSampleCLut16bit -cmsStageSampleCLutFloat = cmsStageSampleCLutFloat -cmsStageType = cmsStageType -cmsStageData = cmsStageData -cmsNamedColorCount = cmsNamedColorCount -cmsNamedColorIndex = cmsNamedColorIndex -cmsNamedColorInfo = cmsNamedColorInfo -cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile -cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem -cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL -cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream -cmsOpenProfileFromFile = cmsOpenProfileFromFile -cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR -cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR -cmsOpenProfileFromMem = cmsOpenProfileFromMem -cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR -cmsOpenProfileFromStream = cmsOpenProfileFromStream -cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR -cmsPlugin = cmsPlugin -_cmsRead15Fixed16Number = _cmsRead15Fixed16Number -_cmsReadAlignment = _cmsReadAlignment -_cmsReadFloat32Number = _cmsReadFloat32Number -cmsReadRawTag = cmsReadRawTag -cmsReadTag = cmsReadTag -_cmsReadTypeBase = _cmsReadTypeBase -_cmsReadUInt16Array = _cmsReadUInt16Array -_cmsReadUInt16Number = _cmsReadUInt16Number -_cmsReadUInt32Number = _cmsReadUInt32Number -_cmsReadUInt64Number = _cmsReadUInt64Number -_cmsReadUInt8Number = _cmsReadUInt8Number -_cmsReadXYZNumber = _cmsReadXYZNumber -_cmsRealloc = _cmsRealloc -cmsReverseToneCurve = cmsReverseToneCurve -cmsReverseToneCurveEx = cmsReverseToneCurveEx -cmsSaveProfileToFile = cmsSaveProfileToFile -cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler -cmsSaveProfileToMem = cmsSaveProfileToMem -cmsSaveProfileToStream = cmsSaveProfileToStream -cmsSetAdaptationState = cmsSetAdaptationState -cmsSetAlarmCodes = cmsSetAlarmCodes -cmsSetColorSpace = cmsSetColorSpace -cmsSetDeviceClass = cmsSetDeviceClass -cmsSetEncodedICCversion = cmsSetEncodedICCversion -cmsSetHeaderAttributes = cmsSetHeaderAttributes -cmsSetHeaderFlags = cmsSetHeaderFlags -cmsSetHeaderManufacturer = cmsSetHeaderManufacturer -cmsSetHeaderModel = cmsSetHeaderModel -cmsSetHeaderProfileID = cmsSetHeaderProfileID -cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent -cmsSetLogErrorHandler = cmsSetLogErrorHandler -cmsSetPCS = cmsSetPCS -cmsSetProfileVersion = cmsSetProfileVersion -cmsSignalError = cmsSignalError -cmsSmoothToneCurve = cmsSmoothToneCurve -cmsstrcasecmp = cmsstrcasecmp -cmsTempFromWhitePoint = cmsTempFromWhitePoint -cmsTransform2DeviceLink = cmsTransform2DeviceLink -cmsUnregisterPlugins = cmsUnregisterPlugins -_cmsVEC3cross = _cmsVEC3cross -_cmsVEC3distance = _cmsVEC3distance -_cmsVEC3dot = _cmsVEC3dot -_cmsVEC3init = _cmsVEC3init -_cmsVEC3length = _cmsVEC3length -_cmsVEC3minus = _cmsVEC3minus -cmsWhitePointFromTemp = cmsWhitePointFromTemp -_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number -_cmsWriteAlignment = _cmsWriteAlignment -_cmsWriteFloat32Number = _cmsWriteFloat32Number -cmsWriteRawTag = cmsWriteRawTag -cmsWriteTag = cmsWriteTag -_cmsWriteTypeBase = _cmsWriteTypeBase -_cmsWriteUInt16Array = _cmsWriteUInt16Array -_cmsWriteUInt16Number = _cmsWriteUInt16Number -_cmsWriteUInt32Number = _cmsWriteUInt32Number -_cmsWriteUInt64Number = _cmsWriteUInt64Number -_cmsWriteUInt8Number = _cmsWriteUInt8Number -_cmsWriteXYZNumber = _cmsWriteXYZNumber -cmsxyY2XYZ = cmsxyY2XYZ -cmsXYZ2Lab = cmsXYZ2Lab -cmsXYZ2xyY = cmsXYZ2xyY -cmsXYZEncoded2Float = cmsXYZEncoded2Float -cmsSliceSpace16 = cmsSliceSpace16 -cmsSliceSpaceFloat = cmsSliceSpaceFloat -cmsChangeBuffersFormat = cmsChangeBuffersFormat +LIBRARY LCMS2.DLL + +EXPORTS + +_cms15Fixed16toDouble = _cms15Fixed16toDouble +_cms8Fixed8toDouble = _cms8Fixed8toDouble +cmsAdaptToIlluminant = cmsAdaptToIlluminant +_cmsAdjustEndianess16 = _cmsAdjustEndianess16 +_cmsAdjustEndianess32 = _cmsAdjustEndianess32 +_cmsAdjustEndianess64 = _cmsAdjustEndianess64 +cmsAllocNamedColorList = cmsAllocNamedColorList +cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription +cmsAppendNamedColor = cmsAppendNamedColor +cmsBFDdeltaE = cmsBFDdeltaE +cmsBuildGamma = cmsBuildGamma +cmsBuildParametricToneCurve = cmsBuildParametricToneCurve +cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve +cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16 +cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat +_cmsCalloc = _cmsCalloc +cmsChannelsOf = cmsChannelsOf +cmsCIE2000DeltaE = cmsCIE2000DeltaE +cmsCIE94DeltaE = cmsCIE94DeltaE +cmsCIECAM02Done = cmsCIECAM02Done +cmsCIECAM02Forward = cmsCIECAM02Forward +cmsCIECAM02Init = cmsCIECAM02Init +cmsCIECAM02Reverse = cmsCIECAM02Reverse +cmsCloseIOhandler = cmsCloseIOhandler +cmsCloseProfile = cmsCloseProfile +cmsCMCdeltaE = cmsCMCdeltaE +cmsCreate_sRGBProfile = cmsCreate_sRGBProfile +cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR +cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile +cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR +cmsCreateExtendedTransform = cmsCreateExtendedTransform +cmsCreateGrayProfile = cmsCreateGrayProfile +cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR +cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink +cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR +cmsCreateLab2Profile = cmsCreateLab2Profile +cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR +cmsCreateLab4Profile = cmsCreateLab4Profile +cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR +cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink +cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR +cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform +cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR +cmsCreateNULLProfile = cmsCreateNULLProfile +cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR +cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder +cmsCreateProofingTransform = cmsCreateProofingTransform +cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR +cmsCreateRGBProfile = cmsCreateRGBProfile +cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR +cmsCreateTransform = cmsCreateTransform +cmsCreateTransformTHR = cmsCreateTransformTHR +cmsCreateXYZProfile = cmsCreateXYZProfile +cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR +cmsD50_xyY = cmsD50_xyY +cmsD50_XYZ = cmsD50_XYZ +_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber +_cmsDefaultICCintents = _cmsDefaultICCintents +cmsDeleteTransform = cmsDeleteTransform +cmsDeltaE = cmsDeltaE +cmsDetectBlackPoint = cmsDetectBlackPoint +cmsDetectDestinationBlackPoint = cmsDetectDestinationBlackPoint +cmsDetectTAC = cmsDetectTAC +cmsDesaturateLab = cmsDesaturateLab +cmsDoTransform = cmsDoTransform +cmsDoTransformStride = cmsDoTransformStride +_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16 +_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8 +_cmsDupMem = _cmsDupMem +cmsDupNamedColorList = cmsDupNamedColorList +cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription +cmsDupToneCurve = cmsDupToneCurve +_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber +cmsEstimateGamma = cmsEstimateGamma +cmsGetToneCurveEstimatedTableEntries = cmsGetToneCurveEstimatedTableEntries +cmsGetToneCurveEstimatedTable = cmsGetToneCurveEstimatedTable +cmsEvalToneCurve16 = cmsEvalToneCurve16 +cmsEvalToneCurveFloat = cmsEvalToneCurveFloat +cmsfilelength = cmsfilelength +cmsFloat2LabEncoded = cmsFloat2LabEncoded +cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2 +cmsFloat2XYZEncoded = cmsFloat2XYZEncoded +cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile +cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile +_cmsFree = _cmsFree +cmsFreeNamedColorList = cmsFreeNamedColorList +cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription +cmsFreeToneCurve = cmsFreeToneCurve +cmsFreeToneCurveTriple = cmsFreeToneCurveTriple +cmsGBDAlloc = cmsGBDAlloc +cmsGBDFree = cmsGBDFree +cmsGDBAddPoint = cmsGDBAddPoint +cmsGDBCheckPoint = cmsGDBCheckPoint +cmsGDBCompute = cmsGDBCompute +cmsGetAlarmCodes = cmsGetAlarmCodes +cmsGetColorSpace = cmsGetColorSpace +cmsGetDeviceClass = cmsGetDeviceClass +cmsGetEncodedICCversion = cmsGetEncodedICCversion +cmsGetHeaderAttributes = cmsGetHeaderAttributes +cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime +cmsGetHeaderFlags = cmsGetHeaderFlags +cmsGetHeaderManufacturer = cmsGetHeaderManufacturer +cmsGetHeaderModel = cmsGetHeaderModel +cmsGetHeaderProfileID = cmsGetHeaderProfileID +cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent +cmsGetNamedColorList = cmsGetNamedColorList +cmsGetPCS = cmsGetPCS +cmsGetPostScriptColorResource = cmsGetPostScriptColorResource +cmsGetPostScriptCRD = cmsGetPostScriptCRD +cmsGetPostScriptCSA = cmsGetPostScriptCSA +cmsGetProfileInfo = cmsGetProfileInfo +cmsGetProfileInfoASCII = cmsGetProfileInfoASCII +cmsGetProfileContextID = cmsGetProfileContextID +cmsGetProfileVersion = cmsGetProfileVersion +cmsGetSupportedIntents = cmsGetSupportedIntents +cmsGetTagCount = cmsGetTagCount +cmsGetTagSignature = cmsGetTagSignature +cmsGetTransformContextID = cmsGetTransformContextID +_cmsICCcolorSpace = _cmsICCcolorSpace +_cmsIOPrintf = _cmsIOPrintf +cmsIsCLUT = cmsIsCLUT +cmsIsIntentSupported = cmsIsIntentSupported +cmsIsMatrixShaper = cmsIsMatrixShaper +cmsIsTag = cmsIsTag +cmsIsToneCurveDescending = cmsIsToneCurveDescending +cmsIsToneCurveLinear = cmsIsToneCurveLinear +cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic +cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment +cmsGetToneCurveParametricType = cmsGetToneCurveParametricType +cmsIT8Alloc = cmsIT8Alloc +cmsIT8DefineDblFormat = cmsIT8DefineDblFormat +cmsIT8EnumDataFormat = cmsIT8EnumDataFormat +cmsIT8EnumProperties = cmsIT8EnumProperties +cmsIT8EnumPropertyMulti = cmsIT8EnumPropertyMulti +cmsIT8Free = cmsIT8Free +cmsIT8GetData = cmsIT8GetData +cmsIT8GetDataDbl = cmsIT8GetDataDbl +cmsIT8FindDataFormat = cmsIT8FindDataFormat +cmsIT8GetDataRowCol = cmsIT8GetDataRowCol +cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl +cmsIT8GetPatchName = cmsIT8GetPatchName +cmsIT8GetPatchByName = cmsIT8GetPatchByName +cmsIT8GetProperty = cmsIT8GetProperty +cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl +cmsIT8GetPropertyMulti = cmsIT8GetPropertyMulti +cmsIT8GetSheetType = cmsIT8GetSheetType +cmsIT8LoadFromFile = cmsIT8LoadFromFile +cmsIT8LoadFromMem = cmsIT8LoadFromMem +cmsIT8SaveToFile = cmsIT8SaveToFile +cmsIT8SaveToMem = cmsIT8SaveToMem +cmsIT8SetComment = cmsIT8SetComment +cmsIT8SetData = cmsIT8SetData +cmsIT8SetDataDbl = cmsIT8SetDataDbl +cmsIT8SetDataFormat = cmsIT8SetDataFormat +cmsIT8SetDataRowCol = cmsIT8SetDataRowCol +cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl +cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl +cmsIT8SetPropertyHex = cmsIT8SetPropertyHex +cmsIT8SetPropertyStr = cmsIT8SetPropertyStr +cmsIT8SetPropertyMulti = cmsIT8SetPropertyMulti +cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked +cmsIT8SetSheetType = cmsIT8SetSheetType +cmsIT8SetTable = cmsIT8SetTable +cmsIT8SetTableByLabel = cmsIT8SetTableByLabel +cmsIT8SetIndexColumn = cmsIT8SetIndexColumn +cmsIT8TableCount = cmsIT8TableCount +cmsJoinToneCurve = cmsJoinToneCurve +cmsLab2LCh = cmsLab2LCh +cmsLab2XYZ = cmsLab2XYZ +cmsLabEncoded2Float = cmsLabEncoded2Float +cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2 +cmsLCh2Lab = cmsLCh2Lab +_cmsLCMScolorSpace = _cmsLCMScolorSpace +cmsLinkTag = cmsLinkTag +cmsTagLinkedTo = cmsTagLinkedTo +cmsPipelineAlloc = cmsPipelineAlloc +cmsPipelineCat = cmsPipelineCat +cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages +cmsPipelineDup = cmsPipelineDup +cmsPipelineStageCount = cmsPipelineStageCount +cmsPipelineEval16 = cmsPipelineEval16 +cmsPipelineEvalFloat = cmsPipelineEvalFloat +cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat +cmsPipelineFree = cmsPipelineFree +cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage +cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage +cmsPipelineInputChannels = cmsPipelineInputChannels +cmsPipelineInsertStage = cmsPipelineInsertStage +cmsPipelineOutputChannels = cmsPipelineOutputChannels +cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag +_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters +cmsPipelineUnlinkStage = cmsPipelineUnlinkStage +_cmsMalloc = _cmsMalloc +_cmsMallocZero = _cmsMallocZero +_cmsMAT3eval = _cmsMAT3eval +_cmsMAT3identity = _cmsMAT3identity +_cmsMAT3inverse = _cmsMAT3inverse +_cmsMAT3isIdentity = _cmsMAT3isIdentity +_cmsMAT3per = _cmsMAT3per +_cmsMAT3solve = _cmsMAT3solve +cmsMD5computeID = cmsMD5computeID +cmsMLUalloc = cmsMLUalloc +cmsMLUdup = cmsMLUdup +cmsMLUfree = cmsMLUfree +cmsMLUgetASCII = cmsMLUgetASCII +cmsMLUgetTranslation = cmsMLUgetTranslation +cmsMLUgetWide = cmsMLUgetWide +cmsMLUsetASCII = cmsMLUsetASCII +cmsMLUsetWide = cmsMLUsetWide +cmsStageAllocCLut16bit = cmsStageAllocCLut16bit +cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular +cmsStageAllocCLutFloat = cmsStageAllocCLutFloat +cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular +cmsStageAllocToneCurves = cmsStageAllocToneCurves +cmsStageAllocIdentity = cmsStageAllocIdentity +cmsStageAllocMatrix = cmsStageAllocMatrix +_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder +cmsStageDup = cmsStageDup +cmsStageFree = cmsStageFree +cmsStageNext = cmsStageNext +cmsStageInputChannels = cmsStageInputChannels +cmsStageOutputChannels = cmsStageOutputChannels +cmsStageSampleCLut16bit = cmsStageSampleCLut16bit +cmsStageSampleCLutFloat = cmsStageSampleCLutFloat +cmsStageType = cmsStageType +cmsStageData = cmsStageData +cmsNamedColorCount = cmsNamedColorCount +cmsNamedColorIndex = cmsNamedColorIndex +cmsNamedColorInfo = cmsNamedColorInfo +cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile +cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem +cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL +cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream +cmsOpenProfileFromFile = cmsOpenProfileFromFile +cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR +cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR +cmsOpenProfileFromMem = cmsOpenProfileFromMem +cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR +cmsOpenProfileFromStream = cmsOpenProfileFromStream +cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR +cmsPlugin = cmsPlugin +_cmsRead15Fixed16Number = _cmsRead15Fixed16Number +_cmsReadAlignment = _cmsReadAlignment +_cmsReadFloat32Number = _cmsReadFloat32Number +cmsReadRawTag = cmsReadRawTag +cmsReadTag = cmsReadTag +_cmsReadTypeBase = _cmsReadTypeBase +_cmsReadUInt16Array = _cmsReadUInt16Array +_cmsReadUInt16Number = _cmsReadUInt16Number +_cmsReadUInt32Number = _cmsReadUInt32Number +_cmsReadUInt64Number = _cmsReadUInt64Number +_cmsReadUInt8Number = _cmsReadUInt8Number +_cmsReadXYZNumber = _cmsReadXYZNumber +_cmsRealloc = _cmsRealloc +cmsReverseToneCurve = cmsReverseToneCurve +cmsReverseToneCurveEx = cmsReverseToneCurveEx +cmsSaveProfileToFile = cmsSaveProfileToFile +cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler +cmsSaveProfileToMem = cmsSaveProfileToMem +cmsSaveProfileToStream = cmsSaveProfileToStream +cmsSetAdaptationState = cmsSetAdaptationState +cmsSetAlarmCodes = cmsSetAlarmCodes +cmsSetColorSpace = cmsSetColorSpace +cmsSetDeviceClass = cmsSetDeviceClass +cmsSetEncodedICCversion = cmsSetEncodedICCversion +cmsSetHeaderAttributes = cmsSetHeaderAttributes +cmsSetHeaderFlags = cmsSetHeaderFlags +cmsSetHeaderManufacturer = cmsSetHeaderManufacturer +cmsSetHeaderModel = cmsSetHeaderModel +cmsSetHeaderProfileID = cmsSetHeaderProfileID +cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent +cmsSetLogErrorHandler = cmsSetLogErrorHandler +cmsSetPCS = cmsSetPCS +cmsSetProfileVersion = cmsSetProfileVersion +cmsSignalError = cmsSignalError +cmsSmoothToneCurve = cmsSmoothToneCurve +cmsstrcasecmp = cmsstrcasecmp +cmsTempFromWhitePoint = cmsTempFromWhitePoint +cmsTransform2DeviceLink = cmsTransform2DeviceLink +cmsUnregisterPlugins = cmsUnregisterPlugins +_cmsVEC3cross = _cmsVEC3cross +_cmsVEC3distance = _cmsVEC3distance +_cmsVEC3dot = _cmsVEC3dot +_cmsVEC3init = _cmsVEC3init +_cmsVEC3length = _cmsVEC3length +_cmsVEC3minus = _cmsVEC3minus +cmsWhitePointFromTemp = cmsWhitePointFromTemp +_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number +_cmsWriteAlignment = _cmsWriteAlignment +_cmsWriteFloat32Number = _cmsWriteFloat32Number +cmsWriteRawTag = cmsWriteRawTag +cmsWriteTag = cmsWriteTag +_cmsWriteTypeBase = _cmsWriteTypeBase +_cmsWriteUInt16Array = _cmsWriteUInt16Array +_cmsWriteUInt16Number = _cmsWriteUInt16Number +_cmsWriteUInt32Number = _cmsWriteUInt32Number +_cmsWriteUInt64Number = _cmsWriteUInt64Number +_cmsWriteUInt8Number = _cmsWriteUInt8Number +_cmsWriteXYZNumber = _cmsWriteXYZNumber +cmsxyY2XYZ = cmsxyY2XYZ +cmsXYZ2Lab = cmsXYZ2Lab +cmsXYZ2xyY = cmsXYZ2xyY +cmsXYZEncoded2Float = cmsXYZEncoded2Float +cmsSliceSpace16 = cmsSliceSpace16 +cmsSliceSpaceFloat = cmsSliceSpaceFloat +cmsChangeBuffersFormat = cmsChangeBuffersFormat +cmsDictAlloc = cmsDictAlloc +cmsDictFree = cmsDictFree +cmsDictDup = cmsDictDup +cmsDictAddEntry = cmsDictAddEntry +cmsDictGetEntryList = cmsDictGetEntryList +cmsDictNextEntry = cmsDictNextEntry +_cmsGetTransformUserData = _cmsGetTransformUserData +_cmsSetTransformUserData = _cmsSetTransformUserData +_cmsGetTransformFormatters16 = _cmsGetTransformFormatters16 +_cmsGetTransformFormattersFloat = _cmsGetTransformFormattersFloat +cmsGetHeaderCreator = cmsGetHeaderCreator +cmsPluginTHR = cmsPluginTHR +cmsGetPipelineContextID = cmsGetPipelineContextID +cmsGetTransformInputFormat = cmsGetTransformInputFormat +cmsGetTransformOutputFormat = cmsGetTransformOutputFormat +cmsCreateContext = cmsCreateContext +cmsDupContext = cmsDupContext +cmsDeleteContext = cmsDeleteContext +cmsGetContextUserData = cmsGetContextUserData +cmsUnregisterPluginsTHR = cmsUnregisterPluginsTHR +cmsSetAlarmCodesTHR = cmsSetAlarmCodesTHR +cmsGetAlarmCodesTHR = cmsGetAlarmCodesTHR +cmsSetAdaptationStateTHR = cmsSetAdaptationStateTHR +cmsSetLogErrorHandlerTHR = cmsSetLogErrorHandlerTHR +cmsGetSupportedIntentsTHR = cmsGetSupportedIntentsTHR +cmsMLUtranslationsCount = cmsMLUtranslationsCount +cmsMLUtranslationsCodes = cmsMLUtranslationsCodes +_cmsCreateMutex = _cmsCreateMutex +_cmsDestroyMutex = _cmsDestroyMutex +_cmsLockMutex = _cmsLockMutex +_cmsUnlockMutex = _cmsUnlockMutex \ No newline at end of file diff --git a/thirdparty/liblcms2/src/lcms2_internal.h b/thirdparty/liblcms2/src/lcms2_internal.h index 84e5a80f..1a648302 100644 --- a/thirdparty/liblcms2/src/lcms2_internal.h +++ b/thirdparty/liblcms2/src/lcms2_internal.h @@ -1,24 +1,24 @@ // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -46,16 +46,18 @@ # define M_LOG10E 0.434294481903251827651 #endif -// BorlandC 5.5 is broken on that -#ifdef __BORLANDC__ +// BorlandC 5.5, VC2003 are broken on that +#if defined(__BORLANDC__) || (_MSC_VER < 1400) // 1400 == VC++ 8.0 #define sinf(x) (float)sin((float)x) #define sqrtf(x) (float)sqrt((float)x) #endif // Alignment of ICC file format uses 4 bytes (cmsUInt32Number) -#define _cmsSIZEOFLONGMINUS1 (sizeof(cmsUInt32Number)-1) -#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1)) +#define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1)) + +// Alignment to memory pointer +#define _cmsALIGNMEM(x) (((x)+(sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) // Maximum encodeable values in floating point #define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) @@ -65,10 +67,10 @@ #define MAX_ENCODEABLE_ab4 (127.0) // Maximum of channels for internal pipeline evaluation -#define MAX_STAGE_CHANNELS 128 +#define MAX_STAGE_CHANNELS 128 // Unused parameter warning supression -#define cmsUNUSED_PARAMETER(x) ((void)x) +#define cmsUNUSED_PARAMETER(x) ((void)x) // The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999). // unfortunately VisualC++ does not conform that @@ -88,39 +90,9 @@ # endif #endif -// Pthreads. In windows we use the native WIN32 API instead -#ifdef CMS_DONT_USE_PTHREADS -typedef int LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) -# define LCMS_FREE_LOCK(x) -# define LCMS_READ_LOCK(x) -# define LCMS_WRITE_LOCK(x) -# define LCMS_UNLOCK(x) -#else -#ifdef CMS_IS_WINDOWS_ -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include - typedef CRITICAL_SECTION LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x)) -# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x)) -# define LCMS_READ_LOCK(x) EnterCriticalSection((x)) -# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x)) -# define LCMS_UNLOCK(x) LeaveCriticalSection((x)) -#else -# include - typedef pthread_rwlock_t LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL) -# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x)) -# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x)) -# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x)) -# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x)) -#endif -#endif // A fast way to convert from/to 16 <-> 8 bits -#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) +#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) #define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF) // Code analysis is broken on asserts @@ -147,12 +119,12 @@ typedef int LCMS_RWLOCK_T; #define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16) cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); } -cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); } +cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); } // ----------------------------------------------------------------------------------------------------------- -// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon -// note than this only works in the range ..-32767...+32767 because +// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon +// note than this only works in the range ..-32767...+32767 because // mantissa is interpreted as 15.16 fixed point. // The union is to avoid pointer aliasing overoptimization. cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) @@ -165,9 +137,9 @@ cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) cmsFloat64Number val; int halves[2]; } temp; - + temp.val = val + _lcms_double2fixmagic; - + #ifdef CMS_USE_BIG_ENDIAN return temp.halves[1] >> 16; #else @@ -177,13 +149,13 @@ cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) } // Fast floor restricted to 0..65535.0 -cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d) -{ - return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U; +cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d) +{ + return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U; } // Floor to word, taking care of saturation -cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) +cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) { d += 0.5; if (d <= 0) return 0; @@ -192,42 +164,202 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) return _cmsQuickFloorWord(d); } -// Plug-In registering --------------------------------------------------------------- + +// Pthread support -------------------------------------------------------------------- +#ifndef CMS_NO_PTHREADS + +// This is the threading support. Unfortunately, it has to be platform-dependent because +// windows does not support pthreads. + +#ifdef CMS_IS_WINDOWS_ + +#define WIN32_LEAN_AND_MEAN 1 +#include + + +// From: http://locklessinc.com/articles/pthreads_on_windows/ +// The pthreads API has an initialization macro that has no correspondence to anything in +// the windows API. By investigating the internal definition of the critical section type, +// one may work out how to initialize one without calling InitializeCriticalSection(). +// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries +// to allocate a critical section debug object, but if no memory is available, it sets +// the pointer to a specific value. (One would expect that value to be NULL, but it is +// actually (void *)-1 for some reason.) Thus we can use this special value for that +// pointer, and the critical section code will work. + +// The other important part of the critical section type to initialize is the number +// of waiters. This controls whether or not the mutex is locked. Fortunately, this +// part of the critical section is unlikely to change. Apparently, many programs +// already test critical sections to see if they are locked using this value, so +// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical +// section, even when they changed the underlying algorithm to be more scalable. +// The final parts of the critical section object are unimportant, and can be set +// to zero for their defaults. This yields an initialization macro: + +typedef CRITICAL_SECTION _cmsMutex; + +#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0} + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + InitializeCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + DeleteCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +#else + +// Rest of the wide world +#include + +#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_init(m, NULL); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_destroy(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +#endif +#else + +#define CMS_MUTEX_INITIALIZER 0 +typedef int _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} +#endif + +// Plug-In registration --------------------------------------------------------------- // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. -void* _cmsPluginMalloc(cmsUInt32Number size); +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); // Memory management -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Interpolation -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Tag type management -cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Tag management -cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Intent management -cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Multi Process elements -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Optimization -cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin); +// Transform +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Mutex +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // --------------------------------------------------------------------------------------------------------- -// Suballocators. Those are blocks of memory that is freed at the end on whole block. +// Suballocators. typedef struct _cmsSubAllocator_chunk_st { cmsUInt8Number* Block; @@ -250,37 +382,292 @@ typedef struct { _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); void _cmsSubAllocDestroy(_cmsSubAllocator* s); void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); // ---------------------------------------------------------------------------------- +// The context clients. +typedef enum { + + UserPtr, // User-defined pointer + Logger, + AlarmCodesContext, + AdaptationStateContext, + MemPlugin, + InterpPlugin, + CurvesPlugin, + FormattersPlugin, + TagTypePlugin, + TagPlugin, + IntentPlugin, + MPEPlugin, + OptimizationPlugin, + TransformPlugin, + MutexPlugin, + + // Last in list + MemoryClientMax + +} _cmsMemoryClient; + + +// Container for memory management plug-in. +typedef struct { + + _cmsMallocFnPtrType MallocPtr; + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} _cmsMemPluginChunkType; + +// Copy memory management function pointers from plug-in to chunk, taking care of missing routines +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); + +// Internal structure for context +struct _cmsContext_struct { + + struct _cmsContext_struct* Next; // Points to next context in the new style + _cmsSubAllocator* MemPool; // The memory pool that stores context data + + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + // If NULL, then it reverts to global Context0 + + _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden +}; + +// Returns a pointer to a valid context structure, including the global one if id is zero. +// Verifies the magic number. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); + +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); + + +// Chunks of context memory by plug-in client ------------------------------------------------------- + +// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) + +// Container for error logger -- not a plug-in +typedef struct { + + cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback + +} _cmsLogErrorChunkType; + +// The global Context0 storage for error logger +extern _cmsLogErrorChunkType _cmsLogErrorChunk; + +// Allocate and init error logger container. +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for alarm codes -- not a plug-in +typedef struct { + + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; + +} _cmsAlarmCodesChunkType; + +// The global Context0 storage for alarm codes +extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; + +// Allocate and init alarm codes container. +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for adaptation state -- not a plug-in +typedef struct { + + cmsFloat64Number AdaptationState; + +} _cmsAdaptationStateChunkType; + +// The global Context0 storage for adaptation state +extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; + +// Allocate and init adaptation state container. +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + + +// The global Context0 storage for memory management +extern _cmsMemPluginChunkType _cmsMemPluginChunk; + +// Allocate and init memory management container. +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for interpolation plug-in +typedef struct { + + cmsInterpFnFactory Interpolators; + +} _cmsInterpPluginChunkType; + +// The global Context0 storage for interpolation plug-in +extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; + +// Allocate and init interpolation container. +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for parametric curves plug-in +typedef struct { + + struct _cmsParametricCurvesCollection_st* ParametricCurves; + +} _cmsCurvesPluginChunkType; + +// The global Context0 storage for tone curves plug-in +extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; + +// Allocate and init parametric curves container. +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for formatters plug-in +typedef struct { + + struct _cms_formatters_factory_list* FactoryList; + +} _cmsFormattersPluginChunkType; + +// The global Context0 storage for formatters plug-in +extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; + +// Allocate and init formatters container. +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// This chunk type is shared by TagType plug-in and MPE Plug-in +typedef struct { + + struct _cmsTagTypeLinkedList_st* TagTypes; + +} _cmsTagTypePluginChunkType; + + +// The global Context0 storage for tag types plug-in +extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; + + +// The global Context0 storage for mult process elements plug-in +extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; + +// Allocate and init Tag types container. +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Allocate and init MPE container. +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Container for tag plug-in +typedef struct { + + struct _cmsTagLinkedList_st* Tag; + +} _cmsTagPluginChunkType; + + +// The global Context0 storage for tag plug-in +extern _cmsTagPluginChunkType _cmsTagPluginChunk; + +// Allocate and init Tag container. +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for intents plug-in +typedef struct { + + struct _cms_intents_list* Intents; + +} _cmsIntentsPluginChunkType; + + +// The global Context0 storage for intents plug-in +extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; + +// Allocate and init intents container. +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for optimization plug-in +typedef struct { + + struct _cmsOptimizationCollection_st* OptimizationCollection; + +} _cmsOptimizationPluginChunkType; + + +// The global Context0 storage for optimizers plug-in +extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; + +// Allocate and init optimizers container. +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for transform plug-in +typedef struct { + + struct _cmsTransformCollection_st* TransformCollection; + +} _cmsTransformPluginChunkType; + +// The global Context0 storage for full-transform replacement plug-in +extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; + +// Allocate and init transform container. +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for mutex plug-in +typedef struct { + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} _cmsMutexPluginChunkType; + +// The global Context0 storage for mutex plug-in +extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// ---------------------------------------------------------------------------------- // MLU internal representation typedef struct { cmsUInt16Number Language; - cmsUInt16Number Country; + cmsUInt16Number Country; cmsUInt32Number StrW; // Offset to current unicode string - cmsUInt32Number Len; // Lenght in bytes + cmsUInt32Number Len; // Length in bytes } _cmsMLUentry; struct _cms_MLU_struct { - + cmsContext ContextID; // The directory - int AllocatedEntries; + int AllocatedEntries; int UsedEntries; _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool // The Pool cmsUInt32Number PoolSize; // The maximum allocated size cmsUInt32Number PoolUsed; // The used size - void* MemPool; // Pointer to begin of memory pool + void* MemPool; // Pointer to begin of memory pool }; // Named color list internal representation -typedef struct { +typedef struct { char Name[cmsMAX_PATH]; cmsUInt16Number PCS[3]; @@ -290,12 +677,12 @@ typedef struct { struct _cms_NAMEDCOLORLIST_struct { - cmsUInt32Number nColors; + cmsUInt32Number nColors; cmsUInt32Number Allocated; - cmsUInt32Number ColorantCount; + cmsUInt32Number ColorantCount; char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most - char Suffix[33]; + char Suffix[33]; _cmsNAMEDCOLOR* List; @@ -321,15 +708,17 @@ typedef struct _cms_iccprofile_struct { // Creation time struct tm Created; - // Only most important items found in ICC profiles + // Only most important items found in ICC profiles cmsUInt32Number Version; cmsProfileClassSignature DeviceClass; cmsColorSpaceSignature ColorSpace; cmsColorSpaceSignature PCS; cmsUInt32Number RenderingIntent; + cmsUInt32Number flags; cmsUInt32Number manufacturer, model; cmsUInt64Number attributes; + cmsUInt32Number creator; cmsProfileID ProfileID; @@ -342,10 +731,14 @@ typedef struct _cms_iccprofile_struct { cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked void * TagPtrs[MAX_TABLE_TAG]; cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types - // depending on profile version, so we keep track of the // type handler for each tag in the list. + // depending on profile version, so we keep track of the + // type handler for each tag in the list. // Special cmsBool IsWrite; - + + // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin + void * UsrMutex; + } _cmsICCPROFILE; // IO helpers for profiles @@ -354,9 +747,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSp int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); // Tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig); +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); // Error logging --------------------------------------------------------------------------------------------------------- @@ -367,7 +760,7 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); void _cmsFreeInterpParams(cmsInterpParams* p); -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); // Curves ---------------------------------------------------------------------------------------------------------------- @@ -385,19 +778,19 @@ struct _cms_curve_struct { cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment) - // 16 bit Table-based representation follows + // 16 bit Table-based representation follows cmsUInt32Number nEntries; // Number of table elements - cmsUInt16Number* Table16; // The table itself. -}; + cmsUInt16Number* Table16; // The table itself. +}; // Pipelines & Stages --------------------------------------------------------------------------------------------- // A single stage struct _cmsStage_struct { - + cmsContext ContextID; - + cmsStageSignature Type; // Identifies the stage cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations) @@ -415,37 +808,6 @@ struct _cmsStage_struct { struct _cmsStage_struct* Next; }; -// Data kept in "Element" member of cmsStage - -// Curves -typedef struct { - cmsUInt32Number nCurves; - cmsToneCurve** TheCurves; - -} _cmsStageToneCurvesData; - -// Matrix -typedef struct { - cmsFloat64Number* Double; // floating point for the matrix - cmsFloat64Number* Offset; // The offset - -} _cmsStageMatrixData; - -// CLUT -typedef struct { - - union { // Can have only one of both representations at same time - cmsUInt16Number* T; // Points to the table 16 bits table - cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table - - } Tab; - - cmsInterpParams* Params; - cmsUInt32Number nEntries; - cmsBool HasFloatValues; - -} _cmsStageCLutData; - // Special Stages (cannot be saved) cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID); @@ -454,35 +816,39 @@ cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID); cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID); cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID); cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID); -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList); +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS); cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels); cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan); +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID); -// For curve set only +// For curve set only cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); // Pipeline Evaluator (in floating point) -typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[], - cmsFloat32Number Out[], - const void* Data); +typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const void* Data); struct _cmsPipeline_struct { - cmsStage* Elements; // Points to elements chain - cmsUInt32Number InputChannels, OutputChannels; - + cmsStage* Elements; // Points to elements chain + cmsUInt32Number InputChannels, OutputChannels; + // Data & evaluators void *Data; _cmsOPTeval16Fn Eval16Fn; _cmsPipelineEvalFloatFn EvalFloatFn; - _cmsOPTfreeDataFn FreeDataFn; - _cmsOPTdupDataFn DupDataFn; - + _cmsFreeUserDataFn FreeDataFn; + _cmsDupUserDataFn DupDataFn; + cmsContext ContextID; // Environment - cmsBool SaveAs8Bits; // Implemntation-specific: save as 8 bits if possible + cmsBool SaveAs8Bits; // Implementation-specific: save as 8 bits if possible }; // LUT reading & creation ------------------------------------------------------------------------------------------- @@ -500,10 +866,10 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile); // Profile linker -------------------------------------------------------------------------------------------------- -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -520,14 +886,15 @@ cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfil cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples); int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags); -cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, - cmsUInt16Number **White, +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, cmsUInt16Number **Black, cmsUInt32Number *nOutputs); -cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** Lut, int Intent, - cmsUInt32Number* InputFormat, + cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags ); @@ -535,11 +902,11 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, // Hi level LUT building ---------------------------------------------------------------------------------------------- cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], cmsFloat64Number AdaptationStates[], - cmsUInt32Number nGamutPCSposition, + cmsUInt32Number nGamutPCSposition, cmsHPROFILE hGamut); @@ -550,26 +917,33 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 - cmsFormatterDirection Dir, +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, cmsUInt32Number dwFlags); +#ifndef CMS_NO_HALF_SUPPORT + +// Half float +cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h); +cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt); + +#endif + // Transform logic ------------------------------------------------------------------------------------------------------ struct _cmstransform_struct; -// Full xform -typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform, - const void* InputBuffer, - void* OutputBuffer, cmsUInt32Number Size); - typedef struct { - cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference - cmsUInt32Number StrideIn, StrideOut; // Planar support + // 1-pixel cache (16 bits only) + cmsUInt16Number CacheIn[cmsMAXCHANNELS]; + cmsUInt16Number CacheOut[cmsMAXCHANNELS]; + +} _cmsCACHE; + -} cmsFormatterInfo; // Transformation typedef struct _cmstransform_struct { @@ -585,18 +959,14 @@ typedef struct _cmstransform_struct { cmsFormatterFloat FromInputFloat; cmsFormatterFloat ToOutputFloat; - - // 1-pixel cache (16 bits only) - cmsUInt16Number CacheIn[cmsMAXCHANNELS]; - cmsUInt16Number CacheOut[cmsMAXCHANNELS]; - // Semaphor for cache - LCMS_RWLOCK_T rwlock; - - // A MPE LUT holding the full (optimized) transform + // 1-pixel cache seed for zero as input (16 bits, read only) + _cmsCACHE Cache; + + // A Pipeline holding the full (optimized) transform cmsPipeline* Lut; - - // A MPE LUT holding the gamut check. It goes from the input space to bilevel + + // A Pipeline holding the gamut check. It goes from the input space to bilevel cmsPipeline* GamutCheck; // Colorant tables @@ -606,12 +976,16 @@ typedef struct _cmstransform_struct { // Informational only cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature ExitColorSpace; - + + // White points (informative only) + cmsCIEXYZ EntryWhitePoint; + cmsCIEXYZ ExitWhitePoint; + // Profiles used to create the transform cmsSEQ* Sequence; - cmsUInt32Number dwOriginalFlags; - cmsFloat64Number AdaptationState; + cmsUInt32Number dwOriginalFlags; + cmsFloat64Number AdaptationState; // The intent of this transform. That is usually the last intent in the profilechain, but may differ cmsUInt32Number RenderingIntent; @@ -619,6 +993,10 @@ typedef struct _cmstransform_struct { // An id that uniquely identifies the running context. May be null. cmsContext ContextID; + // A user-defined pointer that can be used to store data for transform plug-ins + void* UserData; + _cmsFreeUserDataFn FreeUserData; + } _cmsTRANSFORM; // -------------------------------------------------------------------------------------------------- @@ -627,18 +1005,18 @@ cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, cmsUInt32Number nProfiles, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], const cmsBool BPC[], const cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); -cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, cmsUInt32Number nPoints, cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], const cmsBool BPC[], const cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); diff --git a/thirdparty/libpng/LICENSE b/thirdparty/libpng/LICENSE index 756ebd04..eb4a9a9d 100644 --- a/thirdparty/libpng/LICENSE +++ b/thirdparty/libpng/LICENSE @@ -10,8 +10,8 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.4.4, September 23, 2010, are -Copyright (c) 2004, 2006-2010 Glenn Randers-Pehrson, and are +libpng versions 1.2.6, August 15, 2004, through 1.6.17, March 26, 2015, are +Copyright (c) 2004, 2006-2015 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -108,4 +108,4 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -September 23, 2010 +March 26, 2015 diff --git a/thirdparty/libpng/example.c b/thirdparty/libpng/example.c deleted file mode 100644 index d7391734..00000000 --- a/thirdparty/libpng/example.c +++ /dev/null @@ -1,838 +0,0 @@ - -#if 0 /* in case someone actually tries to compile this */ - -/* example.c - an example of using libpng - * Last changed in libpng 1.4.2 [May 6, 2010] - * This file has been placed in the public domain by the authors. - * Maintained 1998-2010 Glenn Randers-Pehrson - * Maintained 1996, 1997 Andreas Dilger) - * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - */ - -/* 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, NULL, 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, 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 - * quantizing, 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_palette_to_rgb(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_gray_1_2_4_to_8(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_tRNS_to_alpha(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 monitor 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); - } - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - /* Quantize 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 quantized */ - png_color std_color_cube[MAX_SCREEN_COLORS]; - - /* Prior to libpng-1.4.2, this was png_set_dither(). */ - png_set_quantize(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 = NULL; - - png_get_hIST(png_ptr, info_ptr, &histogram); - - png_set_quantize(png_ptr, palette, num_palette, - max_screen_colors, histogram, 0); - } - } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ - - /* 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_p; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); - png_set_shift(png_ptr, sig_bit_p); - } - - /* 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]; - - /* Clear the pointer array */ - for (row = 0; row < height; row++) - row_pointers[row] = NULL; - - 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); -#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, 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, NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf((*png_ptr)))) - { - png_destroy_read_struct(png_ptr, info_ptr, 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, 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 interlaced, and you turned on the interlace handler, - * this function will be called for every row in every pass. - * - * In this function you will receive a pointer to new row data from - * libpng called new_row that is to replace a corresponding row (of - * the same data format) in a buffer allocated by your application. - * - * The new row data pointer "new_row" may be NULL, indicating there is - * no new data to be replaced (in cases of interlace loading). - * - * If new_row is not NULL then you need to call - * png_progressive_combine_row() to replace the corresponding row as - * shown below: - */ - - /* Get pointer to corresponding row in our - * PNG read buffer. - */ - png_bytep old_row = ((png_bytep *)our_data)[row_num]; - - /* If both rows are allocated then copy the new row - * data to the corresponding row data. - */ - if ((old_row != NULL) && (new_row != NULL)) - png_progressive_combine_row(png_ptr, old_row, new_row); - - /* - * 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 new row and the - * old row, as demonstrated above. 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 as new_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, 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 writing 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 write 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 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 - * png_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 (sBIT) chunk */ - png_color_8 sig_bit; - /* 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[0].lang_key = NULL; - text_ptr[1].lang = NULL; - text_ptr[1].lang_key = NULL; - text_ptr[2].lang = NULL; - text_ptr[2].lang_key = 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, if your application chooses to write them, they 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.2.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]; - - if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error (png_ptr, "Image is too tall to process in memory"); - - 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.2.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; - /* Whenever you use png_free() it is a good idea to set the pointer to - * NULL in case your application inadvertently tries to png_free() it - * again. When png_free() sees a NULL it returns without action, thus - * avoiding the double-free security problem. - */ - - /* 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/thirdparty/libpng/png.c b/thirdparty/libpng/png.c index f2e5888f..7575ede9 100644 --- a/thirdparty/libpng/png.c +++ b/thirdparty/libpng/png.c @@ -1,8 +1,8 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.4.2 [May 6, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,17 +11,10 @@ * and license in png.h */ -#define PNG_NO_EXTERN -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_4_4 Your_png_h_is_not_version_1_4_4; - -/* Version information for C files. This had better match the version - * string defined in png.h. - */ +typedef png_libpng_version_1_6_17 Your_png_h_is_not_version_1_6_17; /* 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 @@ -31,7 +24,7 @@ typedef version_1_4_4 Your_png_h_is_not_version_1_4_4; #ifdef PNG_READ_SUPPORTED void PNGAPI -png_set_sig_bytes(png_structp png_ptr, int num_bytes) +png_set_sig_bytes(png_structrp png_ptr, int num_bytes) { png_debug(1, "in png_set_sig_bytes"); @@ -41,7 +34,7 @@ png_set_sig_bytes(png_structp png_ptr, int num_bytes) 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); + png_ptr->sig_bytes = (png_byte)((num_bytes < 0 ? 0 : num_bytes) & 0xff); } /* Checks whether the supplied bytes match the PNG signature. We allow @@ -50,14 +43,16 @@ png_set_sig_bytes(png_structp png_ptr, int num_bytes) * 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). + * PNG signature (this is the same behavior as strcmp, memcmp, etc). */ int PNGAPI -png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) +png_sig_cmp(png_const_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 (-1); @@ -67,51 +62,47 @@ png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) if (start + num_to_check > 8) num_to_check = 8 - start; - return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); + return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Function to allocate memory for zlib and clear it to 0. */ -voidpf /* PRIVATE */ -png_zalloc(voidpf png_ptr, uInt items, uInt size) +/* Function to allocate memory for zlib */ +PNG_FUNCTION(voidpf /* PRIVATE */, +png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) { - png_voidp ptr; - png_structp p=(png_structp)png_ptr; - png_uint_32 save_flags=p->flags; - png_alloc_size_t num_bytes; + png_alloc_size_t num_bytes = size; if (png_ptr == NULL) - return (NULL); - if (items > PNG_UINT_32_MAX/size) + return NULL; + + if (items >= (~(png_alloc_size_t)0)/size) { - png_warning (p, "Potential overflow in png_zalloc()"); - return (NULL); + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); + return NULL; } - num_bytes = (png_alloc_size_t)items * size; - p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); - p->flags=save_flags; - - return ((voidpf)ptr); + num_bytes *= items; + return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); } /* Function to free memory for zlib */ void /* PRIVATE */ png_zfree(voidpf png_ptr, voidpf ptr) { - png_free((png_structp)png_ptr, (png_voidp)ptr); + png_free(png_voidcast(png_const_structrp,png_ptr), 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_reset_crc(png_structrp png_ptr) { - png_ptr->crc = crc32(0, Z_NULL, 0); + /* The cast is safe because the crc is a 32 bit value. */ + png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); } /* Calculate the CRC over a section of data. We can only pass as @@ -120,63 +111,256 @@ png_reset_crc(png_structp png_ptr) * trouble of calculating it. */ void /* PRIVATE */ -png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) { int need_crc = 1; - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) need_crc = 0; } - else /* critical */ + + else /* critical */ { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } - if (need_crc) - png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); + /* 'uLong' is defined in zlib.h as unsigned long; this means that on some + * systems it is a 64 bit value. crc32, however, returns 32 bits so the + * following cast is safe. 'uInt' may be no more than 16 bits, so it is + * necessary to perform a loop here. + */ + if (need_crc != 0 && length > 0) + { + uLong crc = png_ptr->crc; /* Should never issue a warning */ + + do + { + uInt safe_length = (uInt)length; +#ifndef __COVERITY__ + if (safe_length == 0) + safe_length = (uInt)-1; /* evil, but safe */ +#endif + + crc = crc32(crc, ptr, safe_length); + + /* The following should never issue compiler warnings; if they do the + * target system has characteristics that will probably violate other + * assumptions within the libpng code. + */ + ptr += safe_length; + length -= safe_length; + } + while (length > 0); + + /* And the following is always safe because the crc is only 32 bits. */ + png_ptr->crc = (png_uint_32)crc; + } } -/* 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(png_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. +/* Check a user supplied version number, called from both read and write + * functions that create a png_struct. */ -png_infop PNGAPI -png_create_info_struct(png_structp png_ptr) +int +png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) { - png_infop info_ptr; + /* Libpng versions 1.0.0 and later are binary compatible if the version + * string matches through the second '.'; we must recompile any + * applications that use any older library version. + */ + + if (user_png_ver != NULL) + { + int i = -1; + int found_dots = 0; + + do + { + i++; + if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + if (user_png_ver[i] == '.') + found_dots++; + } while (found_dots < 2 && user_png_ver[i] != 0 && + PNG_LIBPNG_VER_STRING[i] != 0); + } + + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) + { +#ifdef PNG_WARNINGS_SUPPORTED + size_t pos = 0; + char m[128]; + + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); + PNG_UNUSED(pos) + + png_warning(png_ptr, m); +#endif + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } + + /* Success return. */ + return 1; +} + +/* Generic function to create a png_struct for either read or write - this + * contains the common initialization. + */ +PNG_FUNCTION(png_structp /* PRIVATE */, +png_create_png_struct,(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),PNG_ALLOCATED) +{ + png_struct create_struct; +# ifdef PNG_SETJMP_SUPPORTED + jmp_buf create_jmp_buf; +# endif + + /* This temporary stack-allocated structure is used to provide a place to + * build enough context to allow the user provided memory allocator (if any) + * to be called. + */ + memset(&create_struct, 0, (sizeof create_struct)); + + /* Added at libpng-1.2.6 */ +# ifdef PNG_USER_LIMITS_SUPPORTED + create_struct.user_width_max = PNG_USER_WIDTH_MAX; + create_struct.user_height_max = PNG_USER_HEIGHT_MAX; + +# ifdef PNG_USER_CHUNK_CACHE_MAX + /* Added at libpng-1.2.43 and 1.4.0 */ + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif + +# ifdef PNG_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists + * in png_struct regardless. + */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; +# endif +# endif + + /* The following two API calls simply set fields in png_struct, so it is safe + * to do them now even though error handling is not yet set up. + */ +# ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); +# else + PNG_UNUSED(mem_ptr) + PNG_UNUSED(malloc_fn) + PNG_UNUSED(free_fn) +# endif + + /* (*error_fn) can return control to the caller after the error_ptr is set, + * this will result in a memory leak unless the error_fn does something + * extremely sophisticated. The design lacks merit but is implicit in the + * API. + */ + png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); + +# ifdef PNG_SETJMP_SUPPORTED + if (!setjmp(create_jmp_buf)) + { + /* Temporarily fake out the longjmp information until we have + * successfully completed this function. This only works if we have + * setjmp() support compiled in, but it is safe - this stuff should + * never happen. + */ + create_struct.jmp_buf_ptr = &create_jmp_buf; + create_struct.jmp_buf_size = 0; /*stack allocation*/ + create_struct.longjmp_fn = longjmp; +# else + { +# endif + /* Call the general version checker (shared with read and write code): + */ + if (png_user_version_check(&create_struct, user_png_ver) != 0) + { + png_structrp png_ptr = png_voidcast(png_structrp, + png_malloc_warn(&create_struct, (sizeof *png_ptr))); + + if (png_ptr != NULL) + { + /* png_ptr->zstream holds a back-pointer to the png_struct, so + * this can only be done now: + */ + create_struct.zstream.zalloc = png_zalloc; + create_struct.zstream.zfree = png_zfree; + create_struct.zstream.opaque = png_ptr; + +# ifdef PNG_SETJMP_SUPPORTED + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; +# endif + + *png_ptr = create_struct; + + /* This is the successful return point */ + return png_ptr; + } + } + } + + /* A longjmp because of a bug in the application storage allocator or a + * simple failure to allocate the png_struct. + */ + return NULL; +} + +/* Allocate the memory for an info_struct for the application. */ +PNG_FUNCTION(png_infop,PNGAPI +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) +{ + png_inforp info_ptr; png_debug(1, "in png_create_info_struct"); if (png_ptr == NULL) - return (NULL); + return NULL; + + /* Use the internal API that does not (or at least should not) error out, so + * that this call always returns ok. The application typically sets up the + * error handling *after* creating the info_struct because this is the way it + * has always been done in 'example.c'. + */ + info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, + (sizeof *info_ptr))); -#ifdef PNG_USER_MEM_SUPPORTED - info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, - png_ptr->malloc_fn, png_ptr->mem_ptr); -#else - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); -#endif if (info_ptr != NULL) - png_info_init_3(&info_ptr, png_sizeof(png_info)); + memset(info_ptr, 0, (sizeof *info_ptr)); - return (info_ptr); + 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. + * useful for some applications. From libpng 1.6.0 this function is also used + * internally to implement the png_info release part of the 'struct' destroy + * APIs. This ensures that all possible approaches free the same data (all of + * it). */ void PNGAPI -png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) { - png_infop info_ptr = NULL; + png_inforp info_ptr = NULL; png_debug(1, "in png_destroy_info_struct"); @@ -188,46 +372,57 @@ png_destroy_info_struct(png_structp png_ptr, png_infopp 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 + /* Do this first in case of an error below; if the app implements its own + * memory management this can lead to png_free calling png_error, which + * will abort this routine and return control to the app error handler. + * An infinite loop may result if it then tries to free the same info + * ptr. + */ *info_ptr_ptr = NULL; + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + memset(info_ptr, 0, (sizeof *info_ptr)); + png_free(png_ptr, info_ptr); } } /* 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. + * instead. Use deprecated in 1.6.0, internal use removed (used internally it + * is just a memset). + * + * NOTE: it is almost inconceivable that this API is used because it bypasses + * the user-memory mechanism and the user error handling/warning mechanisms in + * those cases where it does anything other than a memset. */ - -void PNGAPI -png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +PNG_FUNCTION(void,PNGAPI +png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), + PNG_DEPRECATED) { - png_infop info_ptr = *ptr_ptr; + png_inforp info_ptr = *ptr_ptr; png_debug(1, "in png_info_init_3"); if (info_ptr == NULL) return; - if (png_sizeof(png_info) > png_info_struct_size) + 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 = NULL; + /* The following line is why this API should not be used: */ + free(info_ptr); + info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, + (sizeof *info_ptr))); *ptr_ptr = info_ptr; } /* Set everything to 0 */ - png_memset(info_ptr, 0, png_sizeof(png_info)); + memset(info_ptr, 0, (sizeof *info_ptr)); } +/* The following API is not called internally */ void PNGAPI -png_data_freer(png_structp png_ptr, png_infop info_ptr, +png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, int freer, png_uint_32 mask) { png_debug(1, "in png_data_freer"); @@ -237,15 +432,16 @@ png_data_freer(png_structp png_ptr, png_infop info_ptr, 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"); + png_error(png_ptr, "Unknown freer parameter in png_data_freer"); } void PNGAPI -png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, +png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, int num) { png_debug(1, "in png_free_data"); @@ -255,68 +451,68 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_TEXT_SUPPORTED /* Free text item num or (if num == -1) all text items */ - if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) + if (info_ptr->text != 0 && + ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) { 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; - } + 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[i].key); + png_free(png_ptr, info_ptr->text); info_ptr->text = NULL; - info_ptr->num_text=0; + info_ptr->num_text = 0; } } #endif #ifdef PNG_tRNS_SUPPORTED /* Free any tRNS entry */ - if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) + if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) { + info_ptr->valid &= ~PNG_INFO_tRNS; png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; + info_ptr->num_trans = 0; } #endif #ifdef PNG_sCAL_SUPPORTED /* Free any sCAL entry */ - if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) + if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) { -#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 #ifdef PNG_pCAL_SUPPORTED /* Free any pCAL entry */ - if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) + if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) { 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++) - { + + for (i = 0; i < 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; } @@ -325,8 +521,8 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #endif #ifdef PNG_iCCP_SUPPORTED - /* Free any iCCP entry */ - if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) + /* Free any profile entry */ + if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->iccp_name); png_free(png_ptr, info_ptr->iccp_profile); @@ -338,72 +534,62 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_sPLT_SUPPORTED /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ - if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) + if (info_ptr->splt_palettes != 0 && + ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) { 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; - } + 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); + int i; - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; + for (i = 0; i < info_ptr->splt_palettes_num; i++) + { + png_free(png_ptr, info_ptr->splt_palettes[i].name); + png_free(png_ptr, info_ptr->splt_palettes[i].entries); } + + 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 -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->unknown_chunk.data) - { - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks != 0 && + ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) { 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; - } + 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); + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free(png_ptr, info_ptr->unknown_chunks[i].data); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; } } #endif #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ - if ((mask & PNG_FREE_HIST) & info_ptr->free_me) + if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->hist); info_ptr->hist = NULL; @@ -412,9 +598,9 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #endif /* Free any PLTE entry that was internally allocated */ - if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) + if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) { - png_zfree(png_ptr, info_ptr->palette); + png_free(png_ptr, info_ptr->palette); info_ptr->palette = NULL; info_ptr->valid &= ~PNG_INFO_PLTE; info_ptr->num_palette = 0; @@ -422,16 +608,14 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_INFO_IMAGE_SUPPORTED /* Free any image bits attached to the info structure */ - if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) + if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) { - if (info_ptr->row_pointers) + if (info_ptr->row_pointers != 0) { - int row; - for (row = 0; row < (int)info_ptr->height; row++) - { + png_uint_32 row; + for (row = 0; row < 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; } @@ -439,58 +623,36 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, } #endif - if (num == -1) - info_ptr->free_me &= ~mask; - else - info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); + if (num != -1) + mask &= ~PNG_FREE_MUL; + + info_ptr->free_me &= ~mask; } - -/* 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"); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_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, png_sizeof(png_info)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ +#endif /* READ || WRITE */ /* 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) +png_get_io_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); + return (png_ptr->io_ptr); } #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_STDIO_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED /* 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. + * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, 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_init_io(png_structrp png_ptr, png_FILE_p fp) { png_debug(1, "in png_init_io"); @@ -499,69 +661,122 @@ png_init_io(png_structp png_ptr, png_FILE_p fp) png_ptr->io_ptr = (png_voidp)fp; } -#endif +# endif -#ifdef PNG_TIME_RFC1123_SUPPORTED +# ifdef PNG_SAVE_INT_32_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. Note that, + * the following works correctly even if png_int_32 has more than 32 bits + * (compare the more complex code required on read for sign extension.) + */ +void PNGAPI +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 + +# ifdef 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) +int PNGAPI +png_convert_to_rfc1123_buffer(char out[29], png_const_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 == NULL) - return (NULL); - if (png_ptr->time_buffer == NULL) + if (out == NULL) + return 0; + + if (ptime->year > 9999 /* RFC1123 limitation */ || + ptime->month == 0 || ptime->month > 12 || + ptime->day == 0 || ptime->day > 31 || + ptime->hour > 23 || ptime->minute > 59 || + ptime->second > 60) + return 0; + { - png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* - png_sizeof(char))); + size_t pos = 0; + char number_buf[5]; /* enough for a four-digit year */ + +# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) +# define APPEND_NUMBER(format, value)\ + APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) +# define APPEND(ch) if (pos < 28) out[pos++] = (ch) + + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); + APPEND(' '); + APPEND_STRING(short_months[(ptime->month - 1)]); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); + APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ + +# undef APPEND +# undef APPEND_NUMBER +# undef APPEND_STRING } -#ifdef USE_FAR_KEYWORD - { - char near_time_buf[29]; - png_snprintf6(near_time_buf, 29, "%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*png_sizeof(char)); - } -#else - png_snprintf6(png_ptr->time_buffer, 29, "%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 - return ((png_charp)png_ptr->time_buffer); + return 1; } -#endif /* PNG_TIME_RFC1123_SUPPORTED */ -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -png_charp PNGAPI -png_get_copyright(png_structp png_ptr) +# if PNG_LIBPNG_VER < 10700 +/* To do: remove the following from libpng-1.7 */ +/* Original API that uses a private buffer in png_struct. + * Deprecated because it causes png_struct to carry a spurious temporary + * buffer (png_struct::time_buffer), better to have the caller pass this in. + */ +png_const_charp PNGAPI +png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) { - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ + if (png_ptr != NULL) + { + /* The only failure above if png_ptr != NULL is from an invalid ptime */ + if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) + png_warning(png_ptr, "Ignoring invalid time value"); + + else + return png_ptr->time_buffer; + } + + return NULL; +} +# endif /* LIBPNG_VER < 10700 */ +# endif /* TIME_RFC1123 */ + +#endif /* READ || WRITE */ + +png_const_charp PNGAPI +png_get_copyright(png_const_structrp png_ptr) +{ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ #ifdef PNG_STRING_COPYRIGHT - return PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT #else -#ifdef __STDC__ - return ((png_charp) PNG_STRING_NEWLINE \ - "libpng version 1.4.4 - September 23, 2010" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2010 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ +# ifdef __STDC__ + return PNG_STRING_NEWLINE \ + "libpng version 1.6.17 - March 26, 2015" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2015 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ - PNG_STRING_NEWLINE); -#else - return ((png_charp) "libpng version 1.4.4 - September 23, 2010\ - Copyright (c) 1998-2010 Glenn Randers-Pehrson\ + PNG_STRING_NEWLINE; +# else + return "libpng version 1.6.17 - March 26, 2015\ + Copyright (c) 1998-2015 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."); -#endif + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; +# endif #endif } @@ -573,209 +788,1687 @@ png_get_copyright(png_structp png_ptr) * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, * it is guaranteed that png.c uses the correct version of png.h. */ -png_charp PNGAPI -png_get_libpng_ver(png_structp png_ptr) +png_const_charp PNGAPI +png_get_libpng_ver(png_const_structrp png_ptr) { /* Version of *.c files used when building libpng */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); + return png_get_header_ver(png_ptr); } -png_charp PNGAPI -png_get_header_ver(png_structp png_ptr) +png_const_charp PNGAPI +png_get_header_ver(png_const_structrp png_ptr) { /* Version of *.h files used when building libpng */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return PNG_LIBPNG_VER_STRING; } -png_charp PNGAPI -png_get_header_version(png_structp png_ptr) +png_const_charp PNGAPI +png_get_header_version(png_const_structrp png_ptr) { /* Returns longer string containing both version and date */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ #ifdef __STDC__ - return ((png_charp) PNG_HEADER_VERSION_STRING -#ifndef PNG_READ_SUPPORTED + return PNG_HEADER_VERSION_STRING +# ifndef PNG_READ_SUPPORTED " (NO READ SUPPORT)" -#endif - PNG_STRING_NEWLINE); +# endif + PNG_STRING_NEWLINE; #else - return ((png_charp) PNG_HEADER_VERSION_STRING); + return PNG_HEADER_VERSION_STRING; #endif } -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -int PNGAPI -png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* NOTE: this routine is not used internally! */ +/* 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. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) { - /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + int num_palette; + int color_inc; 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; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + 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 & 0xff); + palette[i].green = (png_byte)(v & 0xff); + palette[i].blue = (png_byte)(v & 0xff); + } } #endif -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + png_const_bytep p, p_end; + + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) + return PNG_HANDLE_CHUNK_AS_DEFAULT; + + p_end = png_ptr->chunk_list; + p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ + + /* The code is the fifth byte after each four byte string. Historically this + * code was always searched from the end of the list, this is no longer + * necessary because the 'set' routine handles duplicate entries correcty. + */ + do /* num_chunk_list > 0, so at least one */ + { + p -= 5; + + if (memcmp(chunk_name, p, 4) == 0) + return p[4]; + } + while (p > p_end); + + /* This means that known chunks should be processed and unknown chunks should + * be handled according to the value of png_ptr->unknown_default; this can be + * confusing because, as a result, there are two levels of defaulting for + * unknown chunks. + */ + return PNG_HANDLE_CHUNK_AS_DEFAULT; +} + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +int /* PRIVATE */ +png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) +{ + png_byte chunk_string[5]; + + PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); + return png_handle_as_unknown(png_ptr, chunk_string); +} +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* SET_UNKNOWN_CHUNKS */ #ifdef PNG_READ_SUPPORTED /* This function, added to libpng-1.0.6g, is untested. */ int PNGAPI -png_reset_zstream(png_structp png_ptr) +png_reset_zstream(png_structrp png_ptr) { if (png_ptr == NULL) return Z_STREAM_ERROR; + + /* WARNING: this resets the window bits to the maximum! */ return (inflateReset(&png_ptr->zstream)); } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ /* 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) PNG_LIBPNG_VER); + return((png_uint_32)PNG_LIBPNG_VER); } - - #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_SIZE_T -/* Added at libpng version 1.2.6 */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); -png_size_t PNGAPI -png_convert_size(size_t size) +/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. + * If it doesn't 'ret' is used to set it to something appropriate, even in cases + * like Z_OK or Z_STREAM_END where the error code is apparently a success code. + */ +void /* PRIVATE */ +png_zstream_error(png_structrp png_ptr, int ret) { - if (size > (png_size_t)-1) - PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ - return ((png_size_t)size); + /* Translate 'ret' into an appropriate error string, priority is given to the + * one in zstream if set. This always returns a string, even in cases like + * Z_OK or Z_STREAM_END where the error code is a success code. + */ + if (png_ptr->zstream.msg == NULL) switch (ret) + { + default: + case Z_OK: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + break; + + case Z_STREAM_END: + /* Normal exit */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + break; + + case Z_NEED_DICT: + /* This means the deflate stream did not have a dictionary; this + * indicates a bogus PNG. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + break; + + case Z_ERRNO: + /* gz APIs only: should not happen */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + break; + + case Z_STREAM_ERROR: + /* internal libpng error */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + break; + + case Z_DATA_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + break; + + case Z_MEM_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + break; + + case Z_BUF_ERROR: + /* End of input or output; not a problem if the caller is doing + * incremental read or write. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + break; + + case Z_VERSION_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + break; + + case PNG_UNEXPECTED_ZLIB_RETURN: + /* Compile errors here mean that zlib now uses the value co-opted in + * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above + * and change pngpriv.h. Note that this message is "... return", + * whereas the default/Z_OK one is "... return code". + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + break; + } } -#endif /* PNG_SIZE_T */ + +/* png_convert_size: a PNGAPI but no longer in png.h, so deleted + * at libpng 1.5.5! + */ /* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_CHECK_cHRM_SUPPORTED +#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ +static int +png_colorspace_check_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA, int from) + /* This is called to check a new gamma value against an existing one. The + * routine returns false if the new gamma value should not be written. + * + * 'from' says where the new gamma value comes from: + * + * 0: the new gamma value is the libpng estimate for an ICC profile + * 1: the new gamma value comes from a gAMA chunk + * 2: the new gamma value comes from an sRGB chunk + */ +{ + png_fixed_point gtest; -/* - * Multiply two 32-bit numbers, V1 and V2, using 32-bit - * arithmetic, to produce a 64 bit result in the HI/LO words. - * - * A B - * x C D - * ------ - * AD || BD - * AC || CB || 0 - * - * where A and B are the high and low 16-bit words of V1, - * C and D are the 16-bit words of V2, AD is the product of - * A and D, and X || Y is (X << 16) + Y. -*/ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 || + png_gamma_significant(gtest) != 0)) + { + /* Either this is an sRGB image, in which case the calculated gamma + * approximation should match, or this is an image with a profile and the + * value libpng calculates for the gamma of the profile does not match the + * value recorded in the file. The former, sRGB, case is an error, the + * latter is just a warning. + */ + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) + { + png_chunk_report(png_ptr, "gamma value does not match sRGB", + PNG_CHUNK_ERROR); + /* Do not overwrite an sRGB value */ + return from == 2; + } + + else /* sRGB tag not involved */ + { + png_chunk_report(png_ptr, "gamma value does not match libpng estimate", + PNG_CHUNK_WARNING); + return from == 1; + } + } + + return 1; +} void /* PRIVATE */ -png_64bit_product (long v1, long v2, unsigned long *hi_product, - unsigned long *lo_product) +png_colorspace_set_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA) { - int a, b, c, d; - long lo, hi, x, y; + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is asymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truly ridiculous gamma values (and will produce + * displays that are all black or all white.) + * + * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk + * handling code, which only required the value to be >0. + */ + png_const_charp errmsg; - a = (v1 >> 16) & 0xffff; - b = v1 & 0xffff; - c = (v2 >> 16) & 0xffff; - d = v2 & 0xffff; + if (gAMA < 16 || gAMA > 625000000) + errmsg = "gamma value out of range"; - lo = b * d; /* BD */ - x = a * d + c * b; /* AD + CB */ - y = ((lo >> 16) & 0xffff) + x; +# ifdef PNG_READ_gAMA_SUPPORTED + /* Allow the application to set the gamma value more than once */ + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) + errmsg = "duplicate"; +# endif - lo = (lo & 0xffff) | ((y & 0xffff) << 16); - hi = (y >> 16) & 0xffff; + /* Do nothing if the colorspace is already invalid */ + else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return; - hi += a * c; /* AC */ + else + { + if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, + 1/*from gAMA*/) != 0) + { + /* Store this gamma value. */ + colorspace->gamma = gAMA; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); + } - *hi_product = (unsigned long)hi; - *lo_product = (unsigned long)lo; + /* At present if the check_gamma test fails the gamma of the colorspace is + * not updated however the colorspace is not invalidated. This + * corresponds to the case where the existing gamma comes from an sRGB + * chunk or profile. An error message has already been output. + */ + return; + } + + /* Error exit - errmsg has been set. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); +} + +void /* PRIVATE */ +png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + { + /* Everything is invalid */ + info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| + PNG_INFO_iCCP); + +# ifdef PNG_COLORSPACE_SUPPORTED + /* Clean up the iCCP profile now if it won't be used. */ + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); +# else + PNG_UNUSED(png_ptr) +# endif + } + + else + { +# ifdef PNG_COLORSPACE_SUPPORTED + /* Leave the INFO_iCCP flag set if the pngset.c code has already set + * it; this allows a PNG to contain a profile which matches sRGB and + * yet still have that profile retrievable by the application. + */ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0) + info_ptr->valid |= PNG_INFO_sRGB; + + else + info_ptr->valid &= ~PNG_INFO_sRGB; + + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + info_ptr->valid |= PNG_INFO_cHRM; + + else + info_ptr->valid &= ~PNG_INFO_cHRM; +# endif + + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0) + info_ptr->valid |= PNG_INFO_gAMA; + + else + info_ptr->valid &= ~PNG_INFO_gAMA; + } +} + +#ifdef PNG_READ_SUPPORTED +void /* PRIVATE */ +png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr == NULL) /* reduce code size; check here not in the caller */ + return; + + info_ptr->colorspace = png_ptr->colorspace; + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif +#endif /* GAMMA */ + +#ifdef PNG_COLORSPACE_SUPPORTED +/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for + * cHRM, as opposed to using chromaticities. These internal APIs return + * non-zero on a parameter error. The X, Y and Z values are required to be + * positive and less than 1.0. + */ +static int +png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) +{ + png_int_32 d, dwhite, whiteX, whiteY; + + d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; + if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0) + return 1; + dwhite = d; + whiteX = XYZ->red_X; + whiteY = XYZ->red_Y; + + d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; + if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0) + return 1; + dwhite += d; + whiteX += XYZ->green_X; + whiteY += XYZ->green_Y; + + d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; + if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0) + return 1; + dwhite += d; + whiteX += XYZ->blue_X; + whiteY += XYZ->blue_Y; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, + * thus: + */ + if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) + return 1; + if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) + return 1; + + return 0; +} + +static int +png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) +{ + png_fixed_point red_inverse, green_inverse, blue_scale; + png_fixed_point left, right, denominator; + + /* Check xy and, implicitly, z. Note that wide gamut color spaces typically + * have end points with 0 tristimulus values (these are impossible end + * points, but they are used to cover the possible colors.) + */ + if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; + if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; + if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; + if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; + if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1; + + /* The reverse calculation is more difficult because the original tristimulus + * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 + * derived values were recorded in the cHRM chunk; + * (red,green,blue,white)x(x,y). This loses one degree of freedom and + * therefore an arbitrary ninth value has to be introduced to undo the + * original transformations. + * + * Think of the original end-points as points in (X,Y,Z) space. The + * chromaticity values (c) have the property: + * + * C + * c = --------- + * X + Y + Z + * + * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the + * three chromaticity values (x,y,z) for each end-point obey the + * relationship: + * + * x + y + z = 1 + * + * This describes the plane in (X,Y,Z) space that intersects each axis at the + * value 1.0; call this the chromaticity plane. Thus the chromaticity + * calculation has scaled each end-point so that it is on the x+y+z=1 plane + * and chromaticity is the intersection of the vector from the origin to the + * (X,Y,Z) value with the chromaticity plane. + * + * To fully invert the chromaticity calculation we would need the three + * end-point scale factors, (red-scale, green-scale, blue-scale), but these + * were not recorded. Instead we calculated the reference white (X,Y,Z) and + * recorded the chromaticity of this. The reference white (X,Y,Z) would have + * given all three of the scale factors since: + * + * color-C = color-c * color-scale + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * But cHRM records only white-x and white-y, so we have lost the white scale + * factor: + * + * white-C = white-c*white-scale + * + * To handle this the inverse transformation makes an arbitrary assumption + * about white-scale: + * + * Assume: white-Y = 1.0 + * Hence: white-scale = 1/white-y + * Or: red-Y + green-Y + blue-Y = 1.0 + * + * Notice the last statement of the assumption gives an equation in three of + * the nine values we want to calculate. 8 more equations come from the + * above routine as summarised at the top above (the chromaticity + * calculation): + * + * Given: color-x = color-X / (color-X + color-Y + color-Z) + * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 + * + * This is 9 simultaneous equations in the 9 variables "color-C" and can be + * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix + * determinants, however this is not as bad as it seems because only 28 of + * the total of 90 terms in the various matrices are non-zero. Nevertheless + * Cramer's rule is notoriously numerically unstable because the determinant + * calculation involves the difference of large, but similar, numbers. It is + * difficult to be sure that the calculation is stable for real world values + * and it is certain that it becomes unstable where the end points are close + * together. + * + * So this code uses the perhaps slightly less optimal but more + * understandable and totally obvious approach of calculating color-scale. + * + * This algorithm depends on the precision in white-scale and that is + * (1/white-y), so we can immediately see that as white-y approaches 0 the + * accuracy inherent in the cHRM chunk drops off substantially. + * + * libpng arithmetic: a simple inversion of the above equations + * ------------------------------------------------------------ + * + * white_scale = 1/white-y + * white-X = white-x * white-scale + * white-Y = 1.0 + * white-Z = (1 - white-x - white-y) * white_scale + * + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * This gives us three equations in (red-scale,green-scale,blue-scale) where + * all the coefficients are now known: + * + * red-x*red-scale + green-x*green-scale + blue-x*blue-scale + * = white-x/white-y + * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 + * red-z*red-scale + green-z*green-scale + blue-z*blue-scale + * = (1 - white-x - white-y)/white-y + * + * In the last equation color-z is (1 - color-x - color-y) so we can add all + * three equations together to get an alternative third: + * + * red-scale + green-scale + blue-scale = 1/white-y = white-scale + * + * So now we have a Cramer's rule solution where the determinants are just + * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * multiplication of three coefficients so we can't guarantee to avoid + * overflow in the libpng fixed point representation. Using Cramer's rule in + * floating point is probably a good choice here, but it's not an option for + * fixed point. Instead proceed to simplify the first two equations by + * eliminating what is likely to be the largest value, blue-scale: + * + * blue-scale = white-scale - red-scale - green-scale + * + * Hence: + * + * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = + * (white-x - blue-x)*white-scale + * + * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = + * 1 - blue-y*white-scale + * + * And now we can trivially solve for (red-scale,green-scale): + * + * green-scale = + * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale + * ----------------------------------------------------------- + * green-x - blue-x + * + * red-scale = + * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale + * --------------------------------------------------------- + * red-y - blue-y + * + * Hence: + * + * red-scale = + * ( (green-x - blue-x) * (white-y - blue-y) - + * (green-y - blue-y) * (white-x - blue-x) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * green-scale = + * ( (red-y - blue-y) * (white-x - blue-x) - + * (red-x - blue-x) * (white-y - blue-y) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * Accuracy: + * The input values have 5 decimal digits of accuracy. The values are all in + * the range 0 < value < 1, so simple products are in the same range but may + * need up to 10 decimal digits to preserve the original precision and avoid + * underflow. Because we are using a 32-bit signed representation we cannot + * match this; the best is a little over 9 decimal digits, less than 10. + * + * The approach used here is to preserve the maximum precision within the + * signed representation. Because the red-scale calculation above uses the + * difference between two products of values that must be in the range -1..+1 + * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The + * factor is irrelevant in the calculation because it is applied to both + * numerator and denominator. + * + * Note that the values of the differences of the products of the + * chromaticities in the above equations tend to be small, for example for + * the sRGB chromaticities they are: + * + * red numerator: -0.04751 + * green numerator: -0.08788 + * denominator: -0.2241 (without white-y multiplication) + * + * The resultant Y coefficients from the chromaticities of some widely used + * color space definitions are (to 15 decimal places): + * + * sRGB + * 0.212639005871510 0.715168678767756 0.072192315360734 + * Kodak ProPhoto + * 0.288071128229293 0.711843217810102 0.000085653960605 + * Adobe RGB + * 0.297344975250536 0.627363566255466 0.075291458493998 + * Adobe Wide Gamut RGB + * 0.258728243040113 0.724682314948566 0.016589442011321 + */ + /* By the argument, above overflow should be impossible here. The return + * value of 2 indicates an internal error to the caller. + */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0) + return 2; + denominator = left - right; + + /* Now find the red numerator. */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 || + green_inverse <= xy->whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) + return 1; + + + /* And fill in the png_XYZ: */ + if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1) == 0) + return 1; + + return 0; /*success*/ +} + +static int +png_XYZ_normalize(png_XYZ *XYZ) +{ + png_int_32 Y; + + if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || + XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || + XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + return 1; + + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + Y = XYZ->red_Y; + if (0x7fffffff - Y < XYZ->green_X) + return 1; + Y += XYZ->green_Y; + if (0x7fffffff - Y < XYZ->blue_X) + return 1; + Y += XYZ->blue_Y; + + if (Y != PNG_FP_1) + { + if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0) + return 1; + } + + return 0; +} + +static int +png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) +{ + /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ + if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || + PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || + PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || + PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || + PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || + PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || + PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || + PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)) + return 0; + return 1; +} + +/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM + * chunk chromaticities. Earlier checks used to simply look for the overflow + * condition (where the determinant of the matrix to solve for XYZ ends up zero + * because the chromaticity values are not all distinct.) Despite this it is + * theoretically possible to produce chromaticities that are apparently valid + * but that rapidly degrade to invalid, potentially crashing, sets because of + * arithmetic inaccuracies when calculations are performed on them. The new + * check is to round-trip xy -> XYZ -> xy and then check that the result is + * within a small percentage of the original. + */ +static int +png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) +{ + int result; + png_xy xy_test; + + /* As a side-effect this routine also returns the XYZ endpoints. */ + result = png_XYZ_from_xy(XYZ, xy); + if (result != 0) + return result; + + result = png_xy_from_XYZ(&xy_test, XYZ); + if (result != 0) + return result; + + if (png_colorspace_endpoints_match(xy, &xy_test, + 5/*actually, the math is pretty accurate*/) != 0) + return 0; + + /* Too much slip */ + return 1; +} + +/* This is the check going the other way. The XYZ is modified to normalize it + * (another side-effect) and the xy chromaticities are returned. + */ +static int +png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) +{ + int result; + png_XYZ XYZtemp; + + result = png_XYZ_normalize(XYZ); + if (result != 0) + return result; + + result = png_xy_from_XYZ(xy, XYZ); + if (result != 0) + return result; + + XYZtemp = *XYZ; + return png_colorspace_check_xy(&XYZtemp, xy); +} + +/* Used to check for an endpoint match against sRGB */ +static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ +{ + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 +}; + +static int +png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, + int preferred) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + /* The consistency check is performed on the chromaticities; this factors out + * variations because of the normalization (or not) of the end point Y + * values. + */ + if (preferred < 2 && + (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* The end points must be reasonably close to any we already have. The + * following allows an error of up to +/-.001 + */ + if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, + 100) == 0) + { + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "inconsistent chromaticities"); + return 0; /* failed */ + } + + /* Only overwrite with preferred values */ + if (preferred == 0) + return 1; /* ok, but no change */ + } + + colorspace->end_points_xy = *xy; + colorspace->end_points_XYZ = *XYZ; + colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; + + /* The end points are normally quoted to two decimal digits, so allow +/-0.01 + * on this test. + */ + if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0) + colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; + + else + colorspace->flags &= PNG_COLORSPACE_CANCEL( + PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + return 2; /* ok and changed */ } int /* PRIVATE */ -png_check_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) +png_colorspace_set_chromaticities(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, int preferred) { - int ret = 1; - unsigned long xy_hi,xy_lo,yx_hi,yx_lo; + /* We must check the end points to ensure they are reasonable - in the past + * color management systems have crashed as a result of getting bogus + * colorant values, while this isn't the fault of libpng it is the + * responsibility of libpng because PNG carries the bomb and libpng is in a + * position to protect against it. + */ + png_XYZ XYZ; - png_debug(1, "in function png_check_cHRM_fixed"); + switch (png_colorspace_check_xy(&XYZ, xy)) + { + case 0: /* success */ + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, + preferred); - if (png_ptr == NULL) + case 1: + /* We can't invert the chromaticities so we can't produce value XYZ + * values. Likely as not a color management system will fail too. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid chromaticities"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +int /* PRIVATE */ +png_colorspace_set_endpoints(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) +{ + png_XYZ XYZ = *XYZ_in; + png_xy xy; + + switch (png_colorspace_check_XYZ(&xy, &XYZ)) + { + case 0: + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, + preferred); + + case 1: + /* End points are invalid. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid end points"); + break; + + default: + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) +/* Error message generation */ +static char +png_icc_tag_char(png_uint_32 byte) +{ + byte &= 0xff; + if (byte >= 32 && byte <= 126) + return (char)byte; + else + return '?'; +} + +static void +png_icc_tag_name(char *name, png_uint_32 tag) +{ + name[0] = '\''; + name[1] = png_icc_tag_char(tag >> 24); + name[2] = png_icc_tag_char(tag >> 16); + name[3] = png_icc_tag_char(tag >> 8); + name[4] = png_icc_tag_char(tag ); + name[5] = '\''; +} + +static int +is_ICC_signature_char(png_alloc_size_t it) +{ + return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || + (it >= 97 && it <= 122); +} + +static int +is_ICC_signature(png_alloc_size_t it) +{ + return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && + is_ICC_signature_char((it >> 16) & 0xff) && + is_ICC_signature_char((it >> 8) & 0xff) && + is_ICC_signature_char(it & 0xff); +} + +static int +png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_alloc_size_t value, png_const_charp reason) +{ + size_t pos; + char message[196]; /* see below for calculation */ + + if (colorspace != NULL) + colorspace->flags |= PNG_COLORSPACE_INVALID; + + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ + pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ + pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ + if (is_ICC_signature(value) != 0) + { + /* So 'value' is at most 4 bytes and the following cast is safe */ + png_icc_tag_name(message+pos, (png_uint_32)value); + pos += 6; /* total +8; less than the else clause */ + message[pos++] = ':'; + message[pos++] = ' '; + } +# ifdef PNG_WARNINGS_SUPPORTED + else + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ + + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + } +# endif + /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ + pos = png_safecat(message, (sizeof message), pos, reason); + PNG_UNUSED(pos) + + /* This is recoverable, but make it unconditionally an app_error on write to + * avoid writing invalid ICC profiles into PNG files (i.e., we handle them + * on read, with a warning, but on write unless the app turns off + * application errors the PNG won't be written.) + */ + png_chunk_report(png_ptr, message, + (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); + + return 0; +} +#endif /* sRGB || iCCP */ + +#ifdef PNG_sRGB_SUPPORTED +int /* PRIVATE */ +png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, + int intent) +{ + /* sRGB sets known gamma, end points and (from the chunk) intent. */ + /* IMPORTANT: these are not necessarily the values found in an ICC profile + * because ICC profiles store values adapted to a D50 environment; it is + * expected that the ICC profile mediaWhitePointTag will be D50; see the + * checks and code elsewhere to understand this better. + * + * These XYZ values, which are accurate to 5dp, produce rgb to gray + * coefficients of (6968,23435,2366), which are reduced (because they add up + * to 32769 not 32768) to (6968,23434,2366). These are the values that + * libpng has traditionally used (and are the best values given the 15bit + * algorithm used by the rgb to gray code.) + */ + static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ + { + /* color X Y Z */ + /* red */ 41239, 21264, 1933, + /* green */ 35758, 71517, 11919, + /* blue */ 18048, 7219, 95053 + }; + + /* Do nothing if the colorspace is already invalidated. */ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) return 0; - if (white_x < 0 || white_y <= 0 || - red_x < 0 || red_y < 0 || - green_x < 0 || green_y < 0 || - blue_x < 0 || blue_y < 0) + /* Check the intent, then check for existing settings. It is valid for the + * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must + * be consistent with the correct values. If, however, this function is + * called below because an iCCP chunk matches sRGB then it is quite + * conceivable that an older app recorded incorrect gAMA and cHRM because of + * an incorrect calculation based on the values in the profile - this does + * *not* invalidate the profile (though it still produces an error, which can + * be ignored.) + */ + if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "invalid sRGB rendering intent"); + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && + colorspace->rendering_intent != intent) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "inconsistent rendering intents"); + + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) { - png_warning(png_ptr, - "Ignoring attempt to set negative chromaticity value"); - ret = 0; - } - if (white_x > (png_fixed_point) PNG_UINT_31_MAX || - white_y > (png_fixed_point) PNG_UINT_31_MAX || - red_x > (png_fixed_point) PNG_UINT_31_MAX || - red_y > (png_fixed_point) PNG_UINT_31_MAX || - green_x > (png_fixed_point) PNG_UINT_31_MAX || - green_y > (png_fixed_point) PNG_UINT_31_MAX || - blue_x > (png_fixed_point) PNG_UINT_31_MAX || - blue_y > (png_fixed_point) PNG_UINT_31_MAX ) - { - png_warning(png_ptr, - "Ignoring attempt to set chromaticity value exceeding 21474.83"); - ret = 0; - } - if (white_x > 100000L - white_y) - { - png_warning(png_ptr, "Invalid cHRM white point"); - ret = 0; - } - if (red_x > 100000L - red_y) - { - png_warning(png_ptr, "Invalid cHRM red point"); - ret = 0; - } - if (green_x > 100000L - green_y) - { - png_warning(png_ptr, "Invalid cHRM green point"); - ret = 0; - } - if (blue_x > 100000L - blue_y) - { - png_warning(png_ptr, "Invalid cHRM blue point"); - ret = 0; + png_benign_error(png_ptr, "duplicate sRGB information ignored"); + return 0; } - png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); - png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); + /* If the standard sRGB cHRM chunk does not match the one from the PNG file + * warn but overwrite the value with the correct one. + */ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && + !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, + 100)) + png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", + PNG_CHUNK_ERROR); - if (xy_hi == yx_hi && xy_lo == yx_lo) - { - png_warning(png_ptr, - "Ignoring attempt to set cHRM RGB triangle with zero area"); - ret = 0; - } + /* This check is just done for the error reporting - the routine always + * returns true when the 'from' argument corresponds to sRGB (2). + */ + (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, + 2/*from sRGB*/); - return ret; + /* intent: bugs in GCC force 'int' to be used as the parameter type. */ + colorspace->rendering_intent = (png_uint_16)intent; + colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; + + /* endpoints */ + colorspace->end_points_xy = sRGB_xy; + colorspace->end_points_XYZ = sRGB_XYZ; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + /* gamma */ + colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; + colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Finally record that we have an sRGB profile */ + colorspace->flags |= + (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); + + return 1; /* set */ } -#endif /* PNG_CHECK_cHRM_SUPPORTED */ -#endif /* PNG_cHRM_SUPPORTED */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value + * is XYZ(0.9642,1.0,0.8249), which scales to: + * + * (63189.8112, 65536, 54060.6464) + */ +static const png_byte D50_nCIEXYZ[12] = + { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; + +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length) +{ + if (profile_length < 132) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "too short"); + + return 1; +} + +int /* PRIVATE */ +png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile/* first 132 bytes only */, int color_type) +{ + png_uint_32 temp; + + /* Length check; this cannot be ignored in this code because profile_length + * is used later to check the tag table, so even if the profile seems over + * long profile_length from the caller must be correct. The caller can fix + * this up on read or write by just passing in the profile header length. + */ + temp = png_get_uint_32(profile); + if (temp != profile_length) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "length does not match profile"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_length & 3)) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "invalid length"); + + temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ + if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ + profile_length < 132+12*temp) /* truncated tag table */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "tag count too large"); + + /* The 'intent' must be valid or we can't store it, ICC limits the intent to + * 16 bits. + */ + temp = png_get_uint_32(profile+64); + if (temp >= 0xffff) /* The ICC limit */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid rendering intent"); + + /* This is just a warning because the profile may be valid in future + * versions. + */ + if (temp >= PNG_sRGB_INTENT_LAST) + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "intent outside defined range"); + + /* At this point the tag table can't be checked because it hasn't necessarily + * been loaded; however, various header fields can be checked. These checks + * are for values permitted by the PNG spec in an ICC profile; the PNG spec + * restricts the profiles that can be passed in an iCCP chunk (they must be + * appropriate to processing PNG data!) + */ + + /* Data checks (could be skipped). These checks must be independent of the + * version number; however, the version number doesn't accomodate changes in + * the header fields (just the known tags and the interpretation of the + * data.) + */ + temp = png_get_uint_32(profile+36); /* signature 'ascp' */ + if (temp != 0x61637370) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid signature"); + + /* Currently the PCS illuminant/adopted white point (the computational + * white point) are required to be D50, + * however the profile contains a record of the illuminant so perhaps ICC + * expects to be able to change this in the future (despite the rationale in + * the introduction for using a fixed PCS adopted white.) Consequently the + * following is just a warning. + */ + if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) + (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, + "PCS illuminant is not D50"); + + /* The PNG spec requires this: + * "If the iCCP chunk is present, the image samples conform to the colour + * space represented by the embedded ICC profile as defined by the + * International Color Consortium [ICC]. The colour space of the ICC profile + * shall be an RGB colour space for colour images (PNG colour types 2, 3, and + * 6), or a greyscale colour space for greyscale images (PNG colour types 0 + * and 4)." + * + * This checking code ensures the embedded profile (on either read or write) + * conforms to the specification requirements. Notice that an ICC 'gray' + * color-space profile contains the information to transform the monochrome + * data to XYZ or L*a*b (according to which PCS the profile uses) and this + * should be used in preference to the standard libpng K channel replication + * into R, G and B channels. + * + * Previously it was suggested that an RGB profile on grayscale data could be + * handled. However it it is clear that using an RGB profile in this context + * must be an error - there is no specification of what it means. Thus it is + * almost certainly more correct to ignore the profile. + */ + temp = png_get_uint_32(profile+16); /* data colour space field */ + switch (temp) + { + case 0x52474220: /* 'RGB ' */ + if ((color_type & PNG_COLOR_MASK_COLOR) == 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "RGB color space not permitted on grayscale PNG"); + break; + + case 0x47524159: /* 'GRAY' */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "Gray color space not permitted on RGB PNG"); + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid ICC profile color space"); + } + + /* It is up to the application to check that the profile class matches the + * application requirements; the spec provides no guidance, but it's pretty + * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer + * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these + * cases. Issue an error for device link or abstract profiles - these don't + * contain the records necessary to transform the color-space to anything + * other than the target device (and not even that for an abstract profile). + * Profiles of these classes may not be embedded in images. + */ + temp = png_get_uint_32(profile+12); /* profile/device class */ + switch (temp) + { + case 0x73636E72: /* 'scnr' */ + case 0x6D6E7472: /* 'mntr' */ + case 0x70727472: /* 'prtr' */ + case 0x73706163: /* 'spac' */ + /* All supported */ + break; + + case 0x61627374: /* 'abst' */ + /* May not be embedded in an image */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid embedded Abstract ICC profile"); + + case 0x6C696E6B: /* 'link' */ + /* DeviceLink profiles cannot be interpreted in a non-device specific + * fashion, if an app uses the AToB0Tag in the profile the results are + * undefined unless the result is sent to the intended device, + * therefore a DeviceLink profile should not be found embedded in a + * PNG. + */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected DeviceLink ICC profile class"); + + case 0x6E6D636C: /* 'nmcl' */ + /* A NamedColor profile is also device specific, however it doesn't + * contain an AToB0 tag that is open to misinterpretation. Almost + * certainly it will fail the tests below. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unexpected NamedColor ICC profile class"); + break; + + default: + /* To allow for future enhancements to the profile accept unrecognized + * profile classes with a warning, these then hit the test below on the + * tag content to ensure they are backward compatible with one of the + * understood profiles. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unrecognized ICC profile class"); + break; + } + + /* For any profile other than a device link one the PCS must be encoded + * either in XYZ or Lab. + */ + temp = png_get_uint_32(profile+20); + switch (temp) + { + case 0x58595A20: /* 'XYZ ' */ + case 0x4C616220: /* 'Lab ' */ + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected ICC PCS encoding"); + } + + return 1; +} + +int /* PRIVATE */ +png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */) +{ + png_uint_32 tag_count = png_get_uint_32(profile+128); + png_uint_32 itag; + png_const_bytep tag = profile+132; /* The first tag */ + + /* First scan all the tags in the table and add bits to the icc_info value + * (temporarily in 'tags'). + */ + for (itag=0; itag < tag_count; ++itag, tag += 12) + { + png_uint_32 tag_id = png_get_uint_32(tag+0); + png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ + png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ + + /* The ICC specification does not exclude zero length tags, therefore the + * start might actually be anywhere if there is no data, but this would be + * a clear abuse of the intent of the standard so the start is checked for + * being in range. All defined tag types have an 8 byte header - a 4 byte + * type signature then 0. + */ + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } + + /* This is a hard error; potentially it can cause read outside the + * profile. + */ + if (tag_start > profile_length || tag_length > profile_length - tag_start) + return png_icc_profile_error(png_ptr, colorspace, name, tag_id, + "ICC profile tag outside profile"); + } + + return 1; /* success, maybe with warnings */ +} + +#ifdef PNG_sRGB_SUPPORTED +#if PNG_sRGB_PROFILE_CHECKS >= 0 +/* Information about the known ICC sRGB profiles */ +static const struct +{ + png_uint_32 adler, crc, length; + png_uint_32 md5[4]; + png_byte have_md5; + png_byte is_broken; + png_uint_16 intent; + +# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) +# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ + { adler, crc, length, md5, broke, intent }, + +} png_sRGB_checks[] = +{ + /* This data comes from contrib/tools/checksum-icc run on downloads of + * all four ICC sRGB profiles from www.color.org. + */ + /* adler32, crc32, MD5[4], intent, date, length, file-name */ + PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, + PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, + "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") + + /* ICC sRGB v2 perceptual no black-compensation: */ + PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, + PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, + "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") + + PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, + PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, + "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") + + /* ICC sRGB v4 perceptual */ + PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, + PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, + "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") + + /* The following profiles have no known MD5 checksum. If there is a match + * on the (empty) MD5 the other fields are used to attempt a match and + * a warning is produced. The first two of these profiles have a 'cprt' tag + * which suggests that they were also made by Hewlett Packard. + */ + PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, + "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") + + /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not + * match the D50 PCS illuminant in the header (it is in fact the D65 values, + * so the white point is recorded as the un-adapted value.) The profiles + * below only differ in one byte - the intent - and are basically the same as + * the previous profile except for the mediaWhitePointTag error and a missing + * chromaticAdaptationTag. + */ + PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") + + PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") +}; + +static int +png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, + png_const_bytep profile, uLong adler) +{ + /* The quick check is to verify just the MD5 signature and trust the + * rest of the data. Because the profile has already been verified for + * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' + * field too, so if the profile has been edited with an intent not defined + * by sRGB (but maybe defined by a later ICC specification) the read of + * the profile will fail at that point. + */ + + png_uint_32 length = 0; + png_uint_32 intent = 0x10000; /* invalid */ +#if PNG_sRGB_PROFILE_CHECKS > 1 + uLong crc = 0; /* the value for 0 length data */ +#endif + unsigned int i; + +#ifdef PNG_SET_OPTION_SUPPORTED + /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ + if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) == + PNG_OPTION_ON) + return 0; +#endif + + for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) + { + if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && + png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && + png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && + png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) + { + /* This may be one of the old HP profiles without an MD5, in that + * case we can only use the length and Adler32 (note that these + * are not used by default if there is an MD5!) + */ +# if PNG_sRGB_PROFILE_CHECKS == 0 + if (png_sRGB_checks[i].have_md5 != 0) + return 1+png_sRGB_checks[i].is_broken; +# endif + + /* Profile is unsigned or more checks have been configured in. */ + if (length == 0) + { + length = png_get_uint_32(profile); + intent = png_get_uint_32(profile+64); + } + + /* Length *and* intent must match */ + if (length == png_sRGB_checks[i].length && + intent == png_sRGB_checks[i].intent) + { + /* Now calculate the adler32 if not done already. */ + if (adler == 0) + { + adler = adler32(0, NULL, 0); + adler = adler32(adler, profile, length); + } + + if (adler == png_sRGB_checks[i].adler) + { + /* These basic checks suggest that the data has not been + * modified, but if the check level is more than 1 perform + * our own crc32 checksum on the data. + */ +# if PNG_sRGB_PROFILE_CHECKS > 1 + if (crc == 0) + { + crc = crc32(0, NULL, 0); + crc = crc32(crc, profile, length); + } + + /* So this check must pass for the 'return' below to happen. + */ + if (crc == png_sRGB_checks[i].crc) +# endif + { + if (png_sRGB_checks[i].is_broken != 0) + { + /* These profiles are known to have bad data that may cause + * problems if they are used, therefore attempt to + * discourage their use, skip the 'have_md5' warning below, + * which is made irrelevant by this error. + */ + png_chunk_report(png_ptr, "known incorrect sRGB profile", + PNG_CHUNK_ERROR); + } + + /* Warn that this being done; this isn't even an error since + * the profile is perfectly valid, but it would be nice if + * people used the up-to-date ones. + */ + else if (png_sRGB_checks[i].have_md5 == 0) + { + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", + PNG_CHUNK_WARNING); + } + + return 1+png_sRGB_checks[i].is_broken; + } + } + +# if PNG_sRGB_PROFILE_CHECKS > 0 + /* The signature matched, but the profile had been changed in some + * way. This probably indicates a data error or uninformed hacking. + * Fall through to "no match". + */ + png_chunk_report(png_ptr, + "Not recognizing known sRGB profile that has been edited", + PNG_CHUNK_WARNING); + break; +# endif + } + } + } + + return 0; /* no match */ +} +#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */ void /* PRIVATE */ -png_check_IHDR(png_structp png_ptr, +png_icc_set_sRGB(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_bytep profile, uLong adler) +{ + /* Is this profile one of the known ICC sRGB profiles? If it is, just set + * the sRGB information. + */ +#if PNG_sRGB_PROFILE_CHECKS >= 0 + if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0) +#endif + (void)png_colorspace_set_sRGB(png_ptr, colorspace, + (int)/*already checked*/png_get_uint_32(profile+64)); +} +#endif /* sRGB */ + +int /* PRIVATE */ +png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, + int color_type) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + if (png_icc_check_length(png_ptr, colorspace, name, profile_length) != 0 && + png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, + color_type) != 0 && + png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, + profile) != 0) + { +# ifdef PNG_sRGB_SUPPORTED + /* If no sRGB support, don't try storing sRGB information */ + png_icc_set_sRGB(png_ptr, colorspace, profile, 0); +# endif + return 1; + } + + /* Failure case */ + return 0; +} +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void /* PRIVATE */ +png_colorspace_set_rgb_coefficients(png_structrp png_ptr) +{ + /* Set the rgb_to_gray coefficients from the colorspace. */ + if (png_ptr->rgb_to_gray_coefficients_set == 0 && + (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* png_set_background has not been called, get the coefficients from the Y + * values of the colorspace colorants. + */ + png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; + png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; + png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c + */ + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); + } +} +#endif /* READ_RGB_TO_GRAY */ + +#endif /* COLORSPACE */ + +#ifdef __GNUC__ +/* This exists solely to work round a warning from GNU C. */ +static int /* PRIVATE */ +png_gt(size_t a, size_t b) +{ + return a > b; +} +#else +# define png_gt(a,b) ((a) > (b)) +#endif + +void /* PRIVATE */ +png_check_IHDR(png_const_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) @@ -789,14 +2482,36 @@ png_check_IHDR(png_structp png_ptr, error = 1; } - if (height == 0) + if (width > PNG_UINT_31_MAX) { - png_warning(png_ptr, "Image height is zero in IHDR"); + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + if (png_gt(((width + 7) & (~7)), + ((PNG_SIZE_MAX + - 48 /* big_row_buf hack */ + - 1) /* filter byte */ + / 8) /* 8-byte RGBA pixels */ + - 1)) /* extra max_pixel_depth pad */ + { + /* The size of the row must be within the limits of this architecture. + * Because the read code can perform arbitrary transformations the + * maximum size is checked here. Because the code in png_read_start_row + * adds extra space "for safety's sake" in several places a conservative + * limit is used here. + * + * NOTE: it would be far better to check the size that is actually used, + * but the effect in the real world is minor and the changes are more + * extensive, therefore much more dangerous and much more difficult to + * write in a way that avoids compiler warnings. + */ + png_warning(png_ptr, "Image width is too large for this architecture"); error = 1; } #ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX) + if (width > png_ptr->user_width_max) #else if (width > PNG_USER_WIDTH_MAX) #endif @@ -805,8 +2520,20 @@ png_check_IHDR(png_structp png_ptr, error = 1; } + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + + if (height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + #ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX) + if (height > png_ptr->user_height_max) #else if (height > PNG_USER_HEIGHT_MAX) #endif @@ -815,26 +2542,6 @@ png_check_IHDR(png_structp png_ptr, error = 1; } - if (width > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image width in IHDR"); - error = 1; - } - - if ( height > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image height in IHDR"); - error = 1; - } - - if ( width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 64 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - png_warning(png_ptr, "Width is too large for libpng to process pixels"); - /* Check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8 && bit_depth != 16) @@ -881,23 +2588,23 @@ png_check_IHDR(png_structp png_ptr, * 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) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && + png_ptr->mng_features_permitted != 0) png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); 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))) + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (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_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } - if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) { png_warning(png_ptr, "Invalid filter method in IHDR"); error = 1; @@ -915,4 +2622,1869 @@ png_check_IHDR(png_structp png_ptr, if (error == 1) png_error(png_ptr, "Invalid IHDR data"); } -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* ASCII to fp functions */ +/* Check an ASCII formated floating point value, see the more detailed + * comments in pngpriv.h + */ +/* The following is used internally to preserve the sticky flags */ +#define png_fp_add(state, flags) ((state) |= (flags)) +#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) + +int /* PRIVATE */ +png_check_fp_number(png_const_charp string, png_size_t size, int *statep, + png_size_tp whereami) +{ + int state = *statep; + png_size_t i = *whereami; + + while (i < size) + { + int type; + /* First find the type of the next character */ + switch (string[i]) + { + case 43: type = PNG_FP_SAW_SIGN; break; + case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; + case 46: type = PNG_FP_SAW_DOT; break; + case 48: type = PNG_FP_SAW_DIGIT; break; + case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: + case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; + case 69: + case 101: type = PNG_FP_SAW_E; break; + default: goto PNG_FP_End; + } + + /* Now deal with this type according to the current + * state, the type is arranged to not overlap the + * bits of the PNG_FP_STATE. + */ + switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) + { + case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, type); + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DOT: + /* Ok as trailer, ok as lead of fraction. */ + if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ + goto PNG_FP_End; + + else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ + png_fp_add(state, type); + + else + png_fp_set(state, PNG_FP_FRACTION | type); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: + if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ + png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); + + png_fp_add(state, type | PNG_FP_WAS_VALID); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_E: + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: + goto PNG_FP_End; ** no sign in fraction */ + + /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: + goto PNG_FP_End; ** Because SAW_DOT is always set */ + + case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: + png_fp_add(state, type | PNG_FP_WAS_VALID); + break; + + case PNG_FP_FRACTION + PNG_FP_SAW_E: + /* This is correct because the trailing '.' on an + * integer is handled above - so we can only get here + * with the sequence ".E" (with no preceding digits). + */ + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, PNG_FP_SAW_SIGN); + + break; + + /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: + goto PNG_FP_End; */ + + case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: + png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); + + break; + + /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: + goto PNG_FP_End; */ + + default: goto PNG_FP_End; /* I.e. break 2 */ + } + + /* The character seems ok, continue. */ + ++i; + } + +PNG_FP_End: + /* Here at the end, update the state and return the correct + * return code. + */ + *statep = state; + *whereami = i; + + return (state & PNG_FP_SAW_DIGIT) != 0; +} + + +/* The same but for a complete string. */ +int +png_check_fp_string(png_const_charp string, png_size_t size) +{ + int state=0; + png_size_t char_index=0; + + if (png_check_fp_number(string, size, &state, &char_index) != 0 && + (char_index == size || string[char_index] == 0)) + return state /* must be non-zero - see above */; + + return 0; /* i.e. fail */ +} +#endif /* pCAL || sCAL */ + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FLOATING_POINT_SUPPORTED +/* Utility used below - a simple accurate power of ten from an integral + * exponent. + */ +static double +png_pow10(int power) +{ + int recip = 0; + double d = 1; + + /* Handle negative exponent with a reciprocal at the end because + * 10 is exact whereas .1 is inexact in base 2 + */ + if (power < 0) + { + if (power < DBL_MIN_10_EXP) return 0; + recip = 1, power = -power; + } + + if (power > 0) + { + /* Decompose power bitwise. */ + double mult = 10; + do + { + if (power & 1) d *= mult; + mult *= mult; + power >>= 1; + } + while (power > 0); + + if (recip != 0) d = 1/d; + } + /* else power is 0 and d is 1 */ + + return d; +} + +/* Function to format a floating point value in ASCII with a given + * precision. + */ +void /* PRIVATE */ +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, + double fp, unsigned int precision) +{ + /* We use standard functions from math.h, but not printf because + * that would require stdio. The caller must supply a buffer of + * sufficient size or we will png_error. The tests on size and + * the space in ascii[] consumed are indicated below. + */ + if (precision < 1) + precision = DBL_DIG; + + /* Enforce the limit of the implementation precision too. */ + if (precision > DBL_DIG+1) + precision = DBL_DIG+1; + + /* Basic sanity checks */ + if (size >= precision+5) /* See the requirements below. */ + { + if (fp < 0) + { + fp = -fp; + *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ + --size; + } + + if (fp >= DBL_MIN && fp <= DBL_MAX) + { + int exp_b10; /* A base 10 exponent */ + double base; /* 10^exp_b10 */ + + /* First extract a base 10 exponent of the number, + * the calculation below rounds down when converting + * from base 2 to base 10 (multiply by log10(2) - + * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to + * be increased. Note that the arithmetic shift + * performs a floor() unlike C arithmetic - using a + * C multiply would break the following for negative + * exponents. + */ + (void)frexp(fp, &exp_b10); /* exponent to base 2 */ + + exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ + + /* Avoid underflow here. */ + base = png_pow10(exp_b10); /* May underflow */ + + while (base < DBL_MIN || base < fp) + { + /* And this may overflow. */ + double test = png_pow10(exp_b10+1); + + if (test <= DBL_MAX) + ++exp_b10, base = test; + + else + break; + } + + /* Normalize fp and correct exp_b10, after this fp is in the + * range [.1,1) and exp_b10 is both the exponent and the digit + * *before* which the decimal point should be inserted + * (starting with 0 for the first digit). Note that this + * works even if 10^exp_b10 is out of range because of the + * test on DBL_MAX above. + */ + fp /= base; + while (fp >= 1) fp /= 10, ++exp_b10; + + /* Because of the code above fp may, at this point, be + * less than .1, this is ok because the code below can + * handle the leading zeros this generates, so no attempt + * is made to correct that here. + */ + + { + int czero, clead, cdigits; + char exponent[10]; + + /* Allow up to two leading zeros - this will not lengthen + * the number compared to using E-n. + */ + if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ + { + czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */ + exp_b10 = 0; /* Dot added below before first output. */ + } + else + czero = 0; /* No zeros to add */ + + /* Generate the digit list, stripping trailing zeros and + * inserting a '.' before a digit if the exponent is 0. + */ + clead = czero; /* Count of leading zeros */ + cdigits = 0; /* Count of digits in list. */ + + do + { + double d; + + fp *= 10; + /* Use modf here, not floor and subtract, so that + * the separation is done in one step. At the end + * of the loop don't break the number into parts so + * that the final digit is rounded. + */ + if (cdigits+czero-clead+1 < (int)precision) + fp = modf(fp, &d); + + else + { + d = floor(fp + .5); + + if (d > 9) + { + /* Rounding up to 10, handle that here. */ + if (czero > 0) + { + --czero, d = 1; + if (cdigits == 0) --clead; + } + else + { + while (cdigits > 0 && d > 9) + { + int ch = *--ascii; + + if (exp_b10 != (-1)) + ++exp_b10; + + else if (ch == 46) + { + ch = *--ascii, ++size; + /* Advance exp_b10 to '1', so that the + * decimal point happens after the + * previous digit. + */ + exp_b10 = 1; + } + + --cdigits; + d = ch - 47; /* I.e. 1+(ch-48) */ + } + + /* Did we reach the beginning? If so adjust the + * exponent but take into account the leading + * decimal point. + */ + if (d > 9) /* cdigits == 0 */ + { + if (exp_b10 == (-1)) + { + /* Leading decimal point (plus zeros?), if + * we lose the decimal point here it must + * be reentered below. + */ + int ch = *--ascii; + + if (ch == 46) + ++size, exp_b10 = 1; + + /* Else lost a leading zero, so 'exp_b10' is + * still ok at (-1) + */ + } + else + ++exp_b10; + + /* In all cases we output a '1' */ + d = 1; + } + } + } + fp = 0; /* Guarantees termination below. */ + } + + if (d == 0) + { + ++czero; + if (cdigits == 0) ++clead; + } + else + { + /* Included embedded zeros in the digit count. */ + cdigits += czero - clead; + clead = 0; + + while (czero > 0) + { + /* exp_b10 == (-1) means we just output the decimal + * place - after the DP don't adjust 'exp_b10' any + * more! + */ + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) *ascii++ = 46, --size; + /* PLUS 1: TOTAL 4 */ + --exp_b10; + } + *ascii++ = 48, --czero; + } + + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) + *ascii++ = 46, --size; /* counted above */ + + --exp_b10; + } + *ascii++ = (char)(48 + (int)d), ++cdigits; + } + } + while (cdigits+czero-clead < (int)precision && fp > DBL_MIN); + + /* The total output count (max) is now 4+precision */ + + /* Check for an exponent, if we don't need one we are + * done and just need to terminate the string. At + * this point exp_b10==(-1) is effectively if flag - it got + * to '-1' because of the decrement after outputting + * the decimal point above (the exponent required is + * *not* -1!) + */ + if (exp_b10 >= (-1) && exp_b10 <= 2) + { + /* The following only happens if we didn't output the + * leading zeros above for negative exponent, so this + * doesn't add to the digit requirement. Note that the + * two zeros here can only be output if the two leading + * zeros were *not* output, so this doesn't increase + * the output count. + */ + while (--exp_b10 >= 0) *ascii++ = 48; + + *ascii = 0; + + /* Total buffer requirement (including the '\0') is + * 5+precision - see check at the start. + */ + return; + } + + /* Here if an exponent is required, adjust size for + * the digits we output but did not count. The total + * digit output here so far is at most 1+precision - no + * decimal point and no leading or trailing zeros have + * been output. + */ + size -= cdigits; + + *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ + + /* The following use of an unsigned temporary avoids ambiguities in + * the signed arithmetic on exp_b10 and permits GCC at least to do + * better optimization. + */ + { + unsigned int uexp_b10; + + if (exp_b10 < 0) + { + *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ + uexp_b10 = -exp_b10; + } + + else + uexp_b10 = exp_b10; + + cdigits = 0; + + while (uexp_b10 > 0) + { + exponent[cdigits++] = (char)(48 + uexp_b10 % 10); + uexp_b10 /= 10; + } + } + + /* Need another size check here for the exponent digits, so + * this need not be considered above. + */ + if ((int)size > cdigits) + { + while (cdigits > 0) *ascii++ = exponent[--cdigits]; + + *ascii = 0; + + return; + } + } + } + else if (!(fp >= DBL_MIN)) + { + *ascii++ = 48; /* '0' */ + *ascii = 0; + return; + } + else + { + *ascii++ = 105; /* 'i' */ + *ascii++ = 110; /* 'n' */ + *ascii++ = 102; /* 'f' */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} + +# endif /* FLOATING_POINT */ + +# ifdef PNG_FIXED_POINT_SUPPORTED +/* Function to format a fixed point value in ASCII. + */ +void /* PRIVATE */ +png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, + png_size_t size, png_fixed_point fp) +{ + /* Require space for 10 decimal digits, a decimal point, a minus sign and a + * trailing \0, 13 characters: + */ + if (size > 12) + { + png_uint_32 num; + + /* Avoid overflow here on the minimum integer. */ + if (fp < 0) + *ascii++ = 45, --size, num = -fp; + else + num = fp; + + if (num <= 0x80000000) /* else overflowed */ + { + unsigned int ndigits = 0, first = 16 /* flag value */; + char digits[10]; + + while (num) + { + /* Split the low digit off num: */ + unsigned int tmp = num/10; + num -= tmp*10; + digits[ndigits++] = (char)(48 + num); + /* Record the first non-zero digit, note that this is a number + * starting at 1, it's not actually the array index. + */ + if (first == 16 && num > 0) + first = ndigits; + num = tmp; + } + + if (ndigits > 0) + { + while (ndigits > 5) *ascii++ = digits[--ndigits]; + /* The remaining digits are fractional digits, ndigits is '5' or + * smaller at this point. It is certainly not zero. Check for a + * non-zero fractional digit: + */ + if (first <= 5) + { + unsigned int i; + *ascii++ = 46; /* decimal point */ + /* ndigits may be <5 for small numbers, output leading zeros + * then ndigits digits to first: + */ + i = 5; + while (ndigits < i) *ascii++ = 48, --i; + while (ndigits >= first) *ascii++ = digits[--ndigits]; + /* Don't output the trailing zeros! */ + } + } + else + *ascii++ = 48; + + /* And null terminate the string: */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} +# endif /* FIXED_POINT */ +#endif /* SCAL */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +png_fixed_point +png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) +{ + double r = floor(100000 * fp + .5); + + if (r > 2147483647. || r < -2147483648.) + png_fixed_error(png_ptr, text); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(text) +# endif + + return (png_fixed_point)r; +} +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* muldiv functions */ +/* This API takes signed arguments and rounds the result to the nearest + * integer (or, for a fixed point number - the standard argument - to + * the nearest .00001). Overflow and divide by zero are signalled in + * the result, a boolean - true on success, false on overflow. + */ +int +png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + /* Return a * times / divisor, rounded. */ + if (divisor != 0) + { + if (a == 0 || times == 0) + { + *res = 0; + return 1; + } + else + { +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a; + r *= times; + r /= divisor; + r = floor(r+.5); + + /* A png_fixed_point is a 32-bit integer. */ + if (r <= 2147483647. && r >= -2147483648.) + { + *res = (png_fixed_point)r; + return 1; + } +#else + int negative = 0; + png_uint_32 A, T, D; + png_uint_32 s16, s32, s00; + + if (a < 0) + negative = 1, A = -a; + else + A = a; + + if (times < 0) + negative = !negative, T = -times; + else + T = times; + + if (divisor < 0) + negative = !negative, D = -divisor; + else + D = divisor; + + /* Following can't overflow because the arguments only + * have 31 bits each, however the result may be 32 bits. + */ + s16 = (A >> 16) * (T & 0xffff) + + (A & 0xffff) * (T >> 16); + /* Can't overflow because the a*times bit is only 30 + * bits at most. + */ + s32 = (A >> 16) * (T >> 16) + (s16 >> 16); + s00 = (A & 0xffff) * (T & 0xffff); + + s16 = (s16 & 0xffff) << 16; + s00 += s16; + + if (s00 < s16) + ++s32; /* carry */ + + if (s32 < D) /* else overflow */ + { + /* s32.s00 is now the 64-bit product, do a standard + * division, we know that s32 < D, so the maximum + * required shift is 31. + */ + int bitshift = 32; + png_fixed_point result = 0; /* NOTE: signed */ + + while (--bitshift >= 0) + { + png_uint_32 d32, d00; + + if (bitshift > 0) + d32 = D >> (32-bitshift), d00 = D << bitshift; + + else + d32 = 0, d00 = D; + + if (s32 > d32) + { + if (s00 < d00) --s32; /* carry */ + s32 -= d32, s00 -= d00, result += 1<= d00) + s32 = 0, s00 -= d00, result += 1<= (D >> 1)) + ++result; + + if (negative != 0) + result = -result; + + /* Check for overflow. */ + if ((negative != 0 && result <= 0) || + (negative == 0 && result >= 0)) + { + *res = result; + return 1; + } + } +#endif + } + } + + return 0; +} +#endif /* READ_GAMMA || INCH_CONVERSIONS */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* The following is for when the caller doesn't much care about the + * result. + */ +png_fixed_point +png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + png_fixed_point result; + + if (png_muldiv(&result, a, times, divisor) != 0) + return result; + + png_warning(png_ptr, "fixed point overflow ignored"); + return 0; +} +#endif + +#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ +/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ +png_fixed_point +png_reciprocal(png_fixed_point a) +{ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(1E10/a+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, 100000, 100000, a) != 0) + return res; +#endif + + return 0; /* error/overflow */ +} + +/* This is the shared test on whether a gamma value is 'significant' - whether + * it is worth doing gamma correction. + */ +int /* PRIVATE */ +png_gamma_significant(png_fixed_point gamma_val) +{ + return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || + gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +#ifdef PNG_16BIT_SUPPORTED +/* A local convenience routine. */ +static png_fixed_point +png_product2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a * 1E-5; + r *= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, a, b, 100000) != 0) + return res; +#endif + + return 0; /* overflow */ +} +#endif /* 16BIT */ + +/* The inverse of the above. */ +png_fixed_point +png_reciprocal2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + if (a != 0 && b != 0) + { + double r = 1E15/a; + r /= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; + } +#else + /* This may overflow because the range of png_fixed_point isn't symmetric, + * but this API is only used for the product of file and screen gamma so it + * doesn't matter that the smallest number it can produce is 1/21474, not + * 1/100000 + */ + png_fixed_point res = png_product2(a, b); + + if (res != 0) + return png_reciprocal(res); +#endif + + return 0; /* overflow */ +} +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ +#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* Fixed point gamma. + * + * The code to calculate the tables used below can be found in the shell script + * contrib/tools/intgamma.sh + * + * To calculate gamma this code implements fast log() and exp() calls using only + * fixed point arithmetic. This code has sufficient precision for either 8-bit + * or 16-bit sample values. + * + * The tables used here were calculated using simple 'bc' programs, but C double + * precision floating point arithmetic would work fine. + * + * 8-bit log table + * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. + */ +static const png_uint_32 +png_8bit_l2[128] = +{ + 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, + 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, + 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, + 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, + 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, + 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, + 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, + 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, + 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, + 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, + 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, + 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, + 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, + 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, + 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, + 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, + 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, + 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, + 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, + 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, + 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, + 24347096U, 0U + +#if 0 + /* The following are the values for 16-bit tables - these work fine for the + * 8-bit conversions but produce very slightly larger errors in the 16-bit + * log (about 1.2 as opposed to 0.7 absolute error in the final value). To + * use these all the shifts below must be adjusted appropriately. + */ + 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, + 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, + 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, + 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, + 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, + 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, + 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, + 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, + 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, + 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, + 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, + 1119, 744, 372 +#endif +}; + +static png_int_32 +png_log8bit(unsigned int x) +{ + unsigned int lg2 = 0; + /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, + * because the log is actually negate that means adding 1. The final + * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 + * input), return -1 for the overflow (log 0) case, - so the result is + * always at most 19 bits. + */ + if ((x &= 0xff) == 0) + return -1; + + if ((x & 0xf0) == 0) + lg2 = 4, x <<= 4; + + if ((x & 0xc0) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x80) == 0) + lg2 += 1, x <<= 1; + + /* result is at most 19 bits, so this cast is safe: */ + return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); +} + +/* The above gives exact (to 16 binary places) log2 values for 8-bit images, + * for 16-bit images we use the most significant 8 bits of the 16-bit value to + * get an approximation then multiply the approximation by a correction factor + * determined by the remaining up to 8 bits. This requires an additional step + * in the 16-bit case. + * + * We want log2(value/65535), we have log2(v'/255), where: + * + * value = v' * 256 + v'' + * = v' * f + * + * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 + * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less + * than 258. The final factor also needs to correct for the fact that our 8-bit + * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. + * + * This gives a final formula using a calculated value 'x' which is value/v' and + * scaling by 65536 to match the above table: + * + * log2(x/257) * 65536 + * + * Since these numbers are so close to '1' we can use simple linear + * interpolation between the two end values 256/257 (result -368.61) and 258/257 + * (result 367.179). The values used below are scaled by a further 64 to give + * 16-bit precision in the interpolation: + * + * Start (256): -23591 + * Zero (257): 0 + * End (258): 23499 + */ +#ifdef PNG_16BIT_SUPPORTED +static png_int_32 +png_log16bit(png_uint_32 x) +{ + unsigned int lg2 = 0; + + /* As above, but now the input has 16 bits. */ + if ((x &= 0xffff) == 0) + return -1; + + if ((x & 0xff00) == 0) + lg2 = 8, x <<= 8; + + if ((x & 0xf000) == 0) + lg2 += 4, x <<= 4; + + if ((x & 0xc000) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x8000) == 0) + lg2 += 1, x <<= 1; + + /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional + * value. + */ + lg2 <<= 28; + lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; + + /* Now we need to interpolate the factor, this requires a division by the top + * 8 bits. Do this with maximum precision. + */ + x = ((x << 16) + (x >> 9)) / (x >> 8); + + /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, + * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly + * 16 bits to interpolate to get the low bits of the result. Round the + * answer. Note that the end point values are scaled by 64 to retain overall + * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust + * the overall scaling by 6-12. Round at every step. + */ + x -= 1U << 24; + + if (x <= 65536U) /* <= '257' */ + lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); + + else + lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); + + /* Safe, because the result can't have more than 20 bits: */ + return (png_int_32)((lg2 + 2048) >> 12); +} +#endif /* 16BIT */ + +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In + * each case only the low 16 bits are relevant - the fraction - since the + * integer bits (the top 4) simply determine a shift. + * + * The worst case is the 16-bit distinction between 65535 and 65534. This + * requires perhaps spurious accuracy in the decoding of the logarithm to + * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance + * of getting this accuracy in practice. + * + * To deal with this the following exp() function works out the exponent of the + * frational part of the logarithm by using an accurate 32-bit value from the + * top four fractional bits then multiplying in the remaining bits. + */ +static const png_uint_32 +png_32bit_exp[16] = +{ + /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ + 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, + 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, + 2553802834U, 2445529972U, 2341847524U, 2242560872U +}; + +/* Adjustment table; provided to explain the numbers in the code below. */ +#if 0 +for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} + 11 44937.64284865548751208448 + 10 45180.98734845585101160448 + 9 45303.31936980687359311872 + 8 45364.65110595323018870784 + 7 45395.35850361789624614912 + 6 45410.72259715102037508096 + 5 45418.40724413220722311168 + 4 45422.25021786898173001728 + 3 45424.17186732298419044352 + 2 45425.13273269940811464704 + 1 45425.61317555035558641664 + 0 45425.85339951654943850496 +#endif + +static png_uint_32 +png_exp(png_fixed_point x) +{ + if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ + { + /* Obtain a 4-bit approximation */ + png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; + + /* Incorporate the low 12 bits - these decrease the returned value by + * multiplying by a number less than 1 if the bit is set. The multiplier + * is determined by the above table and the shift. Notice that the values + * converge on 45426 and this is used to allow linear interpolation of the + * low bits. + */ + if (x & 0x800) + e -= (((e >> 16) * 44938U) + 16U) >> 5; + + if (x & 0x400) + e -= (((e >> 16) * 45181U) + 32U) >> 6; + + if (x & 0x200) + e -= (((e >> 16) * 45303U) + 64U) >> 7; + + if (x & 0x100) + e -= (((e >> 16) * 45365U) + 128U) >> 8; + + if (x & 0x080) + e -= (((e >> 16) * 45395U) + 256U) >> 9; + + if (x & 0x040) + e -= (((e >> 16) * 45410U) + 512U) >> 10; + + /* And handle the low 6 bits in a single block. */ + e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; + + /* Handle the upper bits of x. */ + e >>= x >> 16; + return e; + } + + /* Check for overflow */ + if (x <= 0) + return png_32bit_exp[0]; + + /* Else underflow */ + return 0; +} + +static png_byte +png_exp8bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the + * second, rounding, step can't overflow because of the first, subtraction, + * step. + */ + x -= x >> 8; + return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +static png_uint_16 +png_exp16bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ + x -= x >> 16; + return (png_uint_16)((x + 32767U) >> 16); +} +#endif /* 16BIT */ +#endif /* FLOATING_ARITHMETIC */ + +png_byte +png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 255) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly + * convert this to a floating point value. This includes values that + * would overflow if 'value' were to be converted to 'int'. + * + * Apparently GCC, however, does an intermediate conversion to (int) + * on some (ARM) but not all (x86) platforms, possibly because of + * hardware FP limitations. (E.g. if the hardware conversion always + * assumes the integer register contains a signed value.) This results + * in ANSI-C undefined behavior for large values. + * + * Other implementations on the same machine might actually be ANSI-C90 + * conformant and therefore compile spurious extra code for the large + * values. + * + * We can be reasonably sure that an unsigned to float conversion + * won't be faster than an int to float one. Therefore this code + * assumes responsibility for the undefined behavior, which it knows + * can't happen because of the check above. + * + * Note the argument to this routine is an (unsigned int) because, on + * 16-bit platforms, it is assigned a value which might be out of + * range for an (int); that would result in undefined behavior in the + * caller if the *argument* ('value') were to be declared (int). + */ + double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); + return (png_byte)r; +# else + png_int_32 lg2 = png_log8bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp8bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_byte)(value & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +png_uint_16 +png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 65535) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* The same (unsigned int)->(double) constraints apply here as above, + * however in this case the (unsigned int) to (int) conversion can + * overflow on an ANSI-C90 compliant system so the cast needs to ensure + * that this is not possible. + */ + double r = floor(65535*pow((png_int_32)value/65535., + gamma_val*.00001)+.5); + return (png_uint_16)r; +# else + png_int_32 lg2 = png_log16bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp16bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_uint_16)value; +} +#endif /* 16BIT */ + +/* This does the right thing based on the bit_depth field of the + * png_struct, interpreting values as 8-bit or 16-bit. While the result + * is nominally a 16-bit value if bit depth is 8 then the result is + * 8-bit (as are the arguments.) + */ +png_uint_16 /* PRIVATE */ +png_gamma_correct(png_structrp png_ptr, unsigned int value, + png_fixed_point gamma_val) +{ + if (png_ptr->bit_depth == 8) + return png_gamma_8bit_correct(value, gamma_val); + +#ifdef PNG_16BIT_SUPPORTED + else + return png_gamma_16bit_correct(value, gamma_val); +#else + /* should not reach this */ + return 0; +#endif /* 16BIT */ +} + +#ifdef PNG_16BIT_SUPPORTED +/* Internal function to build a single 16-bit table - the table consists of + * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount + * to shift the input values right (or 16-number_of_signifiant_bits). + * + * The caller is responsible for ensuring that the table gets cleaned up on + * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument + * should be somewhere that will be cleaned. + */ +static void +png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + /* Various values derived from 'shift': */ + PNG_CONST unsigned int num = 1U << (8U - shift); +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* CSE the division and work round wacky GCC warnings (see the comments + * in png_gamma_8bit_correct for where these come from.) + */ + PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1); +#endif + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); + unsigned int i; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_uint_16p sub_table = table[i] = + (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); + + /* The 'threshold' test is repeated here because it can arise for one of + * the 16-bit tables even if the others don't hit it. + */ + if (png_gamma_significant(gamma_val) != 0) + { + /* The old code would overflow at the end and this would cause the + * 'pow' function to return a result >1, resulting in an + * arithmetic error. This code follows the spec exactly; ig is + * the recovered input sample, it always has 8-16 bits. + * + * We want input * 65535/max, rounded, the arithmetic fits in 32 + * bits (unsigned) so long as max <= 32767. + */ + unsigned int j; + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* Inline the 'max' scaling operation: */ + /* See png_gamma_8bit_correct for why the cast to (int) is + * required here. + */ + double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); + sub_table[j] = (png_uint_16)d; +# else + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); +# endif + } + } + else + { + /* We must still build a table, but do it the fast way. */ + unsigned int j; + + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; + + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = (png_uint_16)ig; + } + } + } +} + +/* NOTE: this function expects the *inverse* of the overall gamma transformation + * required. + */ +static void +png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + unsigned int i; + png_uint_32 last; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + /* 'num' is the number of tables and also the number of low bits of low + * bits of the input 16-bit value used to select a table. Each table is + * itself indexed by the high 8 bits of the value. + */ + for (i = 0; i < num; i++) + table[i] = (png_uint_16p)png_malloc(png_ptr, + 256 * (sizeof (png_uint_16))); + + /* 'gamma_val' is set to the reciprocal of the value calculated above, so + * pow(out,g) is an *input* value. 'last' is the last input value set. + * + * In the loop 'i' is used to find output values. Since the output is + * 8-bit there are only 256 possible values. The tables are set up to + * select the closest possible output value for each input by finding + * the input value at the boundary between each pair of output values + * and filling the table up to that boundary with the lower output + * value. + * + * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit + * values the code below uses a 16-bit value in i; the values start at + * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last + * entries are filled with 255). Start i at 128 and fill all 'last' + * table entries <= 'max' + */ + last = 0; + for (i = 0; i < 255; ++i) /* 8-bit output value */ + { + /* Find the corresponding maximum input value */ + png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ + + /* Find the boundary value in 16 bits: */ + png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); + + /* Adjust (round) to (16-shift) bits: */ + bound = (bound * max + 32768U)/65535U + 1U; + + while (last < bound) + { + table[last & (0xffU >> shift)][last >> (8U - shift)] = out; + last++; + } + } + + /* And fill in the final entries. */ + while (last < (num << 8)) + { + table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; + last++; + } +} +#endif /* 16BIT */ + +/* Build a single 8-bit table: same as the 16-bit case but much simpler (and + * typically much faster). Note that libpng currently does no sBIT processing + * (apparently contrary to the spec) so a 256-entry table is always generated. + */ +static void +png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, + PNG_CONST png_fixed_point gamma_val) +{ + unsigned int i; + png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); + + if (png_gamma_significant(gamma_val) != 0) + for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); + + else + for (i=0; i<256; ++i) + table[i] = (png_byte)(i & 0xff); +} + +/* Used from png_read_destroy and below to release the memory used by the gamma + * tables. + */ +void /* PRIVATE */ +png_destroy_gamma_table(png_structrp png_ptr) +{ + png_free(png_ptr, png_ptr->gamma_table); + png_ptr->gamma_table = NULL; + +#ifdef PNG_16BIT_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); + png_ptr->gamma_16_table = NULL; + } +#endif /* 16BIT */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_ptr->gamma_from_1 = NULL; + png_free(png_ptr, png_ptr->gamma_to_1); + png_ptr->gamma_to_1 = NULL; + +#ifdef PNG_16BIT_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); + png_ptr->gamma_16_from_1 = NULL; + } + 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); + png_ptr->gamma_16_to_1 = NULL; + } +#endif /* 16BIT */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +} + +/* 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_structrp png_ptr, int bit_depth) +{ + png_debug(1, "in png_build_gamma_table"); + + /* Remove any existing table; this copes with multiple calls to + * png_read_update_info. The warning is because building the gamma tables + * multiple times is a performance hit - it's harmless but the ability to call + * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible + * to warn if the app introduces such a hit. + */ + if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) + { + png_warning(png_ptr, "gamma table being rebuilt"); + png_destroy_gamma_table(png_ptr); + } + + if (bit_depth <= 8) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_table, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, + png_reciprocal(png_ptr->colorspace.gamma)); + + png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } +#ifdef PNG_16BIT_SUPPORTED + else + { + png_byte shift, sig_bit; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + sig_bit = png_ptr->sig_bit.red; + + if (png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if (png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + sig_bit = png_ptr->sig_bit.gray; + + /* 16-bit gamma code uses this equation: + * + * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] + * + * Where 'iv' is the input color value and 'ov' is the output value - + * pow(iv, gamma). + * + * Thus the gamma table consists of up to 256 256-entry tables. The table + * is selected by the (8-gamma_shift) most significant of the low 8 bits of + * the color value then indexed by the upper 8 bits: + * + * table[low bits][high 8 bits] + * + * So the table 'n' corresponds to all those 'iv' of: + * + * ..<(n+1 << gamma_shift)-1> + * + */ + if (sig_bit > 0 && sig_bit < 16U) + /* shift == insignificant bits */ + shift = (png_byte)((16U - sig_bit) & 0xff); + + else + shift = 0; /* keep all 16 bits */ + + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + { + /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively + * the significant bits in the *input* when the output will + * eventually be 8 bits. By default it is 11. + */ + if (shift < (16U - PNG_MAX_GAMMA_8)) + shift = (16U - PNG_MAX_GAMMA_8); + } + + if (shift > 8U) + shift = 8U; /* Guarantees at least one table! */ + + png_ptr->gamma_shift = shift; + + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be reduced + * to 8 bits. + */ + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + + else + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, + png_reciprocal(png_ptr->colorspace.gamma)); + + /* Notice that the '16 from 1' table should be full precision, however + * the lookup on this table still uses gamma_shift, so it can't be. + * TODO: fix this. + */ + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } +#endif /* 16BIT */ +} +#endif /* READ_GAMMA */ + +/* HARDWARE OR SOFTWARE OPTION SUPPORT */ +#ifdef PNG_SET_OPTION_SUPPORTED +int PNGAPI +png_set_option(png_structrp png_ptr, int option, int onoff) +{ + if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && + (option & 1) == 0) + { + int mask = 3 << option; + int setting = (2 + (onoff != 0)) << option; + int current = png_ptr->options; + + png_ptr->options = (png_byte)(((current & ~mask) | setting) & 0xff); + + return (current & mask) >> option; + } + + return PNG_OPTION_INVALID; +} +#endif + +/* sRGB support */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* sRGB conversion tables; these are machine generated with the code in + * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the + * specification (see the article at http://en.wikipedia.org/wiki/SRGB) + * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. + * The sRGB to linear table is exact (to the nearest 16 bit linear fraction). + * The inverse (linear to sRGB) table has accuracies as follows: + * + * For all possible (255*65535+1) input values: + * + * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact + * + * For the input values corresponding to the 65536 16-bit values: + * + * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact + * + * In all cases the inexact readings are only off by one. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* The convert-to-sRGB table is only currently required for read. */ +const png_uint_16 png_sRGB_table[256] = +{ + 0,20,40,60,80,99,119,139, + 159,179,199,219,241,264,288,313, + 340,367,396,427,458,491,526,562, + 599,637,677,718,761,805,851,898, + 947,997,1048,1101,1156,1212,1270,1330, + 1391,1453,1517,1583,1651,1720,1790,1863, + 1937,2013,2090,2170,2250,2333,2418,2504, + 2592,2681,2773,2866,2961,3058,3157,3258, + 3360,3464,3570,3678,3788,3900,4014,4129, + 4247,4366,4488,4611,4736,4864,4993,5124, + 5257,5392,5530,5669,5810,5953,6099,6246, + 6395,6547,6700,6856,7014,7174,7335,7500, + 7666,7834,8004,8177,8352,8528,8708,8889, + 9072,9258,9445,9635,9828,10022,10219,10417, + 10619,10822,11028,11235,11446,11658,11873,12090, + 12309,12530,12754,12980,13209,13440,13673,13909, + 14146,14387,14629,14874,15122,15371,15623,15878, + 16135,16394,16656,16920,17187,17456,17727,18001, + 18277,18556,18837,19121,19407,19696,19987,20281, + 20577,20876,21177,21481,21787,22096,22407,22721, + 23038,23357,23678,24002,24329,24658,24990,25325, + 25662,26001,26344,26688,27036,27386,27739,28094, + 28452,28813,29176,29542,29911,30282,30656,31033, + 31412,31794,32179,32567,32957,33350,33745,34143, + 34544,34948,35355,35764,36176,36591,37008,37429, + 37852,38278,38706,39138,39572,40009,40449,40891, + 41337,41785,42236,42690,43147,43606,44069,44534, + 45002,45473,45947,46423,46903,47385,47871,48359, + 48850,49344,49841,50341,50844,51349,51858,52369, + 52884,53401,53921,54445,54971,55500,56032,56567, + 57105,57646,58190,58737,59287,59840,60396,60955, + 61517,62082,62650,63221,63795,64372,64952,65535 +}; +#endif /* SIMPLIFIED_READ */ + +/* The base/delta tables are required for both read and write (but currently + * only the simplified versions.) + */ +const png_uint_16 png_sRGB_base[512] = +{ + 128,1782,3383,4644,5675,6564,7357,8074, + 8732,9346,9921,10463,10977,11466,11935,12384, + 12816,13233,13634,14024,14402,14769,15125,15473, + 15812,16142,16466,16781,17090,17393,17690,17981, + 18266,18546,18822,19093,19359,19621,19879,20133, + 20383,20630,20873,21113,21349,21583,21813,22041, + 22265,22487,22707,22923,23138,23350,23559,23767, + 23972,24175,24376,24575,24772,24967,25160,25352, + 25542,25730,25916,26101,26284,26465,26645,26823, + 27000,27176,27350,27523,27695,27865,28034,28201, + 28368,28533,28697,28860,29021,29182,29341,29500, + 29657,29813,29969,30123,30276,30429,30580,30730, + 30880,31028,31176,31323,31469,31614,31758,31902, + 32045,32186,32327,32468,32607,32746,32884,33021, + 33158,33294,33429,33564,33697,33831,33963,34095, + 34226,34357,34486,34616,34744,34873,35000,35127, + 35253,35379,35504,35629,35753,35876,35999,36122, + 36244,36365,36486,36606,36726,36845,36964,37083, + 37201,37318,37435,37551,37668,37783,37898,38013, + 38127,38241,38354,38467,38580,38692,38803,38915, + 39026,39136,39246,39356,39465,39574,39682,39790, + 39898,40005,40112,40219,40325,40431,40537,40642, + 40747,40851,40955,41059,41163,41266,41369,41471, + 41573,41675,41777,41878,41979,42079,42179,42279, + 42379,42478,42577,42676,42775,42873,42971,43068, + 43165,43262,43359,43456,43552,43648,43743,43839, + 43934,44028,44123,44217,44311,44405,44499,44592, + 44685,44778,44870,44962,45054,45146,45238,45329, + 45420,45511,45601,45692,45782,45872,45961,46051, + 46140,46229,46318,46406,46494,46583,46670,46758, + 46846,46933,47020,47107,47193,47280,47366,47452, + 47538,47623,47709,47794,47879,47964,48048,48133, + 48217,48301,48385,48468,48552,48635,48718,48801, + 48884,48966,49048,49131,49213,49294,49376,49458, + 49539,49620,49701,49782,49862,49943,50023,50103, + 50183,50263,50342,50422,50501,50580,50659,50738, + 50816,50895,50973,51051,51129,51207,51285,51362, + 51439,51517,51594,51671,51747,51824,51900,51977, + 52053,52129,52205,52280,52356,52432,52507,52582, + 52657,52732,52807,52881,52956,53030,53104,53178, + 53252,53326,53400,53473,53546,53620,53693,53766, + 53839,53911,53984,54056,54129,54201,54273,54345, + 54417,54489,54560,54632,54703,54774,54845,54916, + 54987,55058,55129,55199,55269,55340,55410,55480, + 55550,55620,55689,55759,55828,55898,55967,56036, + 56105,56174,56243,56311,56380,56448,56517,56585, + 56653,56721,56789,56857,56924,56992,57059,57127, + 57194,57261,57328,57395,57462,57529,57595,57662, + 57728,57795,57861,57927,57993,58059,58125,58191, + 58256,58322,58387,58453,58518,58583,58648,58713, + 58778,58843,58908,58972,59037,59101,59165,59230, + 59294,59358,59422,59486,59549,59613,59677,59740, + 59804,59867,59930,59993,60056,60119,60182,60245, + 60308,60370,60433,60495,60558,60620,60682,60744, + 60806,60868,60930,60992,61054,61115,61177,61238, + 61300,61361,61422,61483,61544,61605,61666,61727, + 61788,61848,61909,61969,62030,62090,62150,62211, + 62271,62331,62391,62450,62510,62570,62630,62689, + 62749,62808,62867,62927,62986,63045,63104,63163, + 63222,63281,63340,63398,63457,63515,63574,63632, + 63691,63749,63807,63865,63923,63981,64039,64097, + 64155,64212,64270,64328,64385,64443,64500,64557, + 64614,64672,64729,64786,64843,64900,64956,65013, + 65070,65126,65183,65239,65296,65352,65409,65465 +}; + +const png_byte png_sRGB_delta[512] = +{ + 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, + 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, + 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, + 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, + 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, + 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, + 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,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,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#endif /* SIMPLIFIED READ/WRITE sRGB support */ + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +static int +png_image_free_function(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_controlp cp = image->opaque; + png_control c; + + /* Double check that we have a png_ptr - it should be impossible to get here + * without one. + */ + if (cp->png_ptr == NULL) + return 0; + + /* First free any data held in the control structure. */ +# ifdef PNG_STDIO_SUPPORTED + if (cp->owned_file != 0) + { + FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); + cp->owned_file = 0; + + /* Ignore errors here. */ + if (fp != NULL) + { + cp->png_ptr->io_ptr = NULL; + (void)fclose(fp); + } + } +# endif + + /* Copy the control structure so that the original, allocated, version can be + * safely freed. Notice that a png_error here stops the remainder of the + * cleanup, but this is probably fine because that would indicate bad memory + * problems anyway. + */ + c = *cp; + image->opaque = &c; + png_free(c.png_ptr, cp); + + /* Then the structures, calling the correct API. */ + if (c.for_write != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + png_destroy_write_struct(&c.png_ptr, &c.info_ptr); +# else + png_error(c.png_ptr, "simplified write not supported"); +# endif + } + else + { +# ifdef PNG_SIMPLIFIED_READ_SUPPORTED + png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); +# else + png_error(c.png_ptr, "simplified read not supported"); +# endif + } + + /* Success. */ + return 1; +} + +void PNGAPI +png_image_free(png_imagep image) +{ + /* Safely call the real function, but only if doing so is safe at this point + * (if not inside an error handling context). Otherwise assume + * png_safe_execute will call this API after the return. + */ + if (image != NULL && image->opaque != NULL && + image->opaque->error_buf == NULL) + { + /* Ignore errors here: */ + (void)png_safe_execute(image, png_image_free_function, image); + image->opaque = NULL; + } +} + +int /* PRIVATE */ +png_image_error(png_imagep image, png_const_charp error_message) +{ + /* Utility to log an error. */ + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + png_image_free(image); + return 0; +} + +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h index 805be120..372599bf 100644 --- a/thirdparty/libpng/png.h +++ b/thirdparty/libpng/png.h @@ -1,26 +1,27 @@ /* png.h - header file for PNG reference library * - * libpng version 1.4.4 - September 23, 2010 - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * libpng version 1.6.17, March 26, 2015 + * + * Copyright (c) 1998-2015 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 code is released under the libpng license (See LICENSE, below) * * 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.4.4 - September 23, 2010: Glenn - * See also "Contributing Authors", below. + * 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.6.17, March 26, 2015: 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: + * 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 @@ -137,37 +138,105 @@ * 1.4.1beta01-03 14 10401 14.so.14.1[.0] * 1.4.1rc01 14 10401 14.so.14.1[.0] * 1.4.1beta04-12 14 10401 14.so.14.1[.0] - * 1.4.1rc02-04 14 10401 14.so.14.1[.0] * 1.4.1 14 10401 14.so.14.1[.0] - * 1.4.2beta01 14 10402 14.so.14.2[.0] - * 1.4.2rc02-06 14 10402 14.so.14.2[.0] * 1.4.2 14 10402 14.so.14.2[.0] - * 1.4.3beta01-05 14 10403 14.so.14.3[.0] - * 1.4.3rc01-03 14 10403 14.so.14.3[.0] * 1.4.3 14 10403 14.so.14.3[.0] - * 1.4.4beta01-08 14 10404 14.so.14.4[.0] - * 1.4.4rc01-06 14 10404 14.so.14.4[.0] + * 1.4.4 14 10404 14.so.14.4[.0] + * 1.5.0beta01-58 15 10500 15.so.15.0[.0] + * 1.5.0rc01-07 15 10500 15.so.15.0[.0] + * 1.5.0 15 10500 15.so.15.0[.0] + * 1.5.1beta01-11 15 10501 15.so.15.1[.0] + * 1.5.1rc01-02 15 10501 15.so.15.1[.0] + * 1.5.1 15 10501 15.so.15.1[.0] + * 1.5.2beta01-03 15 10502 15.so.15.2[.0] + * 1.5.2rc01-03 15 10502 15.so.15.2[.0] + * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-08 15 10505 15.so.15.5[.0] + * 1.5.5rc01 15 10505 15.so.15.5[.0] + * 1.5.5 15 10505 15.so.15.5[.0] + * 1.5.6beta01-07 15 10506 15.so.15.6[.0] + * 1.5.6rc01-03 15 10506 15.so.15.6[.0] + * 1.5.6 15 10506 15.so.15.6[.0] + * 1.5.7beta01-05 15 10507 15.so.15.7[.0] + * 1.5.7rc01-03 15 10507 15.so.15.7[.0] + * 1.5.7 15 10507 15.so.15.7[.0] + * 1.6.0beta01-40 16 10600 16.so.16.0[.0] + * 1.6.0rc01-08 16 10600 16.so.16.0[.0] + * 1.6.0 16 10600 16.so.16.0[.0] + * 1.6.1beta01-09 16 10601 16.so.16.1[.0] + * 1.6.1rc01 16 10601 16.so.16.1[.0] + * 1.6.1 16 10601 16.so.16.1[.0] + * 1.6.2beta01 16 10602 16.so.16.2[.0] + * 1.6.2rc01-06 16 10602 16.so.16.2[.0] + * 1.6.2 16 10602 16.so.16.2[.0] + * 1.6.3beta01-11 16 10603 16.so.16.3[.0] + * 1.6.3rc01 16 10603 16.so.16.3[.0] + * 1.6.3 16 10603 16.so.16.3[.0] + * 1.6.4beta01-02 16 10604 16.so.16.4[.0] + * 1.6.4rc01 16 10604 16.so.16.4[.0] + * 1.6.4 16 10604 16.so.16.4[.0] + * 1.6.5 16 10605 16.so.16.5[.0] + * 1.6.6 16 10606 16.so.16.6[.0] + * 1.6.7beta01-04 16 10607 16.so.16.7[.0] + * 1.6.7rc01-03 16 10607 16.so.16.7[.0] + * 1.6.7 16 10607 16.so.16.7[.0] + * 1.6.8beta01-02 16 10608 16.so.16.8[.0] + * 1.6.8rc01-02 16 10608 16.so.16.8[.0] + * 1.6.8 16 10608 16.so.16.8[.0] + * 1.6.9beta01-04 16 10609 16.so.16.9[.0] + * 1.6.9rc01-02 16 10609 16.so.16.9[.0] + * 1.6.9 16 10609 16.so.16.9[.0] + * 1.6.10beta01-03 16 10610 16.so.16.10[.0] + * 1.6.10rc01-03 16 10610 16.so.16.10[.0] + * 1.6.10 16 10610 16.so.16.10[.0] + * 1.6.11beta01-06 16 10611 16.so.16.11[.0] + * 1.6.11rc01-02 16 10611 16.so.16.11[.0] + * 1.6.11 16 10611 16.so.16.11[.0] + * 1.6.12rc01-03 16 10612 16.so.16.12[.0] + * 1.6.12 16 10612 16.so.16.12[.0] + * 1.6.13beta01-04 16 10613 16.so.16.13[.0] + * 1.6.13rc01-02 16 10613 16.so.16.13[.0] + * 1.6.13 16 10613 16.so.16.13[.0] + * 1.6.14beta01-07 16 10614 16.so.16.14[.0] + * 1.6.14rc01-02 16 10614 16.so.16.14[.0] + * 1.6.14 16 10614 16.so.16.14[.0] + * 1.6.15beta01-08 16 10615 16.so.16.15[.0] + * 1.6.15rc01-03 16 10615 16.so.16.15[.0] + * 1.6.15 16 10615 16.so.16.15[.0] + * 1.6.16beta01-03 16 10616 16.so.16.16[.0] + * 1.6.16rc01-02 16 10616 16.so.16.16[.0] + * 1.6.16 16 10616 16.so.16.16[.0] + * 1.6.17beta01-06 16 10617 16.so.16.17[.0] + * 1.6.17rc01-06 16 10617 16.so.16.17[.0] + * 1.6.17 16 10617 16.so.16.17[.0] * - * 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". + * 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 "rcNN". * - * 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. + * 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). + * 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 a W3C Recommendation and as an ISO Specification, - * + * + * If you just need to read a PNG file and don't want to read the documentation + * skip to the end of this file and read the section entitled 'simplified API'. */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.4.4" +#define PNG_LIBPNG_VER_STRING "1.6.17" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.4.4 - September 23, 2010\n" + " libpng version 1.6.17 - March 26, 2015\n" -#define PNG_LIBPNG_VER_SONUM 14 -#define PNG_LIBPNG_VER_DLLNUM 14 +#define PNG_LIBPNG_VER_SONUM 16 +#define PNG_LIBPNG_VER_DLLNUM 16 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 -#define PNG_LIBPNG_VER_MINOR 4 -#define PNG_LIBPNG_VER_RELEASE 4 +#define PNG_LIBPNG_VER_MINOR 6 +#define PNG_LIBPNG_VER_RELEASE 17 + /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ @@ -384,7 +460,7 @@ #define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with PNG_LIBPNG_BUILD_PRIVATE */ -#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_BETA +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE /* Careful here. At one time, Guy wanted to use 082, but that would be octal. * We must not include leading zeros. @@ -392,15 +468,22 @@ * 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 10404 /* 1.4.4 */ +#define PNG_LIBPNG_VER 10617 /* 1.6.17 */ -#ifndef PNG_VERSION_INFO_ONLY -/* Include the compression library's header */ -#include "zlib.h" +/* Library configuration: these options cannot be changed after + * the library has been built. + */ +#ifndef PNGLCONF_H + /* If pnglibconf.h is missing, you can + * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h + */ +# include "pnglibconf.h" #endif -/* Include all user configurable info, including optional assembler routines */ -#include "pngconf.h" +#ifndef PNG_VERSION_INFO_ONLY + /* Machine specific configuration. */ +# include "pngconf.h" +#endif /* * Added at libpng-1.2.8 @@ -416,13 +499,13 @@ * StringFileInfo block must contain a SpecialBuild string. */ -#ifdef PNG_USER_PRIVATEBUILD +#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */ # define PNG_LIBPNG_BUILD_TYPE \ - (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) #else # ifdef PNG_LIBPNG_SPECIALBUILD # define PNG_LIBPNG_BUILD_TYPE \ - (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) # else # define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE) # endif @@ -435,20 +518,103 @@ 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. */ #define png_libpng_ver png_get_header_ver(NULL) -#endif /* PNG_NO_EXTERN */ +/* This file is arranged in several sections: + * + * 1. Any configuration options that can be specified by for the application + * code when it is built. (Build time configuration is in pnglibconf.h) + * 2. Type definitions (base types are defined in pngconf.h), structure + * definitions. + * 3. Exported library functions. + * 4. Simplified API. + * + * The library source code has additional files (principally pngpriv.h) that + * allow configuration of the library. + */ +/* Section 1: run time configuration + * See pnglibconf.h for build time configuration + * + * Run time configuration allows the application to choose between + * implementations of certain arithmetic APIs. The default is set + * at build time and recorded in pnglibconf.h, but it is safe to + * override these (and only these) settings. Note that this won't + * change what the library does, only application code, and the + * settings can (and probably should) be made on a per-file basis + * by setting the #defines before including png.h + * + * Use macros to read integers from PNG data or use the exported + * functions? + * PNG_USE_READ_MACROS: use the macros (see below) Note that + * the macros evaluate their argument multiple times. + * PNG_NO_USE_READ_MACROS: call the relevant library function. + * + * Use the alternative algorithm for compositing alpha samples that + * does not use division? + * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division' + * algorithm. + * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm. + * + * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is + * false? + * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error + * APIs to png_warning. + * Otherwise the calls are mapped to png_error. + */ + +/* Section 2: type definitions, including structures and compile time + * constants. + * See pngconf.h for base types that vary by machine/system + */ + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef char* png_libpng_version_1_6_17; + +/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. + * + * png_struct is the cache of information used while reading or writing a single + * PNG file. One of these is always required, although the simplified API + * (below) hides the creation and destruction of it. + */ +typedef struct png_struct_def png_struct; +typedef const png_struct * png_const_structp; +typedef png_struct * png_structp; +typedef png_struct * * png_structpp; + +/* png_info contains information read from or to be written to a PNG file. One + * or more of these must exist while reading or creating a PNG file. The + * information is not used by libpng during read but is used to control what + * gets written when a PNG file is created. "png_get_" function calls read + * information during read and "png_set_" functions calls write information + * when creating a PNG. + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_info_def png_info; +typedef png_info * png_infop; +typedef const png_info * png_const_infop; +typedef png_info * * png_infopp; + +/* Types with names ending 'p' are pointer types. The corresponding types with + * names ending 'rp' are identical pointer types except that the pointer is + * marked 'restrict', which means that it is the only pointer to the object + * passed to the function. Applications should not use the 'restrict' types; + * it is always valid to pass 'p' to a pointer with a function argument of the + * corresponding 'rp' type. Different compilers have different rules with + * regard to type matching in the presence of 'restrict'. For backward + * compatibility libpng callbacks never have 'restrict' in their parameters and, + * consequentially, writing portable application code is extremely difficult if + * an attempt is made to use 'restrict'. + */ +typedef png_struct * PNG_RESTRICT png_structrp; +typedef const png_struct * PNG_RESTRICT png_const_structrp; +typedef png_info * PNG_RESTRICT png_inforp; +typedef const png_info * PNG_RESTRICT png_const_inforp; /* 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 @@ -460,8 +626,9 @@ typedef struct png_color_struct png_byte green; png_byte blue; } png_color; -typedef png_color FAR * png_colorp; -typedef png_color FAR * FAR * png_colorpp; +typedef png_color * png_colorp; +typedef const png_color * png_const_colorp; +typedef png_color * * png_colorpp; typedef struct png_color_16_struct { @@ -471,8 +638,9 @@ typedef struct png_color_16_struct 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 png_color_16 * png_color_16p; +typedef const png_color_16 * png_const_color_16p; +typedef png_color_16 * * png_color_16pp; typedef struct png_color_8_struct { @@ -482,8 +650,9 @@ typedef struct png_color_8_struct 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; +typedef png_color_8 * png_color_8p; +typedef const png_color_8 * png_const_color_8p; +typedef png_color_8 * * png_color_8pp; /* * The following two structures are used for the in-core representation @@ -497,8 +666,9 @@ typedef struct png_sPLT_entry_struct 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; +typedef png_sPLT_entry * png_sPLT_entryp; +typedef const png_sPLT_entry * png_const_sPLT_entryp; +typedef png_sPLT_entry * * 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 @@ -512,17 +682,27 @@ typedef struct png_sPLT_struct 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; +typedef png_sPLT_t * png_sPLT_tp; +typedef const png_sPLT_t * png_const_sPLT_tp; +typedef png_sPLT_t * * 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. + * points to a regular zero-terminated C string. The "text" fields can be a + * regular C string, an empty string, or a NULL pointer. + * However, the structure returned by png_get_text() will always contain + * the "text" field as a regular zero-terminated C string (possibly + * empty), never a NULL pointer, so it can be safely used in printf() and + * other string-handling functions. Note that the "itxt_length", "lang", and + * "lang_key" members of the structure only exist when the library is built + * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by + * default without iTXt support. Also note that when iTXt *is* supported, + * the "lang" and "lang_key" fields contain NULL pointers when the + * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or + * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the + * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag" + * which is always 0 or 1, or its "compression method" which is always 0. */ typedef struct png_text_struct { @@ -535,16 +715,15 @@ typedef struct png_text_struct 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; +typedef png_text * png_textp; +typedef const png_text * png_const_textp; +typedef png_text * * png_textpp; #endif /* Supported compression types for text in PNG files (tEXt, and zTXt). @@ -572,340 +751,58 @@ typedef struct png_time_struct 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; +typedef png_time * png_timep; +typedef const png_time * png_const_timep; +typedef png_time * * png_timepp; -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) || \ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_USER_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. + * + * The data in the structure is set by libpng on read and used on write. */ typedef struct png_unknown_chunk_t { - png_byte name[5]; - png_byte *data; + png_byte name[5]; /* Textual chunk name with '\0' terminator */ + png_byte *data; /* Data, should not be modified on read! */ png_size_t size; - /* libpng-using applications should NOT directly modify this byte. */ + /* On write 'location' must be set using the flag values listed below. + * Notice that on read it is set by libpng however the values stored have + * more bits set than are listed below. Always treat the value as a + * bitmask. On write set only one bit - setting multiple bits may cause the + * chunk to be written in multiple places. + */ 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; + +typedef png_unknown_chunk * png_unknown_chunkp; +typedef const png_unknown_chunk * png_const_unknown_chunkp; +typedef png_unknown_chunk * * 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 PNG_DEPSTRUCT; /* width of image in pixels (from IHDR) */ - png_uint_32 height PNG_DEPSTRUCT; /* height of image in pixels (from IHDR) */ - png_uint_32 valid PNG_DEPSTRUCT; /* valid chunk data (see PNG_INFO_ - below) */ - png_size_t rowbytes PNG_DEPSTRUCT; /* bytes needed to hold an untransformed - row */ - png_colorp palette PNG_DEPSTRUCT; /* array of color values - (valid & PNG_INFO_PLTE) */ - png_uint_16 num_palette PNG_DEPSTRUCT; /* number of color entries in - "palette" (PLTE) */ - png_uint_16 num_trans PNG_DEPSTRUCT; /* number of transparent palette - color (tRNS) */ - png_byte bit_depth PNG_DEPSTRUCT; /* 1, 2, 4, 8, or 16 bits/channel - (from IHDR) */ - png_byte color_type PNG_DEPSTRUCT; /* see PNG_COLOR_TYPE_ below - (from IHDR) */ - /* The following three should have been named *_method not *_type */ - png_byte compression_type PNG_DEPSTRUCT; /* must be - PNG_COMPRESSION_TYPE_BASE (IHDR) */ - png_byte filter_type PNG_DEPSTRUCT; /* must be PNG_FILTER_TYPE_BASE - (from IHDR) */ - png_byte interlace_type PNG_DEPSTRUCT; /* One of PNG_INTERLACE_NONE, - PNG_INTERLACE_ADAM7 */ - - /* The following is informational only on read, and not used on writes. */ - png_byte channels PNG_DEPSTRUCT; /* number of data channels per - pixel (1, 2, 3, 4) */ - png_byte pixel_depth PNG_DEPSTRUCT; /* number of bits per pixel */ - png_byte spare_byte PNG_DEPSTRUCT; /* to align the data, and for - future use */ - png_byte signature[8] PNG_DEPSTRUCT; /* 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 PNG_DEPSTRUCT; /* gamma value of image, - if (valid & PNG_INFO_gAMA) */ -#endif - -#ifdef PNG_sRGB_SUPPORTED - /* GR-P, 0.96a */ - /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ - png_byte srgb_intent PNG_DEPSTRUCT; /* sRGB rendering intent - [0, 1, 2, or 3] */ -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* number of comments read/to write */ - int max_text PNG_DEPSTRUCT; /* current size of text array */ - png_textp text PNG_DEPSTRUCT; /* array of comments read/to write */ -#endif /* PNG_TEXT_SUPPORTED */ - -#ifdef 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 PNG_DEPSTRUCT; -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* 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_alpha PNG_DEPSTRUCT; /* alpha values for paletted - image */ - png_color_16 trans_color PNG_DEPSTRUCT; /* 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 PNG_DEPSTRUCT; -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* x offset on page */ - png_int_32 y_offset PNG_DEPSTRUCT; /* y offset on page */ - png_byte offset_unit_type PNG_DEPSTRUCT; /* offset units type */ -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* horizontal pixel density */ - png_uint_32 y_pixels_per_unit PNG_DEPSTRUCT; /* vertical pixel density */ - png_byte phys_unit_type PNG_DEPSTRUCT; /* resolution type (see - PNG_RESOLUTION_ below) */ -#endif - -#ifdef 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 PNG_DEPSTRUCT; -#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 PNG_DEPSTRUCT; - float y_white PNG_DEPSTRUCT; - float x_red PNG_DEPSTRUCT; - float y_red PNG_DEPSTRUCT; - float x_green PNG_DEPSTRUCT; - float y_green PNG_DEPSTRUCT; - float x_blue PNG_DEPSTRUCT; - float y_blue PNG_DEPSTRUCT; -#endif -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* pCAL chunk description string */ - png_int_32 pcal_X0 PNG_DEPSTRUCT; /* minimum value */ - png_int_32 pcal_X1 PNG_DEPSTRUCT; /* maximum value */ - png_charp pcal_units PNG_DEPSTRUCT; /* Latin-1 string giving physical - units */ - png_charpp pcal_params PNG_DEPSTRUCT; /* ASCII strings containing - parameter values */ - png_byte pcal_type PNG_DEPSTRUCT; /* equation type - (see PNG_EQUATION_ below) */ - png_byte pcal_nparams PNG_DEPSTRUCT; /* number of parameters given - in pcal_params */ -#endif - -/* New members added in libpng-1.0.6 */ - png_uint_32 free_me PNG_DEPSTRUCT; /* flags items libpng is - responsible for freeing */ - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) || \ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) - /* Storage for unknown chunks that the library doesn't recognize. */ - png_unknown_chunkp unknown_chunks PNG_DEPSTRUCT; - png_size_t unknown_chunks_num PNG_DEPSTRUCT; -#endif - -#ifdef PNG_iCCP_SUPPORTED - /* iCCP chunk data. */ - png_charp iccp_name PNG_DEPSTRUCT; /* profile name */ - png_charp iccp_profile PNG_DEPSTRUCT; /* International Color Consortium - profile data */ - /* Note to maintainer: should be png_bytep */ - png_uint_32 iccp_proflen PNG_DEPSTRUCT; /* ICC profile data length */ - png_byte iccp_compression PNG_DEPSTRUCT; /* Always zero */ -#endif - -#ifdef PNG_sPLT_SUPPORTED - /* Data on sPLT chunks (there may be more than one). */ - png_sPLT_tp splt_palettes PNG_DEPSTRUCT; - png_uint_32 splt_palettes_num PNG_DEPSTRUCT; -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* unit of physical scale */ -#ifdef PNG_FLOATING_POINT_SUPPORTED - double scal_pixel_width PNG_DEPSTRUCT; /* width of one pixel */ - double scal_pixel_height PNG_DEPSTRUCT; /* height of one pixel */ -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_charp scal_s_width PNG_DEPSTRUCT; /* string containing height */ - png_charp scal_s_height PNG_DEPSTRUCT; /* string containing width */ -#endif -#endif - -#ifdef 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 PNG_DEPSTRUCT; /* the image bits */ -#endif - -#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) - png_fixed_point int_gamma PNG_DEPSTRUCT; /* 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_DEPSTRUCT; - png_fixed_point int_y_white PNG_DEPSTRUCT; - png_fixed_point int_x_red PNG_DEPSTRUCT; - png_fixed_point int_y_red PNG_DEPSTRUCT; - png_fixed_point int_x_green PNG_DEPSTRUCT; - png_fixed_point int_y_green PNG_DEPSTRUCT; - png_fixed_point int_x_blue PNG_DEPSTRUCT; - png_fixed_point int_y_blue PNG_DEPSTRUCT; -#endif - -} png_info; - -typedef png_info FAR * png_infop; -typedef png_info FAR * FAR * png_infopp; +/* Flag values for the unknown chunk location byte. */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_AFTER_IDAT 0x08 /* Maximum positive integer used in PNG is (2^31)-1 */ #define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) #define PNG_UINT_32_MAX ((png_uint_32)(-1)) #define PNG_SIZE_MAX ((png_size_t)(-1)) +/* These are constants for fixed point values encoded in the + * PNG specification manner (x100000) + */ +#define PNG_FP_1 100000 +#define PNG_FP_HALF 50000 +#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) +#define PNG_FP_MIN (-PNG_FP_MAX) + /* These describe the color_type field in png_info. */ /* color type masks */ #define PNG_COLOR_MASK_PALETTE 1 @@ -992,7 +889,7 @@ typedef png_info FAR * FAR * png_infopp; #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 */ +#define PNG_INFO_IDAT 0x8000 /* 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 @@ -1000,61 +897,79 @@ typedef png_info FAR * FAR * png_infopp; */ typedef struct png_row_info_struct { - png_uint_32 width; /* width of row */ - png_size_t 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_uint_32 width; /* width of row */ + png_size_t 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; +typedef png_row_info * png_row_infop; +typedef png_row_info * * 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. + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. */ -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)); +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (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)); +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, - png_row_infop, png_bytep)); +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED -typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, - png_unknown_chunkp)); +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); #endif #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ #endif + #ifdef PNG_SETJMP_SUPPORTED -/* This must match the function definition in , and the - * application must include this before png.h to obtain the definition - * of jmp_buf. +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! */ -typedef void (PNGAPI *png_longjmp_ptr) PNGARG((jmp_buf, int)); +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); #endif /* Transform masks for the high-level interface */ @@ -1076,453 +991,92 @@ typedef void (PNGAPI *png_longjmp_ptr) PNGARG((jmp_buf, int)); #define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ /* Added to libpng-1.4.0 */ #define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read 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_alloc_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. +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); -struct png_struct_def -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf jmpbuf PNG_DEPSTRUCT; /* used in png_error */ - png_longjmp_ptr longjmp_fn PNG_DEPSTRUCT;/* setjmp non-local goto - function. */ -#endif - png_error_ptr error_fn PNG_DEPSTRUCT; /* function for printing - errors and aborting */ - png_error_ptr warning_fn PNG_DEPSTRUCT; /* function for printing - warnings */ - png_voidp error_ptr PNG_DEPSTRUCT; /* user supplied struct for - error functions */ - png_rw_ptr write_data_fn PNG_DEPSTRUCT; /* function for writing - output data */ - png_rw_ptr read_data_fn PNG_DEPSTRUCT; /* function for reading - input data */ - png_voidp io_ptr PNG_DEPSTRUCT; /* ptr to application struct - for I/O functions */ - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr read_user_transform_fn PNG_DEPSTRUCT; /* user read - transform */ -#endif - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr write_user_transform_fn PNG_DEPSTRUCT; /* user write - transform */ -#endif - -/* These were added in libpng-1.0.2 */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_voidp user_transform_ptr PNG_DEPSTRUCT; /* user supplied struct - for user transform */ - png_byte user_transform_depth PNG_DEPSTRUCT; /* bit depth of user - transformed pixels */ - png_byte user_transform_channels PNG_DEPSTRUCT; /* channels in user - transformed pixels */ -#endif -#endif - - png_uint_32 mode PNG_DEPSTRUCT; /* tells us where we are in - the PNG file */ - png_uint_32 flags PNG_DEPSTRUCT; /* flags indicating various - things to libpng */ - png_uint_32 transformations PNG_DEPSTRUCT; /* which transformations - to perform */ - - z_stream zstream PNG_DEPSTRUCT; /* pointer to decompression - structure (below) */ - png_bytep zbuf PNG_DEPSTRUCT; /* buffer for zlib */ - png_size_t zbuf_size PNG_DEPSTRUCT; /* size of zbuf */ - int zlib_level PNG_DEPSTRUCT; /* holds zlib compression level */ - int zlib_method PNG_DEPSTRUCT; /* holds zlib compression method */ - int zlib_window_bits PNG_DEPSTRUCT; /* holds zlib compression window - bits */ - int zlib_mem_level PNG_DEPSTRUCT; /* holds zlib compression memory - level */ - int zlib_strategy PNG_DEPSTRUCT; /* holds zlib compression - strategy */ - - png_uint_32 width PNG_DEPSTRUCT; /* width of image in pixels */ - png_uint_32 height PNG_DEPSTRUCT; /* height of image in pixels */ - png_uint_32 num_rows PNG_DEPSTRUCT; /* number of rows in current pass */ - png_uint_32 usr_width PNG_DEPSTRUCT; /* width of row at start of write */ - png_size_t rowbytes PNG_DEPSTRUCT; /* size of row in bytes */ -#if 0 /* Replaced with the following in libpng-1.4.1 */ - png_size_t irowbytes PNG_DEPSTRUCT; -#endif -/* Added in libpng-1.4.1 */ -#ifdef PNG_USER_LIMITS_SUPPORTED - /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk - * can occupy when decompressed. 0 means unlimited. - * We will change the typedef from png_size_t to png_alloc_size_t - * in libpng-1.6.0 - */ - png_alloc_size_t user_chunk_malloc_max PNG_DEPSTRUCT; -#endif - png_uint_32 iwidth PNG_DEPSTRUCT; /* width of current interlaced - row in pixels */ - png_uint_32 row_number PNG_DEPSTRUCT; /* current row in interlace pass */ - png_bytep prev_row PNG_DEPSTRUCT; /* buffer to save previous - (unfiltered) row */ - png_bytep row_buf PNG_DEPSTRUCT; /* buffer to save current - (unfiltered) row */ - png_bytep sub_row PNG_DEPSTRUCT; /* buffer to save "sub" row - when filtering */ - png_bytep up_row PNG_DEPSTRUCT; /* buffer to save "up" row - when filtering */ - png_bytep avg_row PNG_DEPSTRUCT; /* buffer to save "avg" row - when filtering */ - png_bytep paeth_row PNG_DEPSTRUCT; /* buffer to save "Paeth" row - when filtering */ - png_row_info row_info PNG_DEPSTRUCT; /* used for transformation - routines */ - - png_uint_32 idat_size PNG_DEPSTRUCT; /* current IDAT size for read */ - png_uint_32 crc PNG_DEPSTRUCT; /* current chunk CRC value */ - png_colorp palette PNG_DEPSTRUCT; /* palette from the input file */ - png_uint_16 num_palette PNG_DEPSTRUCT; /* number of color entries in - palette */ - png_uint_16 num_trans PNG_DEPSTRUCT; /* number of transparency values */ - png_byte chunk_name[5] PNG_DEPSTRUCT; /* null-terminated name of current - chunk */ - png_byte compression PNG_DEPSTRUCT; /* file compression type - (always 0) */ - png_byte filter PNG_DEPSTRUCT; /* file filter type (always 0) */ - png_byte interlaced PNG_DEPSTRUCT; /* PNG_INTERLACE_NONE, - PNG_INTERLACE_ADAM7 */ - png_byte pass PNG_DEPSTRUCT; /* current interlace pass (0 - 6) */ - png_byte do_filter PNG_DEPSTRUCT; /* row filter flags (see - PNG_FILTER_ below ) */ - png_byte color_type PNG_DEPSTRUCT; /* color type of file */ - png_byte bit_depth PNG_DEPSTRUCT; /* bit depth of file */ - png_byte usr_bit_depth PNG_DEPSTRUCT; /* bit depth of users row */ - png_byte pixel_depth PNG_DEPSTRUCT; /* number of bits per pixel */ - png_byte channels PNG_DEPSTRUCT; /* number of channels in file */ - png_byte usr_channels PNG_DEPSTRUCT; /* channels at start of write */ - png_byte sig_bytes PNG_DEPSTRUCT; /* magic bytes read/written from - start of file */ - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) - png_uint_16 filler PNG_DEPSTRUCT; /* filler bytes for pixel - expansion */ -#endif - -#ifdef PNG_bKGD_SUPPORTED - png_byte background_gamma_type PNG_DEPSTRUCT; -# ifdef PNG_FLOATING_POINT_SUPPORTED - float background_gamma PNG_DEPSTRUCT; -# endif - png_color_16 background PNG_DEPSTRUCT; /* background color in - screen gamma space */ -#ifdef PNG_READ_GAMMA_SUPPORTED - png_color_16 background_1 PNG_DEPSTRUCT; /* background normalized - to gamma 1.0 */ -#endif -#endif /* PNG_bKGD_SUPPORTED */ - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_flush_ptr output_flush_fn PNG_DEPSTRUCT; /* Function for flushing - output */ - png_uint_32 flush_dist PNG_DEPSTRUCT; /* how many rows apart to flush, - 0 - no flush */ - png_uint_32 flush_rows PNG_DEPSTRUCT; /* number of rows written since - last flush */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - int gamma_shift PNG_DEPSTRUCT; /* number of "insignificant" bits - 16-bit gamma */ -#ifdef PNG_FLOATING_POINT_SUPPORTED - float gamma PNG_DEPSTRUCT; /* file gamma value */ - float screen_gamma PNG_DEPSTRUCT; /* screen gamma value - (display_exponent) */ -#endif -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_table PNG_DEPSTRUCT; /* gamma table for 8-bit - depth files */ - png_bytep gamma_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to screen */ - png_bytep gamma_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_table PNG_DEPSTRUCT; /* gamma table for 16-bit - depth files */ - png_uint_16pp gamma_16_from_1 PNG_DEPSTRUCT; /* converts from 1.0 to - screen */ - png_uint_16pp gamma_16_to_1 PNG_DEPSTRUCT; /* converts from file to 1.0 */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) - png_color_8 sig_bit PNG_DEPSTRUCT; /* significant bits in each - available channel */ -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift PNG_DEPSTRUCT; /* 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_alpha PNG_DEPSTRUCT; /* alpha values for - paletted files */ - png_color_16 trans_color PNG_DEPSTRUCT; /* transparent color for - non-paletted files */ -#endif - - png_read_status_ptr read_row_fn PNG_DEPSTRUCT; /* called after each - row is decoded */ - png_write_status_ptr write_row_fn PNG_DEPSTRUCT; /* called after each - row is encoded */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn PNG_DEPSTRUCT; /* called after header - data fully read */ - png_progressive_row_ptr row_fn PNG_DEPSTRUCT; /* called after each - prog. row is decoded */ - png_progressive_end_ptr end_fn PNG_DEPSTRUCT; /* called after image - is complete */ - png_bytep save_buffer_ptr PNG_DEPSTRUCT; /* current location in - save_buffer */ - png_bytep save_buffer PNG_DEPSTRUCT; /* buffer for previously - read data */ - png_bytep current_buffer_ptr PNG_DEPSTRUCT; /* current location in - current_buffer */ - png_bytep current_buffer PNG_DEPSTRUCT; /* buffer for recently - used data */ - png_uint_32 push_length PNG_DEPSTRUCT; /* size of current input - chunk */ - png_uint_32 skip_length PNG_DEPSTRUCT; /* bytes to skip in - input data */ - png_size_t save_buffer_size PNG_DEPSTRUCT; /* amount of data now - in save_buffer */ - png_size_t save_buffer_max PNG_DEPSTRUCT; /* total size of - save_buffer */ - png_size_t buffer_size PNG_DEPSTRUCT; /* total amount of - available input data */ - png_size_t current_buffer_size PNG_DEPSTRUCT; /* amount of data now - in current_buffer */ - int process_mode PNG_DEPSTRUCT; /* what push library - is currently doing */ - int cur_palette PNG_DEPSTRUCT; /* current push library - palette index */ - -# ifdef PNG_TEXT_SUPPORTED - png_size_t current_text_size PNG_DEPSTRUCT; /* current size of - text input data */ - png_size_t current_text_left PNG_DEPSTRUCT; /* how much text left - to read in input */ - png_charp current_text PNG_DEPSTRUCT; /* current text chunk - buffer */ - png_charp current_text_ptr PNG_DEPSTRUCT; /* 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_DEPSTRUCT; - png_bytep offset_table PNG_DEPSTRUCT; - png_uint_16 offset_table_number PNG_DEPSTRUCT; - png_uint_16 offset_table_count PNG_DEPSTRUCT; - png_uint_16 offset_table_count_free PNG_DEPSTRUCT; -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - png_bytep palette_lookup PNG_DEPSTRUCT; /* lookup table for quantizing */ - png_bytep quantize_index PNG_DEPSTRUCT; /* index translation for palette - files */ -#endif - -#if defined(PNG_READ_QUANTIZE_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist PNG_DEPSTRUCT; /* histogram */ -#endif - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_byte heuristic_method PNG_DEPSTRUCT; /* heuristic for row - filter selection */ - png_byte num_prev_filters PNG_DEPSTRUCT; /* number of weights - for previous rows */ - png_bytep prev_filters PNG_DEPSTRUCT; /* filter type(s) of - previous row(s) */ - png_uint_16p filter_weights PNG_DEPSTRUCT; /* weight(s) for previous - line(s) */ - png_uint_16p inv_filter_weights PNG_DEPSTRUCT; /* 1/weight(s) for - previous line(s) */ - png_uint_16p filter_costs PNG_DEPSTRUCT; /* relative filter - calculation cost */ - png_uint_16p inv_filter_costs PNG_DEPSTRUCT; /* 1/relative filter - calculation cost */ -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_charp time_buffer PNG_DEPSTRUCT; /* String to hold RFC 1123 time text */ -#endif - -/* New members added in libpng-1.0.6 */ - - png_uint_32 free_me PNG_DEPSTRUCT; /* flags items libpng is - responsible for freeing */ - -#ifdef PNG_USER_CHUNKS_SUPPORTED - png_voidp user_chunk_ptr PNG_DEPSTRUCT; - png_user_chunk_ptr read_user_chunk_fn PNG_DEPSTRUCT; /* user read - chunk handler */ -#endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int num_chunk_list PNG_DEPSTRUCT; - png_bytep chunk_list PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.0.3 */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - png_byte rgb_to_gray_status PNG_DEPSTRUCT; - /* These were changed from png_byte in libpng-1.0.6 */ - png_uint_16 rgb_to_gray_red_coeff PNG_DEPSTRUCT; - png_uint_16 rgb_to_gray_green_coeff PNG_DEPSTRUCT; - png_uint_16 rgb_to_gray_blue_coeff PNG_DEPSTRUCT; -#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_uint_32 mng_features_permitted PNG_DEPSTRUCT; -#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 PNG_DEPSTRUCT; -#endif - -/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_byte filter_type PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.2.0 */ - -/* 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 PNG_DEPSTRUCT; /* user supplied struct for - mem functions */ - png_malloc_ptr malloc_fn PNG_DEPSTRUCT; /* function for - allocating memory */ - png_free_ptr free_fn PNG_DEPSTRUCT; /* function for - freeing memory */ -#endif - -/* New member added in libpng-1.0.13 and 1.2.0 */ - png_bytep big_row_buf PNG_DEPSTRUCT; /* buffer to save current - (unfiltered) row */ - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -/* The following three members were added at version 1.0.14 and 1.2.4 */ - png_bytep quantize_sort PNG_DEPSTRUCT; /* working sort array */ - png_bytep index_to_palette PNG_DEPSTRUCT; /* where the original - index currently is - in the palette */ - png_bytep palette_to_index PNG_DEPSTRUCT; /* which original index - points to this - palette color */ -#endif - -/* New members added in libpng-1.0.16 and 1.2.6 */ - png_byte compression_type PNG_DEPSTRUCT; - -#ifdef PNG_USER_LIMITS_SUPPORTED - png_uint_32 user_width_max PNG_DEPSTRUCT; - png_uint_32 user_height_max PNG_DEPSTRUCT; - /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown - * chunks that can be stored (0 means unlimited). - */ - png_uint_32 user_chunk_cache_max PNG_DEPSTRUCT; -#endif - -/* New member added in libpng-1.0.25 and 1.2.17 */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - /* Storage for unknown chunk that the library doesn't recognize. */ - png_unknown_chunk unknown_chunk PNG_DEPSTRUCT; -#endif - -/* New members added in libpng-1.2.26 */ - png_uint_32 old_big_row_buf_size PNG_DEPSTRUCT; - png_uint_32 old_prev_row_size PNG_DEPSTRUCT; - -/* New member added in libpng-1.2.30 */ - png_charp chunkdata PNG_DEPSTRUCT; /* buffer for reading chunk data */ - -#ifdef PNG_IO_STATE_SUPPORTED -/* New member added in libpng-1.4.0 */ - png_uint_32 io_state PNG_DEPSTRUCT; -#endif -}; - - -/* This triggers a compiler error in png.c, if png.c and png.h - * do not agree upon the version number. - */ -typedef png_structp version_1_4_4; - -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 +/* Section 3: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.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. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes */ /* Returns the version number of the library */ -PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); +PNG_EXPORT(1, png_uint_32, png_access_version_number, (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. */ -PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, - int num_bytes)); +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp 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). */ -PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, - png_size_t num_to_check)); +PNG_EXPORT(3, int, png_sig_cmp, (png_const_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). */ -#define png_check_sig(sig,n) !png_sig_cmp((sig), 0, (n)) +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) /* Allocate and initialize png_ptr struct for reading, and any other memory. */ -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)) PNG_ALLOCATED; +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); /* Allocate and initialize png_ptr struct for writing, and any other memory */ -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)) PNG_ALLOCATED; +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); -PNG_EXPORT(png_size_t,png_get_compression_buffer_size) - PNGARG((png_structp png_ptr)); +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); -PNG_EXPORT(void,png_set_compression_buffer_size) - PNGARG((png_structp png_ptr, png_size_t size)); +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_size_t size)); /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp * match up. @@ -1535,288 +1089,484 @@ PNG_EXPORT(void,png_set_compression_buffer_size) * allocated by the library - the call will return NULL on a mismatch * indicating an ABI mismatch. */ -PNG_EXPORT(jmp_buf*, png_set_longjmp_fn) - PNGARG((png_structp png_ptr, png_longjmp_ptr longjmp_fn, size_t - jmp_buf_size)); +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); # define png_jmpbuf(png_ptr) \ - (*png_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) #else # define png_jmpbuf(png_ptr) \ - (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) #endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); #ifdef PNG_READ_SUPPORTED /* Reset the compression stream */ -PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); #endif /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ #ifdef PNG_USER_MEM_SUPPORTED -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)) PNG_ALLOCATED; -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)) PNG_ALLOCATED; +PNG_EXPORTA(11, png_structp, 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), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, 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), + PNG_ALLOCATED); #endif /* Write the PNG file signature. */ -PNG_EXPORT(void,png_write_sig) PNGARG((png_structp png_ptr)); +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); /* Write a PNG chunk - size, type, (optional) data, CRC. */ -PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_bytep data, png_size_t length)); +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); /* Write the start of a PNG chunk - length and chunk name. */ -PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_uint_32 length)); +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); /* Write the data of a PNG chunk started with png_write_chunk_start(). */ -PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, png_size_t length)); /* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); /* Allocate and initialize the info structure */ -PNG_EXPORT(png_infop,png_create_info_struct) - PNGARG((png_structp png_ptr)) PNG_ALLOCATED; +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); -PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, - png_size_t png_info_struct_size)); +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); /* Writes all the PNG information before the image. */ -PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. */ -PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXPORT(22, void, png_read_info, + (png_structrp png_ptr, png_inforp info_ptr)); #endif #ifdef PNG_TIME_RFC1123_SUPPORTED -PNG_EXPORT(png_charp,png_convert_to_rfc1123) - PNGARG((png_structp png_ptr, png_timep ptime)); + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); #endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Convert from a struct tm to png_time */ -PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, - struct tm FAR * ttime)); +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); /* Convert from time_t to png_time. Uses gmtime() */ -PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, - time_t ttime)); -#endif /* PNG_CONVERT_tIME_SUPPORTED */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* CONVERT_tIME */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); -PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp - png_ptr)); -PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); -PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ -PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand the grayscale to 24-bit RGB if necessary. */ -PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB to grayscale. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, - int error_action, double red, double green )); -#endif -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 )); -PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp - png_ptr)); +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); #endif -PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, - png_colorp palette)); +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels + * of a PNG file are returned to the calling application when an alpha channel, + * or a tRNS chunk in a palette file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel, and the color channels are unassociated + * (not premultiplied). The gamma encoded color channels must be scaled + * according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. + * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes + * (the latter being the two common names for associated alpha color channels). + * + * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha + * value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); +PNG_EXPORT(39, void, png_set_filler, (png_structrp 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 +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 /* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* READ_FILLER || WRITE_FILLER */ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swap bytes in 16-bit depth files. */ -PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +PNG_EXPORT(41, void, png_set_swap, (png_structrp 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. */ -PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Swap packing order of pixels in bytes. */ -PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) /* Converts files to legal bit depths. */ -PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, - png_color_8p true_bits)); +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_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. */ -PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) /* Invert monochrome files */ -PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS by replacing with a background color. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -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)); +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point 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 +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# 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 -#ifdef PNG_READ_16_TO_8_SUPPORTED +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ /* Strip the second byte of information from a 16-bit depth file. */ -PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Turn on quantizing, and reduce the palette to the number of colors - * available. Prior to libpng-1.4.2, this was png_set_dither(). + * available. */ -PNG_EXPORT(void,png_set_quantize) PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette, int maximum_colors, - png_uint_16p histogram, int full_quantize)); +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); #endif -/* This migration aid will be removed from libpng-1.5.0 */ -#define png_set_dither png_set_quantize #ifdef PNG_READ_GAMMA_SUPPORTED -/* Handle gamma correction. Screen_gamma=(display_exponent) */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, - double screen_gamma, double default_file_gamma)); -#endif -#endif +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) +#endif #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set how many lines between output flushes - 0 for no flushing */ -PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); /* Flush the current PNG output buffer */ -PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); #endif /* Optional update palette with requested transformations */ -PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); /* Optional call to update the users info structure */ -PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. */ -PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read a row of data. */ -PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, - png_bytep row, - png_bytep display_row)); +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the whole image into memory at once. */ -PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, - png_bytepp image)); +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); #endif /* Write a row of image data */ -PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, - png_bytep row)); +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); -/* Write a few rows of image data */ -PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_uint_32 num_rows)); +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); /* Write the image data */ -PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, - png_bytepp image)); +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); /* Write the end of the PNG file. */ -PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. */ -PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); #endif /* Free any memory associated with the png_info_struct */ -PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, - png_infopp info_ptr_ptr)); +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp - png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(void,png_destroy_write_struct) - PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); /* Set the libpng method of handling chunk CRC errors */ -PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, - int crit_action, int ancil_action)); +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); -/* Values for png_set_crc_action() to say how to handle CRC errors in +/* Values for png_set_crc_action() 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, @@ -1832,6 +1582,7 @@ PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ +#ifdef PNG_WRITE_SUPPORTED /* 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. @@ -1843,8 +1594,9 @@ PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, /* Set the filtering method(s) used by libpng. Currently, the only valid * value for "method" is 0. */ -PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, - int filters)); +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); +#endif /* WRITE */ /* 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 @@ -1870,6 +1622,7 @@ PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 +#ifdef PNG_WRITE_SUPPORTED #ifdef 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 @@ -1899,12 +1652,14 @@ PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, * 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 -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 */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)) +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* WRITE_WEIGHTED_FILTER */ /* Heuristic used for row filter selection. These defines should NOT be * changed. @@ -1921,34 +1676,60 @@ PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ -PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, - int level)); +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); -PNG_EXPORT(void,png_set_compression_mem_level) - PNGARG((png_structp png_ptr, int mem_level)); +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); -PNG_EXPORT(void,png_set_compression_strategy) - PNGARG((png_structp png_ptr, int strategy)); +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); -PNG_EXPORT(void,png_set_compression_window_bits) - PNGARG((png_structp png_ptr, int window_bits)); +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); -PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, - int method)); +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* WRITE */ /* 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 + * different manner by calling png_set_???_fn(). See libpng-manual.txt for * more information. */ #ifdef PNG_STDIO_SUPPORTED /* Initialize the input/output for the PNG file to the default functions. */ -PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, - png_FILE_p fp)); +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); #endif /* Replace the (error and abort), and warning functions with user @@ -1959,11 +1740,11 @@ PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, * default function will be used. */ -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)); +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp 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 */ -PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp 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. @@ -1975,101 +1756,162 @@ PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); * default flush function, which uses the standard *FILE structure, will * be used. */ -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)); +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp 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. */ -PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, png_rw_ptr read_data_fn)); +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); /* Return the user pointer associated with the I/O functions */ -PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); -PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, - png_read_status_ptr read_row_fn)); +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); -PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, - png_write_status_ptr write_row_fn)); +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp 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). */ -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)); +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp 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 */ -PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr read_user_transform_fn)); +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr write_user_transform_fn)); +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); #endif -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -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)); +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp 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 */ -PNG_EXPORT(png_voidp,png_get_user_transform_ptr) - PNGARG((png_structp png_ptr)); +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED -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)); -PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp - png_ptr)); +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp 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. */ -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)); +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp 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 */ -PNG_EXPORT(png_voidp,png_get_progressive_ptr) - PNGARG((png_structp png_ptr)); +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); /* Function to be called when data becomes available */ -PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp 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????? +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. */ -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 */ +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); -PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, - png_alloc_size_t size)) PNG_ALLOCATED; +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); + +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PROGRESSIVE_READ */ + +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.4.0 */ -PNG_EXPORT(png_voidp,png_calloc) PNGARG((png_structp png_ptr, - png_alloc_size_t size)) PNG_ALLOCATED; +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.2.4 */ -PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, - png_alloc_size_t size)) PNG_ALLOCATED; +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Frees a pointer allocated by png_malloc() */ -PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); /* Free data that was allocated internally */ -PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 free_me, int num)); +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); + /* Reassign responsibility for freeing existing data, whether allocated - * by libpng or by the application */ -PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, - png_infop info_ptr, int freer, png_uint_32 mask)); + * by libpng or by the application; this works on the png_info structure passed + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. + */ +PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask)); + /* Assignments for png_data_freer */ #define PNG_DESTROY_WILL_FREE_DATA 1 #define PNG_SET_WILL_FREE_DATA 1 @@ -2081,8 +1923,10 @@ PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, #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 +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200 +#endif +/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ #define PNG_FREE_PLTE 0x1000 #define PNG_FREE_TRNS 0x2000 #define PNG_FREE_TEXT 0x4000 @@ -2090,46 +1934,63 @@ PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, #define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED -PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, - png_alloc_size_t size)) PNG_ALLOCATED; -PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, - png_voidp ptr)); +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); #endif -#ifndef PNG_NO_ERROR_TEXT +#ifdef PNG_ERROR_TEXT_SUPPORTED /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); /* The same, but the chunk name is prepended to the error string. */ -PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); #else /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr)) PNG_NORETURN; +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) #endif +#ifdef PNG_WARNINGS_SUPPORTED /* Non-fatal error in libpng. Can continue, but may have a problem. */ -PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); /* Non-fatal error in libpng, chunk name is prepended to message. */ -PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +#endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Benign error in libpng. Can continue, but may have a problem. * User can choose whether to handle as a fatal error or as a warning. */ -PNG_EXPORT(void,png_benign_error) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); -/* Same, chunk name is prepended to message. */ -PNG_EXPORT(void,png_chunk_benign_error) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif -PNG_EXPORT(void,png_set_benign_errors) PNGARG((png_structp - png_ptr, int allowed)); +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif #endif /* The png_set_ functions are for storing values in the png_info_struct. @@ -2145,258 +2006,274 @@ PNG_EXPORT(void,png_set_benign_errors) PNGARG((png_structp * png_info_struct. */ /* Returns "flag" if chunk data is valid in info_ptr. */ -PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 flag)); +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); /* Returns number of bytes needed to hold a transformed row. */ -PNG_EXPORT(png_size_t,png_get_rowbytes) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* Returns row_pointers, which is an array of pointers to scanlines that was * returned from png_read_png(). */ -PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + /* Set row_pointers, which is an array of pointers to scanlines for use * by png_write_png(). */ -PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytepp row_pointers)); +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); #endif /* Returns number of color channels in image. */ -PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_EASY_ACCESS_SUPPORTED /* Returns image width in pixels. */ -PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image height in pixels. */ -PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image bit_depth. */ -PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image color_type. */ -PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image filter_type. */ -PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image interlace_type. */ -PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image compression_type. */ -PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image resolution in pixels per meter, from pHYs chunk data. */ -PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -#endif +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ -PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -#endif /* PNG_EASY_ACCESS_SUPPORTED */ +#endif /* EASY_ACCESS */ +#ifdef PNG_READ_SUPPORTED /* Returns pointer to signature string read from PNG header */ -PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p *background)); +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #endif #ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p background)); +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); #endif #ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -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 -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 +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp 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_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structrp png_ptr, png_const_inforp 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)) +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)) #endif #ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -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 -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 +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp 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_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp 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)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)) #endif #ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double *file_gamma)); -#endif -PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point *int_file_gamma)); +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) #endif #ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double file_gamma)); -#endif -PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_file_gamma)); +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) #endif #ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p *hist)); +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); #endif #ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p hist)); +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); #endif -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)); +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp 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)); -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)); +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp 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)); #ifdef PNG_oFFs_SUPPORTED -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, +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)); #endif #ifdef PNG_oFFs_SUPPORTED -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)); +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); #endif #ifdef PNG_pCAL_SUPPORTED -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)); +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); #endif #ifdef PNG_pCAL_SUPPORTED -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)); +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); #endif #ifdef PNG_pHYs_SUPPORTED -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)); +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); #endif #ifdef PNG_pHYs_SUPPORTED -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)); +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); #endif -PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp *palette, int *num_palette)); +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); -PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp palette, int num_palette)); +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p *sig_bit)); +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); #endif #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p sig_bit)); +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *intent)); +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); -PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); #endif #ifdef PNG_iCCP_SUPPORTED -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 */ +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); #endif #ifdef PNG_iCCP_SUPPORTED -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 */ +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tpp entries)); +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tp entries, int nentries)); +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); #endif #ifdef PNG_TEXT_SUPPORTED /* png_get_text also returns the number of text chunks in *num_text */ -PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp *text_ptr, int *num_text)); +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); #endif /* Note while png_set_text() will accept a structure whose text, @@ -2407,111 +2284,221 @@ PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, */ #ifdef PNG_TEXT_SUPPORTED -PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep *mod_time)); +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep mod_time)); +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); #endif #ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep *trans_alpha, int *num_trans, - png_color_16p *trans_color)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep trans_alpha, int num_trans, - png_color_16p trans_color)); +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); #endif #ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); #endif #ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -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 -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)); +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) #endif -#endif -#endif /* PNG_sCAL_SUPPORTED */ +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); -#ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, double width, double height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -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 -#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* sCAL */ -#ifdef PNG_HANDLE_AS_UNKNOWN_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 behaviour - = 1: do not keep - = 2: keep only if safe-to-copy - = 3: keep even if unsafe-to-copy -*/ -PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp - png_ptr, int keep, png_bytep chunk_list, int num_chunks)); -PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep - chunk_name)); +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WTIH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); -PNG_EXPORT(void, png_set_unknown_chunk_location) - PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); -PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp - png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp 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); */ -PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, - png_infop info_ptr, int mask)); +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* The "params" pointer is currently not used and is for future expansion. */ -PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); -PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif +#ifdef PNG_WRITE_SUPPORTED +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif #endif -PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); -PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); -PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp - png_ptr)); -PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structrp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structrp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structrp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structrp png_ptr)); #ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp - png_ptr, png_uint_32 mng_features_permitted)); +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); #endif /* For use in png_set_keep_unknown, added to version 1.2.6 */ @@ -2519,79 +2506,151 @@ PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp #define PNG_HANDLE_CHUNK_NEVER 1 #define PNG_HANDLE_CHUNK_IF_SAFE 2 #define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 /* 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 -PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp - png_ptr, png_uint_32 strip_mode)); +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); #endif /* Added in libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED -PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp - png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); -PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp - png_ptr)); -PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp - png_ptr)); +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structrp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structrp png_ptr)); /* Added in libpng-1.4.0 */ -PNG_EXPORT(void,png_set_chunk_cache_max) PNGARG((png_structp - png_ptr, png_uint_32 user_chunk_cache_max)); -PNG_EXPORT(png_uint_32,png_get_chunk_cache_max) - PNGARG((png_structp png_ptr)); +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structrp png_ptr)); /* Added in libpng-1.4.1 */ -PNG_EXPORT(void,png_set_chunk_malloc_max) PNGARG((png_structp - png_ptr, png_alloc_size_t user_chunk_cache_max)); -PNG_EXPORT(png_alloc_size_t,png_get_chunk_malloc_max) - PNGARG((png_structp png_ptr)); +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structrp png_ptr)); #endif -#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) -PNG_EXPORT(png_uint_32,png_get_pixels_per_inch) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(png_uint_32,png_get_x_pixels_per_inch) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(png_uint_32,png_get_y_pixels_per_inch) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(float,png_get_x_offset_inches) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif -PNG_EXPORT(float,png_get_y_offset_inches) PNGARG((png_structp png_ptr, -png_infop info_ptr)); +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif -#ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_pHYs_dpi) PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ /* Added in libpng-1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED -PNG_EXPORT(png_uint_32,png_get_io_state) PNGARG((png_structp png_ptr)); +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); -PNG_EXPORT(png_bytep,png_get_io_chunk_name) - PNGARG((png_structp png_ptr)); +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) + +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structrp png_ptr)); /* The flags returned by png_get_io_state() are the following: */ -#define PNG_IO_NONE 0x0000 /* no I/O at this moment */ -#define PNG_IO_READING 0x0001 /* currently reading */ -#define PNG_IO_WRITING 0x0002 /* currently writing */ -#define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ -#define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ -#define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ -#define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ -#define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ -#define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ -#endif /* ?PNG_IO_STATE_SUPPORTED */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* IO_STATE */ -/* Maintainer: Put new public prototypes here ^, in libpng.3, and project - * defs +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ + (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) #ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED /* With these routines we avoid an integer divide, which will be slower on @@ -2606,89 +2665,623 @@ PNG_EXPORT(png_bytep,png_get_io_chunk_name) * [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 */ + /* 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); } + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); } # 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); } + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)(0xffff & ((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(composite, fg, alpha, bg) \ + (composite) = \ + (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 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 */ + (composite) = \ + (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535)) +#endif /* READ_COMPOSITE_NODIV */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (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. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif #ifdef PNG_USE_READ_MACROS /* Inline macros to do direct reads of bytes from the input buffer. * The png_get_int_32() routine assumes we are using two's complement * format for negative values, which is almost certainly true. */ -# define png_get_uint_32(buf) \ +# define PNG_get_uint_32(buf) \ (((png_uint_32)(*(buf)) << 24) + \ ((png_uint_32)(*((buf) + 1)) << 16) + \ ((png_uint_32)(*((buf) + 2)) << 8) + \ ((png_uint_32)(*((buf) + 3)))) -# define png_get_uint_16(buf) \ - (((png_uint_32)(*(buf)) << 8) + \ - ((png_uint_32)(*((buf) + 1)))) -# define png_get_int_32(buf) \ + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define PNG_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define PNG_get_int_32(buf) \ ((png_int_32)((*(buf) & 0x80) \ - ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffff)+1)) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ : (png_int_32)png_get_uint_32(buf))) + + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif #else -PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf)); -PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf)); -#ifdef PNG_GET_INT_32_SUPPORTED -PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf)); +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif #endif + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/******************************************************************************* + * SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accomodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack and set the + * version field to PNG_IMAGE_VERSION. + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two-bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled, if you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ #endif -PNG_EXPORT(png_uint_32,png_get_uint_31) - PNGARG((png_structp png_ptr, png_bytep buf)); -/* No png_get_int_16 -- may be added if there's a real need for it. */ -/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ -PNG_EXPORT(void,png_save_uint_32) - PNGARG((png_bytep buf, png_uint_32 i)); -PNG_EXPORT(void,png_save_int_32) - PNGARG((png_bytep buf, png_int_32 i)); +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#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. +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: */ -PNG_EXPORT(void,png_save_uint_16) - PNGARG((png_bytep buf, unsigned int i)); -/* No png_save_int_16 -- may be added if there's a real need for it. */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) -/* ************************************************************************* */ - -/* Various modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 -#define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ -#define PNG_HAVE_IEND 0x10 -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates the the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* STDIO */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* SIMPLIFIED_READ */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given (FILE*). */ + +/* With both write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. + * + * Note that the write API does not support interlacing or sub-8-bit pixels. + */ +#endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ +#endif /* SIMPLIFIED_{READ|WRITE} */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ +#endif +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ +#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */ + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif /* SET_OPTION */ + +/******************************************************************************* + * END OF HARDWARE AND SOFTWARE OPTIONS + ******************************************************************************/ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, in project + * defs, and in scripts/symbols.def. + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(244); +#endif #ifdef __cplusplus } diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h index 41b13e9f..3f9493e4 100644 --- a/thirdparty/libpng/pngconf.h +++ b/thirdparty/libpng/pngconf.h @@ -1,9 +1,9 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.4.4 - September 23, 2010 - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * libpng version 1.6.17, March 26, 2015 + * + * Copyright (c) 1998-2015 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.) * @@ -11,9 +11,7 @@ * For conditions of distribution and use, see the disclaimer * and license in png.h * - */ - -/* Any machine specific code is near the front of this file, so if you + * 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. @@ -22,1334 +20,304 @@ #ifndef PNGCONF_H #define PNGCONF_H -#ifndef PNG_NO_LIMITS_H -# include -#endif +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ -/* Added at libpng-1.2.9 */ - -/* config.h is created by and PNG_CONFIGURE_LIBPNG is set by the "configure" - * script. +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. */ -#ifdef PNG_CONFIGURE_LIBPNG -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif -#endif +#include +#include -/* - * Added at libpng-1.2.8 +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. * - * PNG_USER_CONFIG has to be defined on the compiler command line. This - * includes the resource compiler for Windows DLL configurations. - */ -#ifdef PNG_USER_CONFIG -# include "pngusr.h" -# ifndef PNG_USER_PRIVATEBUILD -# define PNG_USER_PRIVATEBUILD -# endif -#endif - -/* - * If you create a private DLL you should define in "pngusr.h" the following: - * #define PNG_USER_PRIVATEBUILD - * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." - * #define PNG_USER_DLLFNAME_POSTFIX - * e.g. // private DLL "libpng14gx.dll" - * #define PNG_USER_DLLFNAME_POSTFIX "gx" - * - * The following macros are also at your disposal if you want to complete the - * DLL VERSIONINFO structure. - * - PNG_USER_VERSIONINFO_COMMENTS - * - PNG_USER_VERSIONINFO_COMPANYNAME - * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. */ -#ifdef __STDC__ -# ifdef SPECIALBUILD -# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ - are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") -# endif - -# ifdef PRIVATEBUILD -# pragma message("PRIVATEBUILD is deprecated.\ - Use PNG_USER_PRIVATEBUILD instead.") -# define PNG_USER_PRIVATEBUILD PRIVATEBUILD -# endif -#endif /* __STDC__ */ - -/* End of material added to libpng-1.2.8 */ - -#ifndef PNG_VERSION_INFO_ONLY - -/* 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 in 1.4.0. */ -#ifdef PNG_ALLOW_BENIGN_ERRORS -# define png_benign_error png_warning -# define png_chunk_benign_error png_chunk_warning -#else -# ifndef PNG_BENIGN_ERRORS_SUPPORTED -# define png_benign_error png_error -# define png_chunk_benign_error png_chunk_error -# endif -#endif - -/* Added at libpng version 1.4.0 */ -#if !defined(PNG_NO_WARNINGS) && !defined(PNG_WARNINGS_SUPPORTED) -# define PNG_WARNINGS_SUPPORTED -#endif - -/* Added at libpng version 1.4.0 */ -#if !defined(PNG_NO_ERROR_TEXT) && !defined(PNG_ERROR_TEXT_SUPPORTED) -# define PNG_ERROR_TEXT_SUPPORTED -#endif - -/* Added at libpng version 1.4.0 */ -#if !defined(PNG_NO_CHECK_cHRM) && !defined(PNG_CHECK_cHRM_SUPPORTED) -# define PNG_CHECK_cHRM_SUPPORTED -#endif - -/* Added at libpng version 1.4.0 */ -#if !defined(PNG_NO_ALIGNED_MEMORY) && !defined(PNG_ALIGNED_MEMORY_SUPPORTED) -# define PNG_ALIGNED_MEMORY_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 - -/* Added at libpng version 1.4.0 */ -#ifndef PNG_NO_FLOATING_POINT_SUPPORTED -# ifndef PNG_FLOATING_POINT_SUPPORTED -# define PNG_FLOATING_POINT_SUPPORTED -# endif -#endif - -/* Added at libpng-1.4.0beta49 for testing (this test is no longer used - in libpng and png_calloc() is always present) - */ -#define PNG_CALLOC_SUPPORTED - -/* 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 -- (ignored) building the dll - * (no define) -- (ignored) building an application, linking to the dll - * PNG_STATIC -- (ignored) building the static lib, or building an - * application that links to the static lib. - * ALL_STATIC -- (ignored) 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 - * - * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent - * of auto-import in binutils, we no longer need to worry about - * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, - * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes - * to __declspec() stuff. However, we DO need to worry about - * PNG_BUILD_DLL and PNG_STATIC because those change some defaults - * such as CONSOLE_IO. - */ -#ifdef __CYGWIN__ -# ifdef ALL_STATIC -# ifdef PNG_BUILD_DLL -# undef PNG_BUILD_DLL -# endif -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifdef PNG_DLL -# undef PNG_DLL -# endif -# ifndef PNG_STATIC -# define PNG_STATIC -# endif -# else -# ifdef PNG_BUILD_DLL -# ifdef PNG_STATIC -# undef PNG_STATIC -# endif -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifndef PNG_DLL -# define PNG_DLL -# endif -# else -# ifdef PNG_STATIC -# ifdef PNG_USE_DLL -# undef PNG_USE_DLL -# endif -# ifdef PNG_DLL -# undef PNG_DLL -# endif -# else -# ifndef PNG_USE_DLL -# define PNG_USE_DLL -# endif -# ifndef 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 - */ - -#ifdef _WIN32_WCE -# define PNG_NO_CONSOLE_IO -# define PNG_NO_STDIO -# define PNG_NO_TIME_RFC1123 -# ifdef PNG_DEBUG -# undef PNG_DEBUG -# endif -#endif - -#if !defined(PNG_NO_STDIO) && !defined(PNG_STDIO_SUPPORTED) -# define PNG_STDIO_SUPPORTED -#endif - -#ifdef PNG_BUILD_DLL -# if !defined(PNG_CONSOLE_IO_SUPPORTED) && !defined(PNG_NO_CONSOLE_IO) -# define PNG_NO_CONSOLE_IO -# 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 -# include -# endif - -#if !(defined PNG_NO_CONSOLE_IO) && !defined(PNG_CONSOLE_IO_SUPPORTED) -# define PNG_CONSOLE_IO_SUPPORTED -#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) -# include -#endif - -/* PNG_SETJMP_NOT_SUPPORTED and PNG_NO_SETJMP_SUPPORTED are deprecated. */ -#if !defined(PNG_NO_SETJMP) && \ - !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) -# define PNG_SETJMP_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include #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. - * - * You can bypass this test if you know that your application uses exactly - * the same setjmp.h that was included when libpng was built. Only define - * PNG_SKIP_SETJMP_CHECK while building your application, prior to the - * application's '#include "png.h"'. Don't define PNG_SKIP_SETJMP_CHECK - * while building a separate libpng library for general use. - */ - -# ifndef PNG_SKIP_SETJMP_CHECK -# ifdef __linux__ -# ifdef _BSD_SOURCE -# define PNG_SAVE_BSD_SOURCE -# undef _BSD_SOURCE -# endif -# ifdef _SETJMP_H - /* If you encounter a compiler error here, see the explanation - * near the end of INSTALL. - */ - __pngconf.h__ in libpng already includes setjmp.h; - __dont__ include it again.; -# endif -# endif /* __linux__ */ -# endif /* PNG_SKIP_SETJMP_CHECK */ - - /* Include setjmp.h for error handling */ + /* Required for the definition of jmp_buf and the declaration of longjmp: */ # include - -# ifdef __linux__ -# ifdef PNG_SAVE_BSD_SOURCE -# ifdef _BSD_SOURCE -# undef _BSD_SOURCE -# endif -# 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_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif -/* This controls how fine the quantizing gets. As this allocates - * a largish chunk of memory (32K), those who are not as concerned - * with quantizing quality can decrease some or all of these. +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. */ +#define PNG_CONST const /* backward compatibility only */ -/* Prior to libpng-1.4.2, these were PNG_DITHER_*_BITS - * These migration aids will be removed from libpng-1.5.0. +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. */ -#ifdef PNG_DITHER_RED_BITS -# define PNG_QUANTIZE_RED_BITS PNG_DITHER_RED_BITS -#endif -#ifdef PNG_DITHER_GREEN_BITS -# define PNG_QUANTIZE_GREEN_BITS PNG_DITHER_GREEN_BITS -#endif -#ifdef PNG_DITHER_BLUE_BITS -# define PNG_QUANTIZE_BLUE_BITS PNG_DITHER_BLUE_BITS -#endif - -#ifndef PNG_QUANTIZE_RED_BITS -# define PNG_QUANTIZE_RED_BITS 5 -#endif -#ifndef PNG_QUANTIZE_GREEN_BITS -# define PNG_QUANTIZE_GREEN_BITS 5 -#endif -#ifndef PNG_QUANTIZE_BLUE_BITS -# define PNG_QUANTIZE_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 - -/* 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. - */ - -#ifndef PNG_CONST -# ifndef PNG_NO_CONST -# define PNG_CONST const -# else -# define PNG_CONST -# endif -#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 an #undef, or pass in PNG_NO_feature 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 PNG_NO_READ|WRITE_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 PNG_NO_READ|WRITE_TRANSFORMS - * 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; PNG_*_TRANSFORMS_NOT_SUPPORTED deprecated in - * 1.4.0) - */ - -/* 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 - -#ifdef PNG_READ_SUPPORTED - -/* PNG_READ_TRANSFORMS_NOT_SUPPORTED is deprecated. */ -#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_QUANTIZE - /* Prior to libpng-1.4.0 this was PNG_READ_DITHER_SUPPORTED */ -# ifndef PNG_NO_READ_DITHER /* This migration aid will be removed */ -# define PNG_READ_QUANTIZE_SUPPORTED -# endif -# 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 */ - -/* PNG_PROGRESSIVE_READ_NOT_SUPPORTED is deprecated. */ -#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 define: */ - -#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ - -/* PNG_NO_SEQUENTIAL_READ_SUPPORTED is deprecated. */ -#if !defined(PNG_NO_SEQUENTIAL_READ) && \ - !defined(PNG_SEQUENTIAL_READ_SUPPORTED) && \ - !defined(PNG_NO_SEQUENTIAL_READ_SUPPORTED) -# define PNG_SEQUENTIAL_READ_SUPPORTED -#endif - -#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 - -#if !defined(PNG_NO_GET_INT_32) || defined(PNG_READ_oFFS_SUPPORTED) || \ - defined(PNG_READ_pCAL_SUPPORTED) -# ifndef PNG_GET_INT_32_SUPPORTED -# define PNG_GET_INT_32_SUPPORTED -# endif -#endif - -#endif /* PNG_READ_SUPPORTED */ - -#ifdef PNG_WRITE_SUPPORTED - -/* PNG_WRITE_TRANSFORMS_NOT_SUPPORTED is deprecated. */ -#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_NO_WRITE_INTERLACING_SUPPORTED) && \ - !defined(PNG_WRITE_INTERLACING_SUPPORTED) - /* This is not required for PNG-compliant encoders, but can cause - * trouble if left undefined - */ -# define PNG_WRITE_INTERLACING_SUPPORTED -#endif - -#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ - !defined(PNG_WRITE_WEIGHTED_FILTER) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) -# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED -#endif - -#ifndef PNG_NO_WRITE_FLUSH -# define PNG_WRITE_FLUSH_SUPPORTED -#endif - -#if !defined(PNG_NO_SAVE_INT_32) || defined(PNG_WRITE_oFFS_SUPPORTED) || \ - defined(PNG_WRITE_pCAL_SUPPORTED) -# ifndef PNG_SAVE_INT_32_SUPPORTED -# define PNG_SAVE_INT_32_SUPPORTED -# endif -#endif - -#endif /* PNG_WRITE_SUPPORTED */ - -#define PNG_NO_ERROR_NUMBERS - -#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 - -#if defined(PNG_STDIO_SUPPORTED) && !defined(PNG_TIME_RFC1123_SUPPORTED) -# 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 - -/* Added at libpng-1.2.0 */ -#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) -# define PNG_USER_MEM_SUPPORTED -#endif - -/* Added at libpng-1.2.6 */ -#ifndef PNG_NO_SET_USER_LIMITS -# ifndef PNG_SET_USER_LIMITS_SUPPORTED -# define PNG_SET_USER_LIMITS_SUPPORTED -# endif - /* Feature added at libpng-1.4.0, this flag added at 1.4.1 */ -# ifndef PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED -# define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED -# endif - /* Feature added at libpng-1.4.1, this flag added at 1.4.1 */ -# ifndef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED -# define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED -# endif -#endif - -/* Added at libpng-1.2.43 */ -#ifndef PNG_USER_LIMITS_SUPPORTED -# ifndef PNG_NO_USER_LIMITS -# define PNG_USER_LIMITS_SUPPORTED -# endif -#endif - -/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGs no matter - * how large, set these two limits to 0x7fffffffL - */ -#ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000L -#endif -#ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000L -#endif - -/* Added at libpng-1.2.43. To accept all valid PNGs no matter - * how large, set these two limits to 0. - */ -#ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 0 -#endif - -/* Added at libpng-1.2.43 */ -#ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 0 -#endif - -/* Added at libpng-1.4.0 */ -#if !defined(PNG_NO_IO_STATE) && !defined(PNG_IO_STATE_SUPPORTED) -# define PNG_IO_STATE_SUPPORTED -#endif - -#ifndef PNG_LITERAL_SHARP -# define PNG_LITERAL_SHARP 0x23 -#endif -#ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET -# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b -#endif -#ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET -# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d -#endif -#ifndef PNG_STRING_NEWLINE -#define PNG_STRING_NEWLINE "\n" -#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 */ -/* -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED -# define PNG_READ_BIG_ENDIAN_SUPPORTED -#endif -*/ - -#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED # define PNG_USE_READ_MACROS #endif - -/* Buggy compilers (e.g., gcc 2.7.2.2) need PNG_NO_POINTER_INDEXING */ - -#if !defined(PNG_NO_POINTER_INDEXING) && \ - !defined(PNG_POINTER_INDEXING_SUPPORTED) -# define PNG_POINTER_INDEXING_SUPPORTED +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif #endif - -/* 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. +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. */ -/* The size of the png_text structure changed in libpng-1.0.6 when - * iTXt support was added. iTXt support was turned off by default through - * libpng-1.2.x, to support old apps that malloc the png_text structure - * instead of calling png_set_text() and letting libpng malloc it. It - * was turned on by default in libpng-1.4.0. +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. */ -/* PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED is deprecated. */ -#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 - -/* PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED is deprecated. */ -#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 -# ifndef PNG_READ_iTXt_SUPPORTED -# define PNG_READ_iTXt_SUPPORTED -# endif -# ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -# endif -#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_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 */ - -#ifndef PNG_NO_READ_UNKNOWN_CHUNKS -# ifndef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# endif -# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_UNKNOWN_CHUNKS_SUPPORTED -# endif -# ifndef PNG_READ_USER_CHUNKS_SUPPORTED -# define PNG_READ_USER_CHUNKS_SUPPORTED -# endif -#endif -#ifndef PNG_NO_READ_USER_CHUNKS -# ifndef PNG_READ_USER_CHUNKS_SUPPORTED -# define PNG_READ_USER_CHUNKS_SUPPORTED -# endif -# ifndef PNG_USER_CHUNKS_SUPPORTED -# define PNG_USER_CHUNKS_SUPPORTED -# endif -#endif -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif - -#ifdef PNG_WRITE_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 -# ifndef PNG_WRITE_iTXt_SUPPORTED -# define PNG_WRITE_iTXt_SUPPORTED -# endif -# 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 -#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 - -#ifdef PNG_WRITE_tIME_SUPPORTED -# ifndef PNG_NO_CONVERT_tIME -# ifndef _WIN32_WCE -/* The "tm" structure is not supported on WindowsCE */ -# ifndef PNG_CONVERT_tIME_SUPPORTED -# define PNG_CONVERT_tIME_SUPPORTED -# endif -# endif -# endif -#endif - -#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ - -#ifndef PNG_NO_WRITE_FILTER -# ifndef PNG_WRITE_FILTER_SUPPORTED -# define PNG_WRITE_FILTER_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 -#endif -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif -#endif /* PNG_WRITE_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 converting tIME chunks */ -#ifdef PNG_CONVERT_tIME_SUPPORTED - /* "time.h" functions are not supported on WindowsCE */ -# include -#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. +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. */ -#if defined(INT_MAX) && (INT_MAX > 0x7ffffffeL) -typedef unsigned int png_uint_32; -typedef int png_int_32; -#else -typedef unsigned long png_uint_32; -typedef long png_int_32; -#endif -typedef unsigned short png_uint_16; -typedef short png_int_16; -typedef unsigned char png_byte; - -#ifdef PNG_NO_SIZE_T - typedef unsigned int png_size_t; -#else - typedef size_t png_size_t; -#endif -#define png_sizeof(x) (sizeof (x)) - -/* The following is needed for medium model support. It cannot be in the - * pngpriv.h header. 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) +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. */ +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif -/* 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 +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif # else -# define LDATA 0 + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" # 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__ */ +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ -/* 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) +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. */ - -/* MSC Medium model */ -#ifdef FAR -# ifdef 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 -typedef FILE * png_FILE_p; -#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; - -/* 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 you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", - * you may get warnings regarding the linkage of png_zalloc and png_zfree. - * Don't ignore those warnings; you must also reset the default calling - * convention in your compiler to match your PNGAPI, and you must build - * zlib and your applications the same way you build libpng. - */ - -#ifdef __CYGWIN__ -# undef PNGAPI -# define PNGAPI __cdecl -# undef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -#ifdef __WATCOMC__ -# ifndef PNGAPI -# define PNGAPI -# endif -#endif - -#if defined(__MINGW32__) && !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__) )) - -# ifndef PNGAPI -# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) -# define PNGAPI __cdecl -# else -# define PNGAPI _cdecl -# endif -# endif - -# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ - 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) -# define PNG_IMPEXP +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT # endif # ifndef 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 -# ifdef 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 - -# ifndef PNG_IMPEXP -# ifdef 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(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) -# ifndef PNGAPI -# define PNGAPI _System -# endif -# else -# if 0 /* ... other platforms, with other meanings */ -# endif -# endif -#endif - -#ifndef PNGAPI -# define PNGAPI -#endif -#ifndef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -#ifdef PNG_BUILDSYMS -# ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END +# define PNG_IMPEXP # endif #endif -#ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args #endif -#define PNG_USE_LOCAL_ARRAYS /* Not used in libpng, defined for legacy apps */ +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ +#ifndef PNG_EXPORTA + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args)\ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif /* Support for compiler specific function attributes. These are used * so that where compiler support is available incorrect use of API @@ -1365,42 +333,97 @@ typedef char FAR * FAR * FAR * png_charppp; #endif #ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED -/* Support for compiler specific function attributes. These are used - * so that where compiler support is available incorrect use of API - * functions in png.h will generate compiler warnings. Added at libpng - * version 1.2.41. - */ -# ifdef __GNUC__ + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__clang__) && defined(__has_attribute) + /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ +# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# if !defined(PNG_PRIVATE) +# ifdef __has_extension +# if __has_extension(attribute_unavailable_with_message) +# define PNG_PRIVATE __attribute__((__unavailable__(\ + "This function is not exported by libpng."))) +# endif +# endif +# endif +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif + +# elif defined(__GNUC__) # ifndef PNG_USE_RESULT # define PNG_USE_RESULT __attribute__((__warn_unused_result__)) # endif # ifndef PNG_NORETURN # define PNG_NORETURN __attribute__((__noreturn__)) # endif -# ifndef PNG_ALLOCATED -# define PNG_ALLOCATED __attribute__((__malloc__)) -# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ +# endif /* __GNUC__ >= 3 */ - /* This specifically protects structure members that should only be - * accessed from within the library, therefore should be empty during - * a library build. - */ -# ifndef PNG_DEPRECATED -# define PNG_DEPRECATED __attribute__((__deprecated__)) +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ # endif -# ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT __attribute__((__deprecated__)) +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) # endif # ifndef PNG_PRIVATE -# if 0 /* Doesn't work so we use deprecated instead*/ -# define PNG_PRIVATE \ - __attribute__((warning("This function is not exported by libpng."))) -# else -# define PNG_PRIVATE \ - __attribute__((__deprecated__)) +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict # endif -# endif /* PNG_PRIVATE */ -# endif /* __GNUC__ */ +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif #endif /* PNG_PEDANTIC_WARNINGS */ #ifndef PNG_DEPRECATED @@ -1415,126 +438,185 @@ typedef char FAR * FAR * FAR * png_charppp; #ifndef PNG_ALLOCATED # define PNG_ALLOCATED /* The result of the function is new memory */ #endif -#ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ -#endif #ifndef PNG_PRIVATE # define PNG_PRIVATE /* This is a private libpng function */ #endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif -/* Users may want to use these so they are not private. Any library - * functions that are passed far data must be model-independent. +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. */ - -/* memory model/platform independent fns */ -#ifndef PNG_ABORT -# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) -# define PNG_ABORT() ExitProcess(0) -# else -# define PNG_ABORT() abort() -# endif +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8 bit bytes" #endif -#ifdef USE_FAR_KEYWORD -/* 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_strncpy _fstrncpy /* Added to v 1.2.6 */ -# define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ -# define png_memcpy _fmemcpy -# define png_memset _fmemset -# define png_sprintf sprintf +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; #else -# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) -# /* Favor Windows over C runtime fns */ -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strcpy lstrcpyA -# define png_strncpy lstrcpynA -# define png_strlen lstrlenA -# define png_memcmp memcmp -# define png_memcpy CopyMemory -# define png_memset memset -# define png_sprintf wsprintfA -# else -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strcpy strcpy -# define png_strncpy strncpy /* Added to v 1.2.6 */ -# define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ -# define png_memcpy memcpy -# define png_memset memset -# define png_sprintf sprintf -# endif +# error "libpng requires a signed 16 bit type" #endif -#ifndef PNG_NO_SNPRINTF -# ifdef _MSC_VER -# define png_snprintf _snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 _snprintf -# define png_snprintf6 _snprintf -# else -# define png_snprintf snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 snprintf -# define png_snprintf6 snprintf -# endif +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; #else - /* You don't have or don't want to use snprintf(). Caution: Using - * sprintf instead of snprintf exposes your application to accidental - * or malevolent buffer overflows. If you don't have snprintf() - * as a general rule you should provide one (you can get one from - * Portable OpenSSH). +# error "libpng requires an unsigned 16 bit type" +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error "libpng requires a signed 32 bit (or more) type" +#endif + +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32 bit (or more) type" +#endif + +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) */ -# define png_snprintf(s1,n,fmt,x1) png_sprintf(s1,fmt,x1) -# define png_snprintf2(s1,n,fmt,x1,x2) png_sprintf(s1,fmt,x1,x2) -# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ - png_sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) -#endif - -/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, - * and no smaller than png_uint_32. Casts from png_size_t or png_uint_32 - * to png_alloc_size_t are not necessary; in fact, it is recommended - * not to use them at all so that the compiler can complain when something - * turns out to be problematic. - * Casts in the other direction (from png_alloc_size_t to png_size_t or - * png_uint_32) should be explicitly applied; however, we do not expect - * to encounter practical situations that require such conversions. - */ -#if defined(__TURBOC__) && !defined(__FLAT__) - typedef unsigned long png_alloc_size_t; -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - typedef unsigned long png_alloc_size_t; -# else - /* This is an attempt to detect an old Windows system where (int) is - * actually 16 bits, in that case png_malloc must have an argument with a - * bigger size to accomodate the requirements of the library. - */ -# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) && \ - (!defined(INT_MAX) || INT_MAX <= 0x7ffffffeL) - typedef DWORD png_alloc_size_t; -# else - typedef png_size_t png_alloc_size_t; -# endif +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T # endif #endif -/* End of memory model/platform independent support */ -/* Just a little check that someone hasn't tried to define something - * contradictory. +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. */ -#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) -# undef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 65536L +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; #endif +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ -/* Added at libpng-1.2.8 */ -#endif /* PNG_VERSION_INFO_ONLY */ +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ #endif /* PNGCONF_H */ diff --git a/thirdparty/libpng/pngdebug.h b/thirdparty/libpng/pngdebug.h new file mode 100644 index 00000000..6a01b106 --- /dev/null +++ b/thirdparty/libpng/pngdebug.h @@ -0,0 +1,153 @@ + +/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c + * + * Last changed in libpng 1.6.8 [December 19, 2013] + * Copyright (c) 1998-2013 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 code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* 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. + * + * png_debug[1-2]?(level, message ,arg{0-2}) + * Expands to a statement (either a simple expression or a compound + * do..while(0) statement) that outputs a message with parameter + * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG + * is undefined, 0 or 1 every png_debug expands to a simple expression + * (actually ((void)0)). + * + * level: level of detail of message, starting at 0. A level 'n' + * message is preceded by 'n' 3-space indentations (not implemented + * on Microsoft compilers unless PNG_DEBUG_FILE is also + * defined, to allow debug DLL compilation with no standard IO). + * message: a printf(3) style text string. A trailing '\n' is added + * to the message. + * arg: 0 to 2 arguments for printf(3) style substitution in message. + */ +#ifndef PNGDEBUG_H +#define PNGDEBUG_H +/* These settings control the formatting of messages in png.c and pngerror.c */ +/* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif +# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +# endif +# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +# endif +# ifndef PNG_STRING_NEWLINE +# define PNG_STRING_NEWLINE "\n" +# endif + +#ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +# include +# if (PNG_DEBUG > 1) +# ifndef _DEBUG +# define _DEBUG +# endif +# ifndef png_debug +# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +# endif +# endif +# else /* PNG_DEBUG_FILE || !_MSC_VER */ +# ifndef PNG_STDIO_SUPPORTED +# include /* not included yet */ +# endif +# ifndef PNG_DEBUG_FILE +# define PNG_DEBUG_FILE stderr +# endif /* PNG_DEBUG_FILE */ + +# if (PNG_DEBUG > 1) +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ + } while (0) +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } while (0) +# endif +# endif /* __STDC __ */ +# endif /* (PNG_DEBUG > 1) */ + +# endif /* _MSC_VER */ +# endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +# define png_debug(l, m) ((void)0) +#endif +#ifndef png_debug1 +# define png_debug1(l, m, p1) ((void)0) +#endif +#ifndef png_debug2 +# define png_debug2(l, m, p1, p2) ((void)0) +#endif +#endif /* PNGDEBUG_H */ diff --git a/thirdparty/libpng/pngerror.c b/thirdparty/libpng/pngerror.c index 633eae29..0781866a 100644 --- a/thirdparty/libpng/pngerror.c +++ b/thirdparty/libpng/pngerror.c @@ -1,8 +1,8 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * Last changed in libpng 1.4.0 [January 3, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 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.) * @@ -16,19 +16,18 @@ * at each function. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #include "pngpriv.h" -static void /* PRIVATE */ -png_default_error PNGARG((png_structp png_ptr, - png_const_charp error_message)) PNG_NORETURN; +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, + png_const_charp error_message)),PNG_NORETURN); + #ifdef PNG_WARNINGS_SUPPORTED static void /* PRIVATE */ -png_default_warning PNGARG((png_structp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_WARNINGS_SUPPORTED */ +png_default_warning PNGARG((png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif /* WARNINGS */ /* 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, @@ -36,65 +35,176 @@ png_default_warning PNGARG((png_structp png_ptr, * to replace the error function at run-time. */ #ifdef PNG_ERROR_TEXT_SUPPORTED -void PNGAPI -png_error(png_structp png_ptr, png_const_charp error_message) +PNG_FUNCTION(void,PNGAPI +png_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED char msg[16]; if (png_ptr != NULL) { - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) - { - if (*error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - for (offset = 1; offset<15; offset++) - if (error_message[offset] == ' ') + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0 + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') break; - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - int i; - for (i = 0; i < offset - 1; i++) - msg[i] = error_message[i + 1]; - msg[i - 1] = '\0'; - error_message = msg; - } - else - error_message += offset; - } - else - { - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - msg[0] = '0'; - msg[1] = '\0'; - error_message = msg; - } + + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + + else + error_message += offset; + } + + else + { + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } } } } #endif if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, error_message); + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), + error_message); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ png_default_error(png_ptr, error_message); } #else -void PNGAPI -png_err(png_structp png_ptr) +PNG_FUNCTION(void,PNGAPI +png_err,(png_const_structrp png_ptr),PNG_NORETURN) { + /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, '\0'); + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ - png_default_error(png_ptr, '\0'); + png_default_error(png_ptr, ""); } -#endif /* PNG_ERROR_TEXT_SUPPORTED */ +#endif /* ERROR_TEXT */ + +/* Utility to safely appends strings to a buffer. This never errors out so + * error checking is not required in the caller. + */ +size_t +png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string) +{ + if (buffer != NULL && pos < bufsize) + { + if (string != NULL) + while (*string != '\0' && pos < bufsize-1) + buffer[pos++] = *string++; + + buffer[pos] = '\0'; + } + + return pos; +} + +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. + */ +png_charp +png_format_number(png_const_charp start, png_charp end, int format, + png_alloc_size_t number) +{ + int count = 0; /* number of digits output */ + int mincount = 1; /* minimum number required */ + int output = 0; /* digit output (for the fixed point format) */ + + *--end = '\0'; + + /* This is written so that the loop always runs at least once, even with + * number zero. + */ + while (end > start && (number != 0 || count < mincount)) + { + + static const char digits[] = "0123456789ABCDEF"; + + switch (format) + { + case PNG_NUMBER_FORMAT_fixed: + /* Needs five digits (the fraction) */ + mincount = 5; + if (output != 0 || number % 10 != 0) + { + *--end = digits[number % 10]; + output = 1; + } + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02u: + /* Expects at least 2 digits. */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_u: + *--end = digits[number % 10]; + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02x: + /* This format expects at least two digits */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_x: + *--end = digits[number & 0xf]; + number >>= 4; + break; + + default: /* an error */ + number = 0; + break; + } + + /* Keep track of the number of digits added */ + ++count; + + /* Float a fixed number here: */ + if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) + { + /* End of the fraction, but maybe nothing was output? In that case + * drop the decimal point. If the number is a true zero handle that + * here. + */ + if (output != 0) + *--end = '.'; + else if (number == 0) /* and !output */ + *--end = '0'; + } + } + + return end; +} +#endif #ifdef PNG_WARNINGS_SUPPORTED /* This function is called whenever there is a non-fatal error. This function @@ -103,46 +213,215 @@ png_err(png_structp png_ptr) * png_set_error_fn() to replace the warning function at run-time. */ void PNGAPI -png_warning(png_structp png_ptr, png_const_charp warning_message) +png_warning(png_const_structrp png_ptr, png_const_charp warning_message) { int offset = 0; if (png_ptr != NULL) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) #endif - { - if (*warning_message == PNG_LITERAL_SHARP) - { - for (offset = 1; offset < 15; offset++) - if (warning_message[offset] == ' ') + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') break; - } - } + } + } } if (png_ptr != NULL && png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); + (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), + warning_message + offset); else png_default_warning(png_ptr, warning_message + offset); } -#endif /* PNG_WARNINGS_SUPPORTED */ + +/* These functions support 'formatted' warning messages with up to + * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter + * is introduced by @, where 'number' starts at 1. This follows the + * standard established by X/Open for internationalizable error messages. + */ +void +png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string) +{ + if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) + (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); +} + +void +png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, + png_alloc_size_t value) +{ + char buffer[PNG_NUMBER_BUFFER_SIZE]; + png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); +} + +void +png_warning_parameter_signed(png_warning_parameters p, int number, int format, + png_int_32 value) +{ + png_alloc_size_t u; + png_charp str; + char buffer[PNG_NUMBER_BUFFER_SIZE]; + + /* Avoid overflow by doing the negate in a png_alloc_size_t: */ + u = (png_alloc_size_t)value; + if (value < 0) + u = ~u + 1; + + str = PNG_FORMAT_NUMBER(buffer, format, u); + + if (value < 0 && str > buffer) + *--str = '-'; + + png_warning_parameter(p, number, str); +} + +void +png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, + png_const_charp message) +{ + /* The internal buffer is just 192 bytes - enough for all our messages, + * overflow doesn't happen because this code checks! If someone figures + * out how to send us a message longer than 192 bytes, all that will + * happen is that the message will be truncated appropriately. + */ + size_t i = 0; /* Index in the msg[] buffer: */ + char msg[192]; + + /* Each iteration through the following loop writes at most one character + * to msg[i++] then returns here to validate that there is still space for + * the trailing '\0'. It may (in the case of a parameter) read more than + * one character from message[]; it must check for '\0' and continue to the + * test if it finds the end of string. + */ + while (i<(sizeof msg)-1 && *message != '\0') + { + /* '@' at end of string is now just printed (previously it was skipped); + * it is an error in the calling code to terminate the string with @. + */ + if (p != NULL && *message == '@' && message[1] != '\0') + { + int parameter_char = *++message; /* Consume the '@' */ + static const char valid_parameters[] = "123456789"; + int parameter = 0; + + /* Search for the parameter digit, the index in the string is the + * parameter to use. + */ + while (valid_parameters[parameter] != parameter_char && + valid_parameters[parameter] != '\0') + ++parameter; + + /* If the parameter digit is out of range it will just get printed. */ + if (parameter < PNG_WARNING_PARAMETER_COUNT) + { + /* Append this parameter */ + png_const_charp parm = p[parameter]; + png_const_charp pend = p[parameter] + (sizeof p[parameter]); + + /* No need to copy the trailing '\0' here, but there is no guarantee + * that parm[] has been initialized, so there is no guarantee of a + * trailing '\0': + */ + while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) + msg[i++] = *parm++; + + /* Consume the parameter digit too: */ + ++message; + continue; + } + + /* else not a parameter and there is a character after the @ sign; just + * copy that. This is known not to be '\0' because of the test above. + */ + } + + /* At this point *message can't be '\0', even in the bad parameter case + * above where there is a lone '@' at the end of the message string. + */ + msg[i++] = *message++; + } + + /* i is always less than (sizeof msg), so: */ + msg[i] = '\0'; + + /* And this is the formatted message. It may be larger than + * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these + * are not (currently) formatted. + */ + png_warning(png_ptr, msg); +} +#endif /* WARNINGS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_benign_error(png_structp png_ptr, png_const_charp error_message) +png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); -} -#endif + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_warning(png_ptr, error_message); + else +# endif + png_warning(png_ptr, error_message); + } + else + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_error(png_ptr, error_message); + else +# endif + png_error(png_ptr, error_message); + } + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif /* BENIGN_ERRORS */ + +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || \ + (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) /* 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 [] + * which 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) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) @@ -151,98 +430,275 @@ static PNG_CONST char png_digit[16] = { 'A', 'B', 'C', 'D', 'E', 'F' }; -#define PNG_MAX_ERROR_TEXT 64 -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) static void /* PRIVATE */ -png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp - error_message) +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp + error_message) { - int iout = 0, iin = 0; + png_uint_32 chunk_name = png_ptr->chunk_name; + int iout = 0, ishift = 24; - while (iin < 4) + while (ishift >= 0) { - int c = png_ptr->chunk_name[iin++]; - if (isnonalpha(c)) + int c = (int)(chunk_name >> ishift) & 0xff; + + ishift -= 8; + if (isnonalpha(c) != 0) { buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; buffer[iout++] = png_digit[(c & 0xf0) >> 4]; buffer[iout++] = png_digit[c & 0x0f]; buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; } + else { - buffer[iout++] = (png_byte)c; + buffer[iout++] = (char)c; } } if (error_message == NULL) buffer[iout] = '\0'; + else { + int iin = 0; + buffer[iout++] = ':'; buffer[iout++] = ' '; - png_memcpy(buffer + iout, error_message, PNG_MAX_ERROR_TEXT); - buffer[iout + PNG_MAX_ERROR_TEXT - 1] = '\0'; + + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; } } +#endif /* WARNINGS || ERROR_TEXT */ -#ifdef PNG_READ_SUPPORTED -void PNGAPI -png_chunk_error(png_structp png_ptr, png_const_charp error_message) +#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_FUNCTION(void,PNGAPI +png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) - png_error(png_ptr, error_message); + png_error(png_ptr, error_message); + else { - png_format_buffer(png_ptr, msg, error_message); - png_error(png_ptr, msg); + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); } } -#endif /* PNG_READ_SUPPORTED */ -#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ +#endif /* READ && ERROR_TEXT */ #ifdef PNG_WARNINGS_SUPPORTED void PNGAPI -png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) +png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) - png_warning(png_ptr, warning_message); + png_warning(png_ptr, warning_message); + else { - png_format_buffer(png_ptr, msg, warning_message); - png_warning(png_ptr, msg); + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); } } -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ #ifdef PNG_READ_SUPPORTED #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) { - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - png_chunk_warning(png_ptr, error_message); - else - png_chunk_error(png_ptr, error_message); + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + png_chunk_warning(png_ptr, error_message); + + else + png_chunk_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif } #endif -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ + +void /* PRIVATE */ +png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) +{ +# ifndef PNG_WARNINGS_SUPPORTED + PNG_UNUSED(message) +# endif + + /* This is always supported, but for just read or just write it + * unconditionally does the right thing. + */ +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +# endif + +# ifdef PNG_READ_SUPPORTED + { + if (error < PNG_CHUNK_ERROR) + png_chunk_warning(png_ptr, message); + + else + png_chunk_benign_error(png_ptr, message); + } +# endif + +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) +# endif + +# ifdef PNG_WRITE_SUPPORTED + { + if (error < PNG_CHUNK_WRITE_ERROR) + png_app_warning(png_ptr, message); + + else + png_app_error(png_ptr, message); + } +# endif +} + +#ifdef PNG_ERROR_TEXT_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_FUNCTION(void, +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) +{ +# define fixed_message "fixed point overflow in " +# define fixed_message_ln ((sizeof fixed_message)-1) + int iin; + char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; + memcpy(msg, fixed_message, fixed_message_ln); + iin = 0; + if (name != NULL) + while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } + msg[fixed_message_ln + iin] = 0; + png_error(png_ptr, msg); +} +#endif +#endif #ifdef PNG_SETJMP_SUPPORTED /* This API only exists if ANSI-C style error handling is used, * otherwise it is necessary for png_default_error to be overridden. */ jmp_buf* PNGAPI -png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, +png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size) { - if (png_ptr == NULL || jmp_buf_size != png_sizeof(jmp_buf)) + /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value + * and it must not change after that. Libpng doesn't care how big the + * buffer is, just that it doesn't change. + * + * If the buffer size is no *larger* than the size of jmp_buf when libpng is + * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 + * semantics that this call will not fail. If the size is larger, however, + * the buffer is allocated and this may fail, causing the function to return + * NULL. + */ + if (png_ptr == NULL) return NULL; + if (png_ptr->jmp_buf_ptr == NULL) + { + png_ptr->jmp_buf_size = 0; /* not allocated */ + + if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) + png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; + + else + { + png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, + png_malloc_warn(png_ptr, jmp_buf_size)); + + if (png_ptr->jmp_buf_ptr == NULL) + return NULL; /* new NULL return on OOM */ + + png_ptr->jmp_buf_size = jmp_buf_size; + } + } + + else /* Already allocated: check the size */ + { + size_t size = png_ptr->jmp_buf_size; + + if (size == 0) + { + size = (sizeof png_ptr->jmp_buf_local); + if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) + { + /* This is an internal error in libpng: somehow we have been left + * with a stack allocated jmp_buf when the application regained + * control. It's always possible to fix this up, but for the moment + * this is a png_error because that makes it easy to detect. + */ + png_error(png_ptr, "Libpng jmp_buf still allocated"); + /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ + } + } + + if (size != jmp_buf_size) + { + png_warning(png_ptr, "Application jmp_buf size changed"); + return NULL; /* caller will probably crash: no choice here */ + } + } + + /* Finally fill in the function, now we have a satisfactory buffer. It is + * valid to change the function on every call. + */ png_ptr->longjmp_fn = longjmp_fn; - return &png_ptr->jmpbuf; + return png_ptr->jmp_buf_ptr; +} + +void /* PRIVATE */ +png_free_jmpbuf(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + jmp_buf *jb = png_ptr->jmp_buf_ptr; + + /* A size of 0 is used to indicate a local, stack, allocation of the + * pointer; used here and in png.c + */ + if (jb != NULL && png_ptr->jmp_buf_size > 0) + { + + /* This stuff is so that a failure to free the error control structure + * does not leave libpng in a state with no valid error handling: the + * free always succeeds, if there is an error it gets ignored. + */ + if (jb != &png_ptr->jmp_buf_local) + { + /* Make an internal, libpng, jmp_buf to return here */ + jmp_buf free_jmp_buf; + + if (!setjmp(free_jmp_buf)) + { + png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ + png_ptr->jmp_buf_size = 0; /* stack allocation */ + png_ptr->longjmp_fn = longjmp; + png_free(png_ptr, jb); /* Return to setjmp on error */ + } + } + } + + /* *Always* cancel everything out: */ + png_ptr->jmp_buf_size = 0; + png_ptr->jmp_buf_ptr = NULL; + png_ptr->longjmp_fn = 0; + } } #endif @@ -251,63 +707,72 @@ png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, * 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 error_message) +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) { #ifdef PNG_CONSOLE_IO_SUPPORTED #ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*error_message == PNG_LITERAL_SHARP) + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - char error_number[16]; - for (offset = 0; offset<15; offset++) - { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { error_number[offset] = error_message[offset + 1]; if (error_message[offset] == ' ') - break; - } - if ((offset > 1) && (offset < 15)) - { - error_number[offset - 1] = '\0'; - fprintf(stderr, "libpng error no. %s: %s", - error_number, error_message + offset + 1); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng error: %s, offset=%d", - error_message, offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } + break; + } + + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } } else #endif { - fprintf(stderr, "libpng error: %s", error_message); + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); fprintf(stderr, PNG_STRING_NEWLINE); } +#else + PNG_UNUSED(error_message) /* Make compiler happy */ +#endif + png_longjmp(png_ptr, 1); +} + +PNG_FUNCTION(void,PNGAPI +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) +{ +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && + png_ptr->jmp_buf_ptr != NULL) + png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(val) #endif -#ifdef PNG_SETJMP_SUPPORTED - if (png_ptr && png_ptr->longjmp_fn) - { -# ifdef USE_FAR_KEYWORD - { - jmp_buf jmpbuf; - png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf)); - png_ptr->longjmp_fn(jmpbuf, 1); - } -# else - png_ptr->longjmp_fn(png_ptr->jmpbuf, 1); -# endif - } -#endif - /* Here if not setjmp support or if png_ptr is null. */ + /* If control reaches this point, png_longjmp() must not return. The only + * choice is to terminate the whole process (or maybe the thread); to do + * this the ANSI-C abort() function is used unless a different method is + * implemented by overriding the default configuration setting for + * PNG_ABORT(). + */ PNG_ABORT(); -#ifndef PNG_CONSOLE_IO_SUPPORTED - error_message = error_message; /* Make compiler happy */ -#endif } #ifdef PNG_WARNINGS_SUPPORTED @@ -317,61 +782,69 @@ png_default_error(png_structp png_ptr, png_const_charp error_message) * 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 warning_message) +png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED # ifdef PNG_ERROR_NUMBERS_SUPPORTED if (*warning_message == PNG_LITERAL_SHARP) { - int offset; - char warning_number[16]; - for (offset = 0; offset < 15; offset++) - { - warning_number[offset] = warning_message[offset + 1]; - if (warning_message[offset] == ' ') + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') break; - } - if ((offset > 1) && (offset < 15)) - { - warning_number[offset + 1] = '\0'; - fprintf(stderr, "libpng warning no. %s: %s", - warning_number, warning_message + offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng warning: %s", - warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } + } + + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } } else # endif + { - fprintf(stderr, "libpng warning: %s", warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); } #else - warning_message = warning_message; /* Make compiler happy */ + PNG_UNUSED(warning_message) /* Make compiler happy */ #endif - png_ptr = png_ptr; /* Make compiler happy */ + PNG_UNUSED(png_ptr) /* Make compiler happy */ } -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ /* 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) + * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 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_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) { if (png_ptr == NULL) return; + png_ptr->error_ptr = error_ptr; png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_ptr->warning_fn = warning_fn; +#else + PNG_UNUSED(warning_fn) +#endif } @@ -380,23 +853,111 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI -png_get_error_ptr(png_structp png_ptr) +png_get_error_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return NULL; + return ((png_voidp)png_ptr->error_ptr); } #ifdef PNG_ERROR_NUMBERS_SUPPORTED void PNGAPI -png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +png_set_strip_error_numbers(png_structrp 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); + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | + PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); } } #endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + /* Currently the above both depend on SETJMP_SUPPORTED, however it would be + * possible to implement without setjmp support just so long as there is some + * way to handle the error return here: + */ +PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI +png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* An error is always logged here, overwriting anything (typically a warning) + * that is already there: + */ + if (image != NULL) + { + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + + /* Retrieve the jmp_buf from within the png_control, making this work for + * C++ compilation too is pretty tricky: C++ wants a pointer to the first + * element of a jmp_buf, but C doesn't tell us the type of that. + */ + if (image->opaque != NULL && image->opaque->error_buf != NULL) + longjmp(png_control_jmp_buf(image->opaque), 1); + + /* Missing longjmp buffer, the following is to help debugging: */ + { + size_t pos = png_safecat(image->message, (sizeof image->message), 0, + "bad longjmp: "); + png_safecat(image->message, (sizeof image->message), pos, + error_message); + } + } + + /* Here on an internal programming error. */ + abort(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +void /* PRIVATE */ PNGCBAPI +png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* A warning is only logged if there is no prior warning or error. */ + if (image->warning_or_error == 0) + { + png_safecat(image->message, (sizeof image->message), 0, warning_message); + image->warning_or_error |= PNG_IMAGE_WARNING; + } +} +#endif + +int /* PRIVATE */ +png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) +{ + volatile png_imagep image = image_in; + volatile int result; + volatile png_voidp saved_error_buf; + jmp_buf safe_jmpbuf; + + /* Safely execute function(arg) with png_error returning to this function. */ + saved_error_buf = image->opaque->error_buf; + result = setjmp(safe_jmpbuf) == 0; + + if (result != 0) + { + + image->opaque->error_buf = safe_jmpbuf; + result = function(arg); + } + + image->opaque->error_buf = saved_error_buf; + + /* And do the cleanup prior to any failure return. */ + if (result == 0) + png_image_free(image); + + return result; +} +#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c index abe721bd..743a6a9b 100644 --- a/thirdparty/libpng/pngget.c +++ b/thirdparty/libpng/pngget.c @@ -1,8 +1,8 @@ /* pngget.c - retrieval of values from info struct * - * Last changed in libpng 1.4.2 [May 6, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -12,47 +12,44 @@ * */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #include "pngpriv.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + png_uint_32 PNGAPI -png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) +png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 flag) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->valid & flag); - else - return(0); + return(0); } png_size_t PNGAPI -png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) +png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->rowbytes); - else - return(0); + return(0); } #ifdef PNG_INFO_IMAGE_SUPPORTED png_bytepp PNGAPI -png_get_rows(png_structp png_ptr, png_infop info_ptr) +png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->row_pointers); - else - return(0); + 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) +png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->width; @@ -61,7 +58,7 @@ png_get_image_width(png_structp png_ptr, png_infop info_ptr) } png_uint_32 PNGAPI -png_get_image_height(png_structp png_ptr, png_infop info_ptr) +png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->height; @@ -70,7 +67,7 @@ png_get_image_height(png_structp png_ptr, png_infop info_ptr) } png_byte PNGAPI -png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) +png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->bit_depth; @@ -79,7 +76,7 @@ png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) } png_byte PNGAPI -png_get_color_type(png_structp png_ptr, png_infop info_ptr) +png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->color_type; @@ -88,7 +85,7 @@ png_get_color_type(png_structp png_ptr, png_infop info_ptr) } png_byte PNGAPI -png_get_filter_type(png_structp png_ptr, png_infop info_ptr) +png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->filter_type; @@ -97,7 +94,7 @@ png_get_filter_type(png_structp png_ptr, png_infop info_ptr) } png_byte PNGAPI -png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) +png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->interlace_type; @@ -106,7 +103,7 @@ png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) } png_byte PNGAPI -png_get_compression_type(png_structp png_ptr, png_infop info_ptr) +png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->compression_type; @@ -115,226 +112,319 @@ png_get_compression_type(png_structp png_ptr, png_infop info_ptr) } png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) #ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", + "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); - } + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->x_pixels_per_unit); + } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return (0); } png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) #ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { - png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); + png_debug1(1, "in %s retrieval function", + "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); + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->y_pixels_per_unit); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return (0); } png_uint_32 PNGAPI -png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) #ifdef PNG_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "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); + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && + info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) + return (info_ptr->x_pixels_per_unit); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #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) -#ifdef PNG_pHYs_SUPPORTED - - if (info_ptr->valid & PNG_INFO_pHYs) +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); - if (info_ptr->x_pixels_per_unit == 0) - return ((float)0.0); - - else + if (info_ptr->x_pixels_per_unit != 0) return ((float)((float)info_ptr->y_pixels_per_unit - /(float)info_ptr->x_pixels_per_unit)); + /(float)info_ptr->x_pixels_per_unit)); } #else - return (0.0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return ((float)0.0); } #endif -png_int_32 PNGAPI -png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) -#ifdef PNG_oFFs_SUPPORTED +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0 && + info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && + info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && + info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + { + png_fixed_point res; - if (info_ptr->valid & PNG_INFO_oFFs) + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); + + /* The following casts work because a PNG 4 byte integer only has a valid + * range of 0..2^31-1; otherwise the cast might overflow. + */ + if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, + (png_int_32)info_ptr->x_pixels_per_unit) != 0) + return res; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->x_offset); + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->x_offset); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return (0); } png_int_32 PNGAPI -png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) +png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) - #ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->y_offset); + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->y_offset); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return (0); } png_int_32 PNGAPI -png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) +png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) - #ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->x_offset); + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->x_offset); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif + return (0); } png_int_32 PNGAPI -png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) +png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { - if (png_ptr != NULL && info_ptr != NULL) - #ifdef PNG_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->y_offset); + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->y_offset); } #else - return (0); + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #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) +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED +static png_uint_32 +ppi_from_ppm(png_uint_32 ppm) { - return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); +#if 0 + /* The conversion is *(2.54/100), in binary (32 digits): + * .00000110100000001001110101001001 + */ + png_uint_32 t1001, t1101; + ppm >>= 1; /* .1 */ + t1001 = ppm + (ppm >> 3); /* .1001 */ + t1101 = t1001 + (ppm >> 1); /* .1101 */ + ppm >>= 20; /* .000000000000000000001 */ + t1101 += t1101 >> 15; /* .1101000000000001101 */ + t1001 >>= 11; /* .000000000001001 */ + t1001 += t1001 >> 12; /* .000000000001001000000001001 */ + ppm += t1001; /* .000000000001001000001001001 */ + ppm += t1101; /* .110100000001001110101001001 */ + return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ +#else + /* The argument is a PNG unsigned integer, so it is not permitted + * to be bigger than 2^31. + */ + png_fixed_point result; + if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, + 5000) != 0) + return result; + + /* Overflow. */ + return 0; +#endif } png_uint_32 PNGAPI -png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { - return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); + return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); } png_uint_32 PNGAPI -png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { - return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); + return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); } +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); +} + +#ifdef PNG_FIXED_POINT_SUPPORTED +static png_fixed_point +png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) +{ + /* Convert from metres * 1,000,000 to inches * 100,000, meters to + * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. + * Notice that this can overflow - a warning is output and 0 is + * returned. + */ + return png_muldiv_warn(png_ptr, microns, 500, 127); +} + +png_fixed_point PNGAPI +png_get_x_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_x_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_y_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_y_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) +png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { - return ((float)png_get_x_offset_microns(png_ptr, info_ptr) - *.00003937); + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); } +#endif +#ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) +png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { - return ((float)png_get_y_offset_microns(png_ptr, info_ptr) - *.00003937); + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); } +#endif #ifdef 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_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp 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)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "pHYs"); @@ -343,15 +433,18 @@ png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, *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); @@ -359,237 +452,367 @@ png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, } } } + return (retval); } -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ +#endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ /* png_get_channels really belongs in here, too, but it's been around longer */ -#endif /* PNG_EASY_ACCESS_SUPPORTED */ +#endif /* EASY_ACCESS */ + png_byte PNGAPI -png_get_channels(png_structp png_ptr, png_infop info_ptr) +png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->channels); - else - return (0); + + return (0); } -png_bytep PNGAPI -png_get_signature(png_structp png_ptr, png_infop info_ptr) +#ifdef PNG_READ_SUPPORTED +png_const_bytep PNGAPI +png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->signature); - else - return (NULL); + + return (NULL); } +#endif #ifdef PNG_bKGD_SUPPORTED png_uint_32 PNGAPI -png_get_bKGD(png_structp png_ptr, png_infop info_ptr, +png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_color_16p *background) { - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) - && background != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_bKGD) != 0 && + background != NULL) { png_debug1(1, "in %s retrieval function", "bKGD"); *background = &(info_ptr->background); return (PNG_INFO_bKGD); } + return (0); } #endif #ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the + * same time to correct the rgb grayscale coefficient defaults obtained from the + * cHRM chunk in 1.5.4 + */ +# 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) +png_get_cHRM(png_const_structrp png_ptr, png_const_inforp 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)) + /* Quiet API change: this code used to only return the end points if a cHRM + * chunk was present, but the end points can also come from iCCP or sRGB + * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and + * the png_set_ APIs merely check that set end points are mutually + * consistent. + */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { png_debug1(1, "in %s retrieval function", "cHRM"); if (white_x != NULL) - *white_x = (double)info_ptr->x_white; + *white_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); if (white_y != NULL) - *white_y = (double)info_ptr->y_white; + *white_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); if (red_x != NULL) - *red_x = (double)info_ptr->x_red; + *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, + "cHRM red X"); if (red_y != NULL) - *red_y = (double)info_ptr->y_red; + *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, + "cHRM red Y"); if (green_x != NULL) - *green_x = (double)info_ptr->x_green; + *green_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); if (green_y != NULL) - *green_y = (double)info_ptr->y_green; + *green_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); if (blue_x != NULL) - *blue_x = (double)info_ptr->x_blue; + *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, + "cHRM blue X"); if (blue_y != NULL) - *blue_y = (double)info_ptr->y_blue; + *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, + "cHRM blue Y"); 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) +png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + + if (red_X != NULL) + *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, + "cHRM red X"); + if (red_Y != NULL) + *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, + "cHRM red Y"); + if (red_Z != NULL) + *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, + "cHRM red Z"); + if (green_X != NULL) + *green_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); + if (green_Y != NULL) + *green_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); + if (green_Z != NULL) + *green_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); + if (blue_X != NULL) + *blue_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); + if (blue_Y != NULL) + *blue_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); + if (blue_Z != NULL) + *blue_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); + return (PNG_INFO_cHRM); + } + + return (0); +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (int_red_X != NULL) + *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; + if (int_red_Y != NULL) + *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; + if (int_red_Z != NULL) + *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; + if (int_green_X != NULL) + *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; + if (int_green_Y != NULL) + *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; + if (int_green_Z != NULL) + *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; + if (int_blue_X != NULL) + *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; + if (int_blue_Y != NULL) + *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; + if (int_blue_Z != NULL) + *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp 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 retrieval function", "cHRM"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { if (white_x != NULL) - *white_x = info_ptr->int_x_white; + *white_x = info_ptr->colorspace.end_points_xy.whitex; if (white_y != NULL) - *white_y = info_ptr->int_y_white; + *white_y = info_ptr->colorspace.end_points_xy.whitey; if (red_x != NULL) - *red_x = info_ptr->int_x_red; + *red_x = info_ptr->colorspace.end_points_xy.redx; if (red_y != NULL) - *red_y = info_ptr->int_y_red; + *red_y = info_ptr->colorspace.end_points_xy.redy; if (green_x != NULL) - *green_x = info_ptr->int_x_green; + *green_x = info_ptr->colorspace.end_points_xy.greenx; if (green_y != NULL) - *green_y = info_ptr->int_y_green; + *green_y = info_ptr->colorspace.end_points_xy.greeny; if (blue_x != NULL) - *blue_x = info_ptr->int_x_blue; + *blue_x = info_ptr->colorspace.end_points_xy.bluex; if (blue_y != NULL) - *blue_y = info_ptr->int_y_blue; + *blue_y = info_ptr->colorspace.end_points_xy.bluey; return (PNG_INFO_cHRM); } + return (0); } -#endif +# endif #endif #ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED png_uint_32 PNGAPI -png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) +png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *file_gamma) { png_debug1(1, "in %s retrieval function", "gAMA"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && file_gamma != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) { - *file_gamma = (double)info_ptr->gamma; + *file_gamma = info_ptr->colorspace.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) -{ - png_debug1(1, "in %s retrieval function", "gAMA"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && int_file_gamma != NULL) - { - *int_file_gamma = info_ptr->int_gamma; - return (PNG_INFO_gAMA); - } return (0); } -#endif +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) + { + *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, + "png_get_gAMA"); + return (PNG_INFO_gAMA); + } + + return (0); +} +# endif #endif #ifdef PNG_sRGB_SUPPORTED png_uint_32 PNGAPI -png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) +png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *file_srgb_intent) { png_debug1(1, "in %s retrieval function", "sRGB"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) - && file_srgb_intent != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL) { - *file_srgb_intent = (int)info_ptr->srgb_intent; + *file_srgb_intent = info_ptr->colorspace.rendering_intent; return (PNG_INFO_sRGB); } + return (0); } #endif #ifdef 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) +png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen) { png_debug1(1, "in %s retrieval function", "iCCP"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) - && name != NULL && profile != NULL && proflen != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_iCCP) != 0 && + name != NULL && compression_type != NULL && profile != NULL && + proflen != NULL) { *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 = png_get_uint_32(info_ptr->iccp_profile); + /* This is somewhat irrelevant since the profile data returned has + * actually been uncompressed. */ - *proflen = (int)info_ptr->iccp_proflen; - *compression_type = (int)info_ptr->iccp_compression; + *compression_type = PNG_COMPRESSION_TYPE_BASE; return (PNG_INFO_iCCP); } + return (0); } #endif #ifdef PNG_sPLT_SUPPORTED -png_uint_32 PNGAPI -png_get_sPLT(png_structp png_ptr, png_infop info_ptr, - png_sPLT_tpp spalettes) +int PNGAPI +png_get_sPLT(png_const_structrp png_ptr, png_inforp 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); + *spalettes = info_ptr->splt_palettes; + return info_ptr->splt_palettes_num; } + return (0); } #endif #ifdef PNG_hIST_SUPPORTED png_uint_32 PNGAPI -png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) +png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_16p *hist) { png_debug1(1, "in %s retrieval function", "hIST"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) - && hist != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) { *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) - +png_get_IHDR(png_const_structrp png_ptr, png_const_inforp 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) { png_debug1(1, "in %s retrieval function", "IHDR"); - if (png_ptr == NULL || info_ptr == NULL || width == NULL || - height == NULL || bit_depth == NULL || color_type == NULL) + if (png_ptr == NULL || info_ptr == NULL) return (0); - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - *color_type = info_ptr->color_type; + if (width != NULL) + *width = info_ptr->width; + + if (height != NULL) + *height = info_ptr->height; + + if (bit_depth != NULL) + *bit_depth = info_ptr->bit_depth; + + if (color_type != NULL) + *color_type = info_ptr->color_type; if (compression_type != NULL) *compression_type = info_ptr->compression_type; @@ -605,7 +828,7 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, * application has ignored our advice not to mess with the members * of info_ptr directly. */ - png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, info_ptr->compression_type, info_ptr->filter_type); @@ -614,33 +837,36 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, #ifdef 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) +png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) { png_debug1(1, "in %s retrieval function", "oFFs"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) - && offset_x != NULL && offset_y != NULL && unit_type != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0 && + offset_x != NULL && offset_y != NULL && unit_type != NULL) { *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 #ifdef 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) +png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) { png_debug1(1, "in %s retrieval function", "pCAL"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) - && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pCAL) != 0 && + purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && nparams != NULL && units != NULL && params != NULL) { *purpose = info_ptr->pcal_purpose; @@ -652,57 +878,82 @@ png_get_pCAL(png_structp png_ptr, png_infop info_ptr, *params = info_ptr->pcal_params; return (PNG_INFO_pCAL); } + return (0); } #endif #ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(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) +png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_fixed_point *width, png_fixed_point *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); + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + /*TODO: make this work without FP support; the API is currently eliminated + * if neither floating point APIs nor internal floating point arithmetic + * are enabled. + */ + *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); + *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), + "sCAL height"); + return (PNG_INFO_sCAL); + } + + return(0); } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED +# endif /* FLOATING_ARITHMETIC */ +# endif /* FIXED_POINT */ +# ifdef PNG_FLOATING_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) +png_get_sCAL(png_const_structrp png_ptr, png_const_inforp 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_s_width; - *height = info_ptr->scal_s_height; - return (PNG_INFO_sCAL); - } - return(0); + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = atof(info_ptr->scal_s_width); + *height = atof(info_ptr->scal_s_height); + return (PNG_INFO_sCAL); + } + + return(0); } -#endif -#endif -#endif +# endif /* FLOATING POINT */ +png_uint_32 PNGAPI +png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + + return(0); +} +#endif /* sCAL */ #ifdef 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_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) { png_uint_32 retval = 0; png_debug1(1, "in %s retrieval function", "pHYs"); if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs)) + (info_ptr->valid & PNG_INFO_pHYs) != 0) { if (res_x != NULL) { @@ -722,53 +973,56 @@ png_get_pHYs(png_structp png_ptr, png_infop info_ptr, retval |= PNG_INFO_pHYs; } } + return (retval); } -#endif +#endif /* pHYs */ png_uint_32 PNGAPI -png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, - int *num_palette) +png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, + png_colorp *palette, int *num_palette) { png_debug1(1, "in %s retrieval function", "PLTE"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) - && palette != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) { *palette = info_ptr->palette; *num_palette = info_ptr->num_palette; png_debug1(3, "num_palette = %d", *num_palette); return (PNG_INFO_PLTE); } + return (0); } #ifdef PNG_sBIT_SUPPORTED png_uint_32 PNGAPI -png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) +png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_8p *sig_bit) { png_debug1(1, "in %s retrieval function", "sBIT"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) - && sig_bit != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) { *sig_bit = &(info_ptr->sig_bit); return (PNG_INFO_sBIT); } + return (0); } #endif #ifdef 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) +int PNGAPI +png_get_text(png_const_structrp png_ptr, png_inforp 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", - (png_ptr->chunk_name[0] == '\0' ? "text" - : (png_const_charp)png_ptr->chunk_name)); + png_debug1(1, "in 0x%lx retrieval function", + (unsigned long)png_ptr->chunk_name); if (text_ptr != NULL) *text_ptr = info_ptr->text; @@ -776,150 +1030,190 @@ png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, if (num_text != NULL) *num_text = info_ptr->num_text; - return ((png_uint_32)info_ptr->num_text); + return info_ptr->num_text; } + if (num_text != NULL) - *num_text = 0; + *num_text = 0; + return(0); } #endif #ifdef PNG_tIME_SUPPORTED png_uint_32 PNGAPI -png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_timep *mod_time) { png_debug1(1, "in %s retrieval function", "tIME"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) - && mod_time != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) { *mod_time = &(info_ptr->mod_time); return (PNG_INFO_tIME); } + return (0); } #endif #ifdef PNG_tRNS_SUPPORTED png_uint_32 PNGAPI -png_get_tRNS(png_structp png_ptr, png_infop info_ptr, - png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) +png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) { png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tRNS) != 0) { png_debug1(1, "in %s retrieval function", "tRNS"); if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (trans_alpha != NULL) - { - *trans_alpha = info_ptr->trans_alpha; - retval |= PNG_INFO_tRNS; - } + if (trans_alpha != NULL) + { + *trans_alpha = info_ptr->trans_alpha; + retval |= PNG_INFO_tRNS; + } - if (trans_color != NULL) - *trans_color = &(info_ptr->trans_color); + if (trans_color != NULL) + *trans_color = &(info_ptr->trans_color); } + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ { - if (trans_color != NULL) - { - *trans_color = &(info_ptr->trans_color); - retval |= PNG_INFO_tRNS; - } + if (trans_color != NULL) + { + *trans_color = &(info_ptr->trans_color); + retval |= PNG_INFO_tRNS; + } - if (trans_alpha != NULL) - *trans_alpha = NULL; + if (trans_alpha != NULL) + *trans_alpha = NULL; } + if (num_trans != NULL) { *num_trans = info_ptr->num_trans; retval |= PNG_INFO_tRNS; } } + return (retval); } #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -png_uint_32 PNGAPI -png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, - png_unknown_chunkpp unknowns) +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp 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); + *unknowns = info_ptr->unknown_chunks; + return info_ptr->unknown_chunks_num; } + return (0); } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte PNGAPI -png_get_rgb_to_gray_status (png_structp png_ptr) +png_get_rgb_to_gray_status (png_const_structrp png_ptr) { - return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); + return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); } #endif #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp PNGAPI -png_get_user_chunk_ptr(png_structp png_ptr) +png_get_user_chunk_ptr(png_const_structrp png_ptr) { - return (png_ptr? png_ptr->user_chunk_ptr : NULL); + return (png_ptr ? png_ptr->user_chunk_ptr : NULL); } #endif png_size_t PNGAPI -png_get_compression_buffer_size(png_structp png_ptr) +png_get_compression_buffer_size(png_const_structrp png_ptr) { - return (png_ptr ? png_ptr->zbuf_size : 0L); -} + if (png_ptr == NULL) + return 0; +#ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +#endif + { +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +#else + return PNG_IDAT_READ_SIZE; +#endif + } + +#ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +#endif +} #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* These functions were added to libpng 1.2.6 and were enabled * by default in libpng-1.4.0 */ png_uint_32 PNGAPI -png_get_user_width_max (png_structp png_ptr) +png_get_user_width_max (png_const_structrp png_ptr) { - return (png_ptr? png_ptr->user_width_max : 0); + return (png_ptr ? png_ptr->user_width_max : 0); } + png_uint_32 PNGAPI -png_get_user_height_max (png_structp png_ptr) +png_get_user_height_max (png_const_structrp png_ptr) { - return (png_ptr? png_ptr->user_height_max : 0); + return (png_ptr ? png_ptr->user_height_max : 0); } + /* This function was added to libpng 1.4.0 */ png_uint_32 PNGAPI -png_get_chunk_cache_max (png_structp png_ptr) +png_get_chunk_cache_max (png_const_structrp png_ptr) { - return (png_ptr? png_ptr->user_chunk_cache_max : 0); + return (png_ptr ? png_ptr->user_chunk_cache_max : 0); } + /* This function was added to libpng 1.4.1 */ png_alloc_size_t PNGAPI -png_get_chunk_malloc_max (png_structp png_ptr) +png_get_chunk_malloc_max (png_const_structrp png_ptr) { - return (png_ptr? - png_ptr->user_chunk_malloc_max : 0); + return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); } -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#endif /* SET_USER_LIMITS */ /* These functions were added to libpng 1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 PNGAPI -png_get_io_state (png_structp png_ptr) +png_get_io_state (png_const_structrp png_ptr) { - return png_ptr->io_state; + return png_ptr->io_state; } -png_bytep PNGAPI -png_get_io_chunk_name (png_structp png_ptr) +png_uint_32 PNGAPI +png_get_io_chunk_type (png_const_structrp png_ptr) { return png_ptr->chunk_name; } -#endif /* ?PNG_IO_STATE_SUPPORTED */ +#endif /* IO_STATE */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +int PNGAPI +png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return png_ptr->num_palette_max; + + return (-1); +} +# endif +#endif + +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pnginfo.h b/thirdparty/libpng/pnginfo.h new file mode 100644 index 00000000..c8c874dd --- /dev/null +++ b/thirdparty/libpng/pnginfo.h @@ -0,0 +1,259 @@ + +/* pnginfo.h - header file for PNG reference library + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 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 code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + + /* 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, using png_set_*() functions, 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 libpng-1.5.0 this was moved into a separate private + * file that is not visible to applications. + * + * 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. + */ +#ifndef PNGINFO_H +#define PNGINFO_H + +struct png_info_def +{ + /* 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_size_t 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 are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ + 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 */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif + + /* 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_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) + */ + png_colorspace colorspace; +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ +#endif + +#ifdef 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 or comments to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read or comments to write */ +#endif /* TEXT */ + +#ifdef 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 + +#ifdef 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_alpha; /* alpha values for paletted image */ + png_color_16 trans_color; /* 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 + +#ifdef 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 + +#ifdef 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 + +#ifdef 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_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 */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + int splt_palettes_num; /* Match type returned by png_get API */ +#endif + +#ifdef 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. Data values are valid if (valid & PNG_INFO_sCAL) is + * non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif + +#ifdef 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 + +}; +#endif /* PNGINFO_H */ diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h new file mode 100644 index 00000000..b4ec3c31 --- /dev/null +++ b/thirdparty/libpng/pnglibconf.h @@ -0,0 +1,214 @@ +/* libpng 1.6.17 STANDARD API DEFINITION */ + +/* pnglibconf.h - library build configuration */ + +/* Libpng version 1.6.17 - March 26, 2015 */ + +/* Copyright (c) 1998-2014 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#define PNG_API_RULE 0 +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_USER_CHUNK_CACHE_MAX 1000 +#define PNG_USER_CHUNK_MALLOC_MAX 8000000 +#define PNG_USER_HEIGHT_MAX 1000000 +#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0 /* unknown */ +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/thirdparty/libpng/pngmem.c b/thirdparty/libpng/pngmem.c index c8a3f6f5..8b157e54 100644 --- a/thirdparty/libpng/pngmem.c +++ b/thirdparty/libpng/pngmem.c @@ -1,8 +1,8 @@ /* pngmem.c - stub functions for memory allocation * - * Last changed in libpng 1.4.2 [May 6, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 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.) * @@ -17,575 +17,244 @@ * identify the replacement functions. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #include "pngpriv.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 = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (png_get_copyright(NULL)); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); - } - else -#endif /* PNG_USER_MEM_SUPPORTED */ - struct_ptr = (png_voidp)farmalloc(size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); -} - -/* Free memory allocated by a png_create_struct() call */ +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Free a png_struct */ void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) +png_destroy_png_struct(png_structrp png_ptr) { -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, NULL, 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) + if (png_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); + /* png_free might call png_error and may certainly call + * png_get_mem_ptr, so fake a temporary png_struct to support this. + */ + png_struct dummy_struct = *png_ptr; + memset(png_ptr, 0, (sizeof *png_ptr)); + png_free(&dummy_struct, png_ptr); + +# ifdef PNG_SETJMP_SUPPORTED + /* We may have a jmp_buf left to deallocate. */ + png_free_jmpbuf(&dummy_struct); +# 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. - * - * 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_calloc(png_structp png_ptr, png_alloc_size_t size) -{ - png_voidp ret; - - ret = (png_malloc(png_ptr, size)); - if (ret != NULL) - png_memset(ret,0,(png_size_t)size); - return (ret); -} - -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_alloc_size_t size) -{ - png_voidp ret; - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_alloc_size_t size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { - png_warning(png_ptr, "Cannot Allocate > 64K"); - ret = NULL; - } - else -#endif - - if (size != (size_t)size) - ret = NULL; - else 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) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of Memory"); /* Note "O", "M" */ - else - png_warning(png_ptr, "Out Of Memory"); -#endif - return (NULL); - } - - if ((png_size_t)table & 0xfff0) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, - "Farmalloc didn't return normalized pointer"); - else - png_warning(png_ptr, - "Farmalloc didn't return normalized pointer"); -#endif - return (NULL); - } - - png_ptr->offset_table = table; - png_ptr->offset_table_ptr = farmalloc(num_blocks * - png_sizeof(png_bytep)); - - if (png_ptr->offset_table_ptr == NULL) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of memory"); /* Note "O", "m" */ - else - png_warning(png_ptr, "Out Of memory"); -#endif - return (NULL); - } - - 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) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); /* Note "o" and "M" */ - else - png_warning(png_ptr, "Out of Memory"); -#endif - return (NULL); - } - - ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; - } - else - ret = farmalloc(size); - -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL) - { - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory"); /* Note "o" and "m" */ - else - png_warning(png_ptr, "Out of memory"); /* Note "o" and "m" */ - } -#endif - - 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 == NULL || ptr == NULL) - return; - - 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 = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); - } -#endif /* PNG_USER_MEM_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(__FLAT__) - struct_ptr = (png_voidp)farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - struct_ptr = (png_voidp)halloc(size, 1); -# else - struct_ptr = (png_voidp)malloc(size); -# endif -#endif - if (struct_ptr != 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, NULL, 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 + * 64K. However, zlib may allocate more than 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_calloc(png_structp png_ptr, png_alloc_size_t size) +PNG_FUNCTION(png_voidp,PNGAPI +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; - ret = (png_malloc(png_ptr, size)); + ret = png_malloc(png_ptr, size); + if (ret != NULL) - png_memset(ret,0,(png_size_t)size); - return (ret); + memset(ret, 0, size); + + return ret; } -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_alloc_size_t size) +/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of + * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. + * Checking and error handling must happen outside this routine; it returns NULL + * if the allocation cannot be done (for any reason.) + */ +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) { - png_voidp ret; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr == NULL || size == 0) - return (NULL); - - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_alloc_size_t size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { + /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS + * allocators have also been removed in 1.6.0, so any 16-bit system now has + * to implement a user memory handler. This checks to be sure it isn't + * called with big numbers. + */ #ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Cannot Allocate > 64K"); + PNG_UNUSED(png_ptr) +#endif + + if (size > 0 && size <= PNG_SIZE_MAX +# ifdef PNG_MAX_MALLOC_64K + && size <= 65536U +# endif + ) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL && png_ptr->malloc_fn != NULL) + return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); + else #endif - return NULL; + return malloc((size_t)size); /* checked for truncation above */ } -#endif - /* Check for overflow */ -#if defined(__TURBOC__) && !defined(__FLAT__) - if (size != (unsigned long)size) - ret = NULL; else - ret = farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - if (size != (unsigned long)size) - ret = NULL; - else - ret = halloc(size, 1); -# else - if (size != (size_t)size) - ret = NULL; - else - ret = malloc((size_t)size); -# endif -#endif + return NULL; +} -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); -#endif +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 + * that arises because of the checks in png_realloc_array that are repeated in + * png_malloc_array. + */ +static png_voidp +png_malloc_array_checked(png_const_structrp png_ptr, int nelements, + size_t element_size) +{ + png_alloc_size_t req = nelements; /* known to be > 0 */ - return (ret); + if (req <= PNG_SIZE_MAX/element_size) + return png_malloc_base(png_ptr, req * element_size); + + /* The failure case when the request is too large */ + return NULL; +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_array,(png_const_structrp png_ptr, int nelements, + size_t element_size),PNG_ALLOCATED) +{ + if (nelements <= 0 || element_size == 0) + png_error(png_ptr, "internal error: array alloc"); + + return png_malloc_array_checked(png_ptr, nelements, element_size); +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) +{ + /* These are internal errors: */ + if (add_elements <= 0 || element_size == 0 || old_elements < 0 || + (old_array == NULL && old_elements > 0)) + png_error(png_ptr, "internal error: array realloc"); + + /* Check for overflow on the elements count (so the caller does not have to + * check.) + */ + if (add_elements <= INT_MAX - old_elements) + { + png_voidp new_array = png_malloc_array_checked(png_ptr, + old_elements+add_elements, element_size); + + if (new_array != NULL) + { + /* Because png_malloc_array worked the size calculations below cannot + * overflow. + */ + if (old_elements > 0) + memcpy(new_array, old_array, element_size*(unsigned)old_elements); + + memset((char*)new_array + element_size*(unsigned)old_elements, 0, + element_size*(unsigned)add_elements); + + return new_array; + } + } + + return NULL; /* error */ +} +#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ + +/* Various functions that have different error handling are derived from this. + * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate + * function png_malloc_default is also provided. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + ret = png_malloc_base(png_ptr, size); + + if (ret == NULL) + png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ + + return ret; +} + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED PNG_DEPRECATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + /* Passing 'NULL' here bypasses the application provided memory handler. */ + ret = png_malloc_base(NULL/*use malloc*/, size); + + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ + + return ret; +} +#endif /* USER_MEM */ + +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will issue a png_warning and return NULL instead of issuing a + * png_error, if it fails to allocate the requested memory. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + if (png_ptr != NULL) + { + png_voidp ret = png_malloc_base(png_ptr, size); + + if (ret != NULL) + return ret; + + png_warning(png_ptr, "Out of memory"); + } + + return NULL; } /* 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) +png_free(png_const_structrp 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; - } + png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); + else png_free_default(png_ptr, ptr); } -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) + +PNG_FUNCTION(void,PNGAPI +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) { if (png_ptr == NULL || ptr == NULL) return; +#endif /* USER_MEM */ -#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 */ - -/* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will set up png_malloc() to issue a png_warning and return NULL - * instead of issuing a png_error, if it fails to allocate the requested - * memory. - */ -png_voidp PNGAPI -png_malloc_warn(png_structp png_ptr, png_alloc_size_t size) -{ - png_voidp ptr; - png_uint_32 save_flags; - if (png_ptr == NULL) - return (NULL); - - save_flags = png_ptr->flags; - png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); - png_ptr->flags=save_flags; - return(ptr); -} - - #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 +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn) { if (png_ptr != NULL) @@ -601,11 +270,12 @@ png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI -png_get_mem_ptr(png_structp png_ptr) +png_get_mem_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) - return (NULL); - return ((png_voidp)png_ptr->mem_ptr); + return NULL; + + return png_ptr->mem_ptr; } -#endif /* PNG_USER_MEM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* USER_MEM */ +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pngpread.c b/thirdparty/libpng/pngpread.c index e33b4286..823dcad8 100644 --- a/thirdparty/libpng/pngpread.c +++ b/thirdparty/libpng/pngpread.c @@ -1,8 +1,8 @@ /* pngpread.c - read a png file in push mode * - * Last changed in libpng 1.4.3 [June 26, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,11 +11,10 @@ * and license in png.h */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED #include "pngpriv.h" +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + /* Push model modes */ #define PNG_READ_SIG_MODE 0 #define PNG_READ_CHUNK_MODE 1 @@ -27,9 +26,16 @@ #define PNG_READ_iTXt_MODE 7 #define PNG_ERROR_MODE 8 +#define PNG_PUSH_SAVE_BUFFER_IF_FULL \ +if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ + { png_push_save_buffer(png_ptr); return; } +#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ +if (png_ptr->buffer_size < N) \ + { png_push_save_buffer(png_ptr); return; } + void PNGAPI -png_process_data(png_structp png_ptr, png_infop info_ptr, - png_bytep buffer, png_size_t buffer_size) +png_process_data(png_structrp png_ptr, png_inforp info_ptr, + png_bytep buffer, png_size_t buffer_size) { if (png_ptr == NULL || info_ptr == NULL) return; @@ -42,11 +48,69 @@ png_process_data(png_structp png_ptr, png_infop info_ptr, } } +png_size_t PNGAPI +png_process_data_pause(png_structrp png_ptr, int save) +{ + if (png_ptr != NULL) + { + /* It's easiest for the caller if we do the save; then the caller doesn't + * have to supply the same data again: + */ + if (save != 0) + png_push_save_buffer(png_ptr); + else + { + /* This includes any pending saved bytes: */ + png_size_t remaining = png_ptr->buffer_size; + png_ptr->buffer_size = 0; + + /* So subtract the saved buffer size, unless all the data + * is actually 'saved', in which case we just return 0 + */ + if (png_ptr->save_buffer_size < remaining) + return remaining - png_ptr->save_buffer_size; + } + } + + return 0; +} + +png_uint_32 PNGAPI +png_process_data_skip(png_structrp png_ptr) +{ + png_uint_32 remaining = 0; + + if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE && + png_ptr->skip_length > 0) + { + /* At the end of png_process_data the buffer size must be 0 (see the loop + * above) so we can detect a broken call here: + */ + if (png_ptr->buffer_size != 0) + png_error(png_ptr, + "png_process_data_skip called inside png_process_data"); + + /* If is impossible for there to be a saved buffer at this point - + * otherwise we could not be in SKIP mode. This will also happen if + * png_process_skip is called inside png_process_data (but only very + * rarely.) + */ + if (png_ptr->save_buffer_size != 0) + png_error(png_ptr, "png_process_data_skip called with saved data"); + + remaining = png_ptr->skip_length; + png_ptr->skip_length = 0; + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + + return remaining; +} + /* 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) +png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr == NULL) return; @@ -71,30 +135,6 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr) break; } -#ifdef PNG_READ_tEXt_SUPPORTED - case PNG_READ_tEXt_MODE: - { - png_push_read_tEXt(png_ptr, info_ptr); - break; - } - -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - case PNG_READ_zTXt_MODE: - { - png_push_read_zTXt(png_ptr, info_ptr); - break; - } - -#endif -#ifdef 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); @@ -116,9 +156,9 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr) * routine. */ void /* PRIVATE */ -png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) { - png_size_t num_checked = png_ptr->sig_bytes, + png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ num_to_check = 8 - num_checked; if (png_ptr->buffer_size < num_to_check) @@ -127,7 +167,7 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr) } png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), - num_to_check); + 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)) @@ -135,6 +175,7 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr) 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"); } @@ -148,114 +189,75 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr) } void /* PRIVATE */ -png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) { - PNG_IHDR; - PNG_IDAT; - PNG_IEND; - PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_sCAL; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_sRGB; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_sPLT; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_zTXt; + png_uint_32 chunk_name; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; /* unknown handling method */ #endif - /* 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 + /* 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 + * 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)) + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; + png_byte chunk_tag[4]; - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + chunk_name = png_ptr->chunk_name; - if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + /* 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_IHDR) == 0) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + + if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) + if (png_ptr->push_length == 0) + return; + + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "Too many IDATs found"); + } + + if (chunk_name == png_IHDR) { if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } - else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + else if (chunk_name == png_IEND) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; @@ -263,70 +265,25 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); - - if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + if (chunk_name == png_PLTE) 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"); - } } - #endif - else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + + else if (chunk_name == png_PLTE) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } - else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + else if (chunk_name == png_IDAT) { - /* 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_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"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - if (png_ptr->push_length == 0) - return; - - if (png_ptr->mode & PNG_AFTER_IDAT) - png_benign_error(png_ptr, "Too many IDATs 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 = @@ -337,295 +294,215 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + else if (png_ptr->chunk_name == png_gAMA) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + else if (png_ptr->chunk_name == png_sBIT) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + else if (png_ptr->chunk_name == png_cHRM) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + else if (chunk_name == png_sRGB) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + else if (png_ptr->chunk_name == png_iCCP) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + else if (chunk_name == png_sPLT) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + else if (chunk_name == png_tRNS) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + else if (chunk_name == png_bKGD) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + else if (chunk_name == png_hIST) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + else if (chunk_name == png_pHYs) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + else if (chunk_name == png_oFFs) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + else if (chunk_name == png_pCAL) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + else if (chunk_name == png_sCAL) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + else if (chunk_name == png_tIME) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + else if (chunk_name == png_tEXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + else if (chunk_name == png_zTXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + else if (chunk_name == png_iTXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } - #endif + else { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; } void /* PRIVATE */ -png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +png_push_crc_skip(png_structrp 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) +png_push_crc_finish(png_structrp png_ptr) { - if (png_ptr->skip_length && png_ptr->save_buffer_size) + if (png_ptr->skip_length != 0 && png_ptr->save_buffer_size != 0) { - png_size_t save_size; + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'save_buffer_size', but + * they are of different types and we don't know which variable has the + * fewest bits. Carefully select the smaller and cast it to the type of + * the larger - this cannot overflow. Do not cast in the following test + * - it will break on either 16 or 64 bit platforms. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; - 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; + skip_length = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - png_ptr->skip_length -= save_size; + png_ptr->skip_length -= skip_length; 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) + if (png_ptr->skip_length != 0 && png_ptr->current_buffer_size != 0) { - png_size_t save_size; + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'current_buffer_size', here, + * the same problem exists as above and the same solution. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; - 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; + skip_length = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - png_ptr->skip_length -= save_size; + png_ptr->skip_length -= skip_length; 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->skip_length == 0) { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(4) png_crc_finish(png_ptr, 0); png_ptr->process_mode = PNG_READ_CHUNK_MODE; } } -void PNGAPI +void PNGCBAPI png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) { png_bytep ptr; @@ -634,23 +511,24 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) return; ptr = buffer; - if (png_ptr->save_buffer_size) + if (png_ptr->save_buffer_size != 0) { 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); + 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) + if (length != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size; @@ -660,7 +538,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) else save_size = png_ptr->current_buffer_size; - png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + 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; @@ -668,9 +546,9 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) } void /* PRIVATE */ -png_push_save_buffer(png_structp png_ptr) +png_push_save_buffer(png_structrp png_ptr) { - if (png_ptr->save_buffer_size) + if (png_ptr->save_buffer_size != 0) { if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) { @@ -680,40 +558,44 @@ png_push_save_buffer(png_structp png_ptr) 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++) + i < istop; i++, sp++, dp++) { *dp = *sp; } } } if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > - png_ptr->save_buffer_max) + png_ptr->save_buffer_max) { png_size_t new_max; png_bytep old_buffer; if (png_ptr->save_buffer_size > PNG_SIZE_MAX - - (png_ptr->current_buffer_size + 256)) + (png_ptr->current_buffer_size + 256)) { - png_error(png_ptr, "Potential overflow of save_buffer"); + png_error(png_ptr, "Potential overflow of save_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_warn(png_ptr, - (png_size_t)new_max); + (png_size_t)new_max); + if (png_ptr->save_buffer == NULL) { - png_free(png_ptr, old_buffer); - png_error(png_ptr, "Insufficient memory for save_buffer"); + png_free(png_ptr, old_buffer); + old_buffer = NULL; + png_error(png_ptr, "Insufficient memory for save_buffer"); } - png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); png_free(png_ptr, old_buffer); + old_buffer = NULL; png_ptr->save_buffer_max = new_max; } if (png_ptr->current_buffer_size) { - png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + 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; @@ -723,7 +605,7 @@ png_push_save_buffer(png_structp png_ptr) } void /* PRIVATE */ -png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, +png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { png_ptr->current_buffer = buffer; @@ -733,99 +615,99 @@ png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, } void /* PRIVATE */ -png_push_read_IDAT(png_structp png_ptr) +png_push_read_IDAT(png_structrp png_ptr) { - PNG_IDAT; - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; + png_byte chunk_tag[4]; - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - + /* TODO: this code can be commoned up with the same code in push_read */ + PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + if (png_ptr->chunk_name != png_IDAT) { png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) 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) + + if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) { - png_size_t save_size; + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; - if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. Do not cast in the following test - it + * will break on either 16 or 64 bit platforms. + */ + if (idat_size < save_size) + save_size = (png_size_t)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; + idat_size = (png_uint_32)save_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->idat_size -= idat_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) + + if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) { - png_size_t save_size; + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; - if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. + */ + if (idat_size < save_size) + save_size = (png_size_t)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; + idat_size = (png_uint_32)save_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->idat_size -= idat_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->idat_size == 0) { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(4) png_crc_finish(png_ptr, 0); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->zowner = 0; } } void /* PRIVATE */ -png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, +png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { /* The caller checks for a non-zero buffer length. */ @@ -837,35 +719,37 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, * handle the uncompressed results. */ png_ptr->zstream.next_in = buffer; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_in = (uInt)buffer_length; /* Keep going until the decompressed data is all processed * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && - !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { int ret; /* We have data for zlib, but we must check that zlib - * has somewhere to put the results. It doesn't matter + * has someplace to put the results. It doesn't matter * if we don't expect any results -- it may be the input * data is just the LZ end code. */ if (!(png_ptr->zstream.avail_out > 0)) { - png_ptr->zstream.avail_out = - (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + png_ptr->zstream.next_out = png_ptr->row_buf; } /* Using Z_SYNC_FLUSH here means that an unterminated - * LZ stream can still be handled (a stream with a missing - * end code), otherwise (Z_NO_FLUSH) a future zlib - * implementation might defer output and, therefore, - * change the current behavior. (See comments in inflate.c - * for why this doesn't happen at present with zlib 1.2.5.) + * LZ stream (a stream with a missing end code) can still + * be handled, otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and therefore + * change the current behavior (see comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5). */ ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); @@ -873,7 +757,8 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, if (ret != Z_OK && ret != Z_STREAM_END) { /* Terminate the decompression. */ - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; /* This may be a truncated stream (missing or * damaged end code). Treat that as a warning. @@ -881,6 +766,7 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, if (png_ptr->row_number >= png_ptr->num_rows || png_ptr->pass > 6) png_warning(png_ptr, "Truncated compressed data in IDAT"); + else png_error(png_ptr, "Decompression error in IDAT"); @@ -900,7 +786,9 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, { /* Extra data. */ png_warning(png_ptr, "Extra compressed data in IDAT"); - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + /* Do no more processing; skip the unprocessed * input check below. */ @@ -914,7 +802,7 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, /* And check for the end of the stream. */ if (ret == Z_STREAM_END) - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; } /* All the data should have been processed, if anything @@ -922,43 +810,66 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, * after the zlib end code. */ if (png_ptr->zstream.avail_in > 0) - png_warning(png_ptr, "Extra compression data"); + png_warning(png_ptr, "Extra compression data in IDAT"); } void /* PRIVATE */ -png_push_process_row(png_structp png_ptr) +png_push_process_row(png_structrp 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; + /* 1.5.6: row_info moved out of png_struct to a local here. */ + png_row_info row_info; - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - 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])); + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } - png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced row count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations != 0) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "progressive row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal progressive row size calculation error"); - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { 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); + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); - switch (png_ptr->pass) - { + switch (png_ptr->pass) + { case 0: { int i; @@ -1109,6 +1020,8 @@ png_push_process_row(png_structp png_ptr) break; } + + default: case 6: { png_push_have_row(png_ptr, png_ptr->row_buf + 1); @@ -1131,44 +1044,46 @@ png_push_process_row(png_structp png_ptr) } void /* PRIVATE */ -png_read_push_finish_row(png_structp png_ptr) +png_read_push_finish_row(png_structrp png_ptr) { +#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; /* Height of interlace block. This is not currently used - if you need * it, uncomment it here and in png.h - PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte 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; #ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - png_memset(png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); + memset(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++; + png_ptr->pass++; if (png_ptr->pass > 7) png_ptr->pass--; @@ -1177,572 +1092,66 @@ png_read_push_finish_row(png_structp png_ptr) 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_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) 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]; + 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); } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -} - -#ifdef 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"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#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_size_t)(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; +#endif /* READ_INTERLACING */ } 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; - int ret; - - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_crc_finish(png_ptr); - -#ifdef PNG_MAX_MALLOC_64K - if (png_ptr->skip_length) - return; -#endif - - key = png_ptr->current_text; - - 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_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; -#endif - text_ptr->text = text; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, key); - png_free(png_ptr, text_ptr); - png_ptr->current_text = NULL; - - if (ret) - png_warning(png_ptr, "Insufficient memory to store text chunk"); - } -} -#endif - -#ifdef 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"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#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_size_t)(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; - - for (text = key; *text; text++) - /* Empty loop */ ; - - /* zTXt can't have zero text */ - if (text >= key + png_ptr->current_text_size) - { - png_ptr->current_text = NULL; - png_free(png_ptr, key); - return; - } - - text++; - - if (*text != PNG_TEXT_COMPRESSION_zTXt) /* Check compression byte */ - { - png_ptr->current_text = NULL; - 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_ptr->current_text = NULL; - 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_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_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_ptr->current_text = NULL; - png_free(png_ptr, key); - png_free(png_ptr, text); - return; - } - - png_ptr->current_text = NULL; - png_free(png_ptr, key); - key = text; - text += key_size; - - text_ptr = (png_textp)png_malloc(png_ptr, - png_sizeof(png_text)); - text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; - text_ptr->key = key; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; -#endif - text_ptr->text = text; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, key); - png_free(png_ptr, text_ptr); - - if (ret) - png_warning(png_ptr, "Insufficient memory to store text chunk"); - } -} -#endif - -#ifdef 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"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#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_size_t)(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; - int ret; - - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_crc_finish(png_ptr); - -#ifdef PNG_MAX_MALLOC_64K - if (png_ptr->skip_length) - return; -#endif - - key = png_ptr->current_text; - - for (lang = key; *lang; lang++) - /* Empty loop */ ; - - if (lang < key + png_ptr->current_text_size - 3) - 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 */ - - text=lang_key; - - if (lang_key < key + png_ptr->current_text_size - 1) - { - for (; *text; text++) - /* Empty loop */ ; - } - - if (text < key + png_ptr->current_text_size) - text++; - - text_ptr = (png_textp)png_malloc(png_ptr, - png_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); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_ptr->current_text = NULL; - - png_free(png_ptr, text_ptr); - if (ret) - png_warning(png_ptr, "Insufficient memory to store iTXt chunk"); - } -} -#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; - - if (!(png_ptr->chunk_name[0] & 0x20)) - { -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) - { -#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_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name) - 1] - = '\0'; - - png_ptr->unknown_chunk.size = (png_size_t)length; - - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - - else - { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, - (png_size_t)length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); - } - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - if (png_ptr->read_user_chunk_fn != NULL) - { - /* Callback to user unknown chunk handler */ - int ret; - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - - if (ret == 0) - { - if (!(png_ptr->chunk_name[0] & 0x20)) - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) - png_chunk_error(png_ptr, "unknown critical chunk"); - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - } - } - - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - 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) +png_push_have_info(png_structrp png_ptr, png_inforp 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) +png_push_have_end(png_structrp png_ptr, png_inforp 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) +png_push_have_row(png_structrp 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); } +#ifdef PNG_READ_INTERLACING_SUPPORTED void PNGAPI -png_progressive_combine_row (png_structp png_ptr, - png_bytep old_row, png_bytep new_row) +png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, + png_const_bytep new_row) { - PNG_CONST int FARDATA png_pass_dsp_mask[7] = - {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; - if (png_ptr == NULL) return; - 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]); + /* new_row is a flag here - if it is NULL then the app callback was called + * from an empty row (see the calls to png_struct::row_fn below), otherwise + * it must be png_ptr->row_buf+1 + */ + if (new_row != NULL) + png_combine_row(png_ptr, old_row, 1/*blocky display*/); } +#endif /* READ_INTERLACING */ 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_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) { if (png_ptr == NULL) return; @@ -1755,11 +1164,11 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, } png_voidp PNGAPI -png_get_progressive_ptr(png_structp png_ptr) +png_get_progressive_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); return png_ptr->io_ptr; } -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h index 8b0621c0..5980a3fc 100644 --- a/thirdparty/libpng/pngpriv.h +++ b/thirdparty/libpng/pngpriv.h @@ -1,9 +1,8 @@ /* pngpriv.h - private declarations for use inside libpng * - * libpng version 1.4.4 - September 23, 2010 - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -13,7 +12,7 @@ */ /* The symbols declared in this file (including the functions declared - * as PNG_EXTERN) are PRIVATE. They are not part of the libpng public + * as extern) are PRIVATE. They are not part of the libpng public * interface, and are not recommended for use by regular applications. * Some of them may become public in the future; others may stay private, * change in an incompatible way, or even disappear. @@ -24,27 +23,382 @@ #ifndef PNGPRIV_H #define PNGPRIV_H -#ifndef PNG_VERSION_INFO_ONLY - -#include - -#ifndef PNG_EXTERN -/* The functions exported by PNG_EXTERN are 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 +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) */ -# define PNG_EXTERN +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ + +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include #endif +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. + */ +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include + + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif + +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif + +#ifdef PNG_USER_CONFIG +# include "pngusr.h" + /* These should have been defined in pngusr.h */ +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD "Custom libpng build" +# endif +# ifndef PNG_USER_DLLFNAME_POSTFIX +# define PNG_USER_DLLFNAME_POSTFIX "Cb" +# endif +#endif + +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions. + * + * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they + * can only be turned on automatically if that is supported too. If + * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail + * to compile with an appropriate #error if ALIGNED_MEMORY has been turned + * off. + * + * Note that gcc-4.9 defines __ARM_NEON instead of __ARM_NEON__, so we + * check both variants. + */ +# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon + + /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used + * if possible - if __ARM_NEON__ is set and the compiler version is not known + * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can + * be: + * + * 1 The intrinsics code (the default with __ARM_NEON__) + * 2 The hand coded assembler (the default without __ARM_NEON__) + * + * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however + * this is *NOT* supported and may cease to work even after a minor revision + * to libpng. It *is* valid to do this for testing purposes, e.g. speed + * testing or a new compiler, but the results should be communicated to the + * libpng implementation list for incorporation in the next minor release. + */ +# ifndef PNG_ARM_NEON_IMPLEMENTATION +# if defined(__ARM_NEON__) || defined(__ARM_NEON) +# if defined(__clang__) + /* At present it is unknown by the libpng developers which versions + * of clang support the intrinsics, however some or perhaps all + * versions do not work with the assembler so this may be + * irrelevant, so just use the default (do nothing here.) + */ +# elif defined(__GNUC__) + /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to + * work, so if this *is* GCC, or G++, look for a version >4.5 + */ +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* no GNUC support */ +# endif /* __GNUC__ */ +# else /* !defined __ARM_NEON__ */ + /* The 'intrinsics' code simply won't compile without this -mfpu=neon: + */ +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* __ARM_NEON__ */ +# endif /* !PNG_ARM_NEON_IMPLEMENTATION */ + +# ifndef PNG_ARM_NEON_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_ARM_NEON_IMPLEMENTATION 1 +# endif +#endif /* PNG_ARM_NEON_OPT > 0 */ + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) extern type name array +#endif + +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) +#endif + +#ifndef PNG_INTERNAL_CALLBACK +# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ + extern PNG_FUNCTION(type, (PNGCBAPI name), args, PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) + * + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif +# endif +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# endif +#endif + +#include "png.h" + +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + +/* SECURITY and SAFETY: + * + * libpng is built with support for internal limits on image dimensions and + * memory usage. These are documented in scripts/pnglibconf.dfa of the + * source and recorded in the machine generated header file pnglibconf.h. + */ + +/* 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. + * + * zlib provides 'MAXSEG_64K' which, if defined, indicates the + * same limit and pngconf.h (already included) sets the limit + * if certain operating systems are detected. + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* If warnings or errors are turned off the code is disabled or redirected here. + * From 1.5.4 functions have been added to allow very limited formatting of + * error and warning messages - this code will also be disabled here. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) +#endif +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_fixed_error(s1,s2) png_err(s1) +#endif + +/* C allows up-casts from (void*) to any pointer and (const void*) to any + * pointer to a const object. C++ regards this as a type error and requires an + * explicit, static, cast and provides the static_cast<> rune to ensure that + * const is not cast away. + */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY /* 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) ||\ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + /* png.c requires the following ANSI-C constants if the conversion of + * floating point to ASCII is implemented therein: + * + * DBL_DIG Maximum number of decimal digits (can be set to any constant) + * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) + * DBL_MAX Maximum floating point number (can be set to an arbitrary value) + */ +# include -#ifdef PNG_FLOATING_POINT_SUPPORTED -# ifdef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) /* 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. @@ -63,11 +417,6 @@ # endif #endif -/* Codewarrior on NT has linking problems without this. */ -#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) -# define PNG_ALWAYS_EXTERN -#endif - /* This provides the non-ANSI (far) memory allocation routines. */ #if defined(__TURBOC__) && defined(__MSDOS__) # include @@ -78,24 +427,95 @@ defined(_WIN32) || defined(__WIN32__) # include /* defines _WINDOWS_ macro */ #endif +#endif /* PNG_VERSION_INFO_ONLY */ + +/* Moved here around 1.5.0beta36 from pngconf.h */ +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* Memory model/platform independent fns */ +#ifndef PNG_ABORT +# ifdef _WINDOWS_ +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif +#endif + +/* These macros may need to be architecture dependent. */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#ifdef offsetof +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +#else +# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ +#endif +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ + +#ifndef PNG_ALIGN_TYPE + /* Default to using aligned access optimizations and requiring alignment to a + * multiple of the data type size. Override in a compiler specific fashion + * if necessary by inserting tests here: + */ +# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE +#endif + +#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE + /* This is used because in some compiler implementations non-aligned + * structure members are supported, so the offsetof approach below fails. + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access + * is good for performance. Do not do this unless you have tested the result + * and understand it. + */ +# define png_alignof(type) (sizeof (type)) +#else +# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET +# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# else +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) (1) +# endif + /* Else leave png_alignof undefined to prevent use thereof */ +# endif +#endif + +/* This implicitly assumes alignment is always to a power of 2. */ +#ifdef png_alignof +# define png_isaligned(ptr, type)\ + ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) +#else +# define png_isaligned(ptr, type) 0 +#endif + +/* End of memory model/platform independent support */ +/* End of 1.5.0beta36 move from pngconf.h */ + +/* CONSTANTS and UTILITY MACROS + * These are used internally by libpng and not exposed in the API + */ /* Various modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ #define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ #define PNG_HAVE_IEND 0x10 -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 -#define PNG_HAVE_sRGB 0x80 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ #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 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001 @@ -104,75 +524,72 @@ #define PNG_SHIFT 0x0008 #define PNG_SWAP_BYTES 0x0010 #define PNG_INVERT_MONO 0x0020 -#define PNG_QUANTIZE 0x0040 /* formerly PNG_DITHER */ -#define PNG_BACKGROUND 0x0080 +#define PNG_QUANTIZE 0x0040 +#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ #define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ -#define PNG_16_TO_8 0x0400 +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ #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 */ - /* 0x800000L Unused */ -#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - +#define PNG_FILLER 0x8000 +#define PNG_PACKSWAP 0x10000 +#define PNG_SWAP_ALPHA 0x20000 +#define PNG_STRIP_ALPHA 0x40000 +#define PNG_INVERT_ALPHA 0x80000 +#define PNG_USER_TRANSFORM 0x100000 +#define PNG_RGB_TO_GRAY_ERR 0x200000 +#define PNG_RGB_TO_GRAY_WARN 0x400000 +#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ /* 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_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ #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 - /* 0x1000 unused */ - /* 0x2000 unused */ - /* 0x4000 unused */ -#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 -#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L -#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000L /* Added to libpng-1.4.0 */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) @@ -189,6 +606,17 @@ abs((int)((c1).green) - (int)((c2).green)) + \ abs((int)((c1).blue) - (int)((c2).blue))) +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + /* Added to libpng-1.2.6 JB */ #define PNG_ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ @@ -201,34 +629,197 @@ * integers, "value" a variable. Added to libpng-1.2.6 JB */ #define PNG_OUT_OF_RANGE(value, ideal, delta) \ - ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) -/* Constant strings for known chunk types. If you need to add a chunk, - * define the name here, and add an invocation of the macro wherever it's - * needed. +/* Conversions between fixed and floating point, only defined if + * required (to make sure the code doesn't accidentally use float + * when it is supposedly disabled.) */ -#define PNG_IHDR PNG_CONST png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} -#define PNG_IDAT PNG_CONST png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} -#define PNG_IEND PNG_CONST png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} -#define PNG_PLTE PNG_CONST png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} -#define PNG_bKGD PNG_CONST png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} -#define PNG_cHRM PNG_CONST png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} -#define PNG_gAMA PNG_CONST png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} -#define PNG_hIST PNG_CONST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} -#define PNG_iCCP PNG_CONST png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} -#define PNG_iTXt PNG_CONST png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} -#define PNG_oFFs PNG_CONST png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} -#define PNG_pCAL PNG_CONST png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} -#define PNG_sCAL PNG_CONST png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} -#define PNG_pHYs PNG_CONST png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} -#define PNG_sBIT PNG_CONST png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} -#define PNG_sPLT PNG_CONST png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} -#define PNG_sRGB PNG_CONST png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} -#define PNG_sTER PNG_CONST png_byte png_sTER[5] = {115, 84, 69, 82, '\0'} -#define PNG_tEXt PNG_CONST png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} -#define PNG_tIME PNG_CONST png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} -#define PNG_tRNS PNG_CONST png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} -#define PNG_zTXt PNG_CONST png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The floating point conversion can't overflow, though it can and + * does lose accuracy relative to the original fixed point value. + * In practice this doesn't matter because png_fixed_point only + * stores numbers with very low precision. The png_ptr and s + * arguments are unused by default but are there in case error + * checking becomes a requirement. + */ +#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) + +/* The fixed point conversion performs range checking and evaluates + * its argument multiple times, so must be used with care. The + * range checking uses the PNG specification values for a signed + * 32 bit fixed point value except that the values are deliberately + * rounded-to-zero to an integral value - 21474 (21474.83 is roughly + * (2^31-1) * 100000). 's' is a string that describes the value being + * converted. + * + * NOTE: this macro will raise a png_error if the range check fails, + * therefore it is normally only appropriate to use this on values + * that come from API calls or other sources where an out of range + * error indicates a programming error, not a data error! + * + * NOTE: by default this is off - the macro is not used - because the + * function call saves a lot of code. + */ +#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED +#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ + ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ +#endif + +/* Constants for known chunk types. If you need to add a chunk, define the name + * here. For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. + * + * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values + * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string + * to be generated if required. + * + * PNG_32b correctly produces a value shifted by up to 24 bits, even on + * architectures where (int) is only 16 bits. + */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* The following will work on (signed char*) strings, whereas the get_uint_32 + * macro will fail on top-bit-set values because of the sign extension. + */ +#define PNG_CHUNK_FROM_STRING(s)\ + PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) + +/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is + * signed and the argument is a (char[]) This macro will fail miserably on + * systems where (char) is more than 8 bits. + */ +#define PNG_STRING_FROM_CHUNK(s,c)\ + (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ + ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ + ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ + ((char*)(s))[3]=(char)((c & 0xff))) + +/* Do the same but terminate with a null character. */ +#define PNG_CSTRING_FROM_CHUNK(s,c)\ + (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS. This will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + +/* This is used for 16 bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) \ + ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* SIMPLIFIED_READ/WRITE */ /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ @@ -236,94 +827,154 @@ extern "C" { #endif /* __cplusplus */ -/* These 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. +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. */ -/* Allocate memory for an internal libpng struct */ -PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); + +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); + +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (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),PNG_ALLOCATED); /* Free memory from internal libpng struct */ -PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); -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)); +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); /* Function to allocate memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); /* Function to free memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); -/* Next four functions are used internally as callbacks. PNGAPI is required - * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ +/* Next four functions are used internally as callbacks. PNGCBAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to + * PNGCBAPI at 1.5.0 + */ -PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); #endif -PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED -PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); -#endif +# ifdef PNG_STDIO_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); +# endif #endif /* Reset the CRC variable */ -PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); + +/* Read and check the PNG file signature */ +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); /* Read the chunk header (length + type name) */ -PNG_EXTERN png_uint_32 png_read_chunk_header PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); /* 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 void png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, png_size_t chunklength, png_size_t prefix_length, - png_size_t *data_length)); -#endif +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); #endif /* Write various chunks */ @@ -331,310 +982,256 @@ PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); /* 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_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp 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_EMPTY); -PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, - png_uint_32 num_pal)); +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); -PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); -PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); #ifdef 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 +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); #endif #ifdef PNG_WRITE_sBIT_SUPPORTED -PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, - int color_type)); +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); #endif #ifdef 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 -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)); +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ #endif #ifdef PNG_WRITE_sRGB_SUPPORTED -PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, - int intent)); +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); #endif #ifdef 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 */ +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. + */ #endif #ifdef PNG_WRITE_sPLT_SUPPORTED -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_sPLT_tp palette)); +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, + png_const_bytep trans, png_const_color_16p values, int number, + int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_bKGD_SUPPORTED -PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_color_16p values, int color_type)); +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); #endif +/* Chunks that have keywords */ #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, int compression),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, + int compression, png_const_charp key, png_const_charp lang, + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); #endif #ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ -PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED -PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); #endif #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_tIME_SUPPORTED -PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_timep mod_time)); +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) -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 +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); #endif /* Called when finished processing a row of data */ -PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); /* Internal use only. Called before first row of data */ -PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr, - png_byte bit_depth)); +/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an + * array of png_ptr->width pixels. If the image is not interlaced or this + * is the final pass this just does a memcpy, otherwise the "display" flag + * is used to determine whether to copy pixels that are not in the current pass. + * + * Because 'png_do_read_interlace' (below) replicates pixels this allows this + * function to achieve the documented 'blocky' appearance during interlaced read + * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' + * are not changed if they are not in the current pass, when display is 0. + * + * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. + * + * The API always reads from the png_struct row buffer and always assumes that + * it is full width (png_do_read_interlace has already been called.) + * + * This function is only ever used to write to row buffers provided by the + * caller of the relevant libpng API and the row must have already been + * transformed by the read transformations. + * + * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed + * bitmasks for use within the code, otherwise runtime generated masks are used. + * The default is compile time masks. + */ +#ifndef PNG_USE_COMPILE_TIME_MASKS +# define PNG_USE_COMPILE_TIME_MASKS 1 #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)); +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); #ifdef 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)); +/* Expand an interlaced row: the 'row_info' describes the pass data that has + * been read in and must correspond to the pixels in 'row', the pixels are + * expanded (moved apart) in 'row' to match the final layout, when doing this + * the pixels are *replicated* to the intervening space. This is essential for + * the correct operation of png_combine_row, above. */ -PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); #endif /* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ #ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); #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)); +/* Unfilter a row: check the filter value before calling this, there is no point + * calling it for PNG_FILTER_VALUE_NONE. + */ +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); /* 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)); +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); -/* 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)); +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ + +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif /* SEQUENTIAL_READ */ /* Initialize the row buffers, etc. */ -PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED /* 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 */ -#ifdef 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 - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); #endif +/* Shared transform functions, defined in pngtran.c */ #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)); +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); #endif +#ifdef PNG_16BIT_SUPPORTED #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)); +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif #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 - -#ifdef 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 - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED -PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p sig_bits)); +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #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 - -#ifdef PNG_READ_16_TO_8_SUPPORTED -PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -PNG_EXTERN void png_do_quantize PNGARG((png_row_infop row_info, - png_bytep row, png_bytep palette_lookup, png_bytep quantize_lookup)); - -# ifdef PNG_CORRECT_PALETTE_SUPPORTED -PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette)); -# endif +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #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 - -#ifdef 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 - -#ifdef 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 - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_color, 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)); -#else -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_color, png_color_16p background)); -#endif -#endif - -#ifdef 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 - -#ifdef 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)); +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif /* The following decodes the appropriate chunks, and does error correction, @@ -642,309 +1239,666 @@ PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, */ /* 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)); +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #ifdef PNG_READ_bKGD_SUPPORTED -PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_cHRM_SUPPORTED -PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_gAMA_SUPPORTED -PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_hIST_SUPPORTED -PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_iCCP_SUPPORTED -PNG_EXTERN void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_iCCP */ #ifdef PNG_READ_iTXt_SUPPORTED -PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_oFFs_SUPPORTED -PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pCAL_SUPPORTED -PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pHYs_SUPPORTED -PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sBIT_SUPPORTED -PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sCAL_SUPPORTED -PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sPLT_SUPPORTED -PNG_EXTERN void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_sPLT_SUPPORTED */ +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_sPLT */ #ifdef PNG_READ_sRGB_SUPPORTED -PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tEXt_SUPPORTED -PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tIME_SUPPORTED -PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tRNS_SUPPORTED -PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_zTXt_SUPPORTED -PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif -PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); -PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_bytep chunk_name)); +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ /* 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)); +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif -PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); +#endif #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_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)); -#ifdef 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 -#ifdef 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 -#ifdef 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 +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, + png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +# ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ -#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)); +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ #endif /* Added at libpng version 1.4.0 */ -#ifdef PNG_cHRM_SUPPORTED -PNG_EXTERN int png_check_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 +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). + */ +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); -#ifdef PNG_cHRM_SUPPORTED -#ifdef PNG_CHECK_cHRM_SUPPORTED -/* Added at libpng version 1.2.34 and 1.4.0 */ -PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, - unsigned long *hi_product, unsigned long *lo_product)); -#endif +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + +/* Routines for checking parts of an ICC profile. */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ #endif +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ +#endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ /* Added at libpng version 1.4.0 */ -PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type)); +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); -/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ -PNG_EXTERN void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr)); +/* Added at libpng version 1.5.10 */ +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); +#endif -/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ -PNG_EXTERN void png_write_destroy PNGARG((png_structp png_ptr)); +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); +#endif -#ifdef USE_FAR_KEYWORD /* memory model conversion function */ -PNG_EXTERN void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, - int check)); -#endif /* USE_FAR_KEYWORD */ - -/* 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. +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) */ -#ifdef PNG_DEBUG -#if (PNG_DEBUG > 0) -#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) -#include -#if (PNG_DEBUG > 1) -#ifndef _DEBUG -# define _DEBUG -#endif -#ifndef png_debug -#define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) -#endif -#ifndef png_debug1 -#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) -#endif -#ifndef png_debug2 -#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) -#endif -#endif -#else /* PNG_DEBUG_FILE || !_MSC_VER */ -#ifndef PNG_DEBUG_FILE -#define PNG_DEBUG_FILE stderr -#endif /* PNG_DEBUG_FILE */ +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); -#if (PNG_DEBUG > 1) -/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on - * non-ISO compilers +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. */ -# ifdef __STDC__ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ - } -# endif -# else /* __STDC __ */ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1,p2); \ - } -# endif -# endif /* __STDC __ */ -#endif /* (PNG_DEBUG > 1) */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); -#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) +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ #endif -/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + +/* ASCII to FP interfaces, currently only implemented if sCAL + * support is required. + */ +#if defined(PNG_sCAL_SUPPORTED) +/* MAX_DIGITS is actually the maximum number of characters in an sCAL + * width or height, derived from the precision (number of significant + * digits - a build time settable option) and assumptions about the + * maximum ridiculous exponent. + */ +#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) + +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), + PNG_EMPTY); +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); +#endif /* FIXED_POINT */ +#endif /* sCAL */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* An internal API to validate the format of a floating point number. + * The result is the index of the next character. If the number is + * not valid it will be the index of a character in the supposed number. + * + * The format of a number is defined in the PNG extensions specification + * and this API is strictly conformant to that spec, not anyone elses! + * + * The format as a regular expression is: + * + * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? + * + * or: + * + * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? + * + * The complexity is that either integer or fraction must be present and the + * fraction is permitted to have no digits only if the integer is present. + * + * NOTE: The dangling E problem. + * There is a PNG valid floating point number in the following: + * + * PNG floating point numbers are not greedy. + * + * Working this out requires *TWO* character lookahead (because of the + * sign), the parser does not do this - it will fail at the 'r' - this + * doesn't matter for PNG sCAL chunk values, but it requires more care + * if the value were ever to be embedded in something more complex. Use + * ANSI-C strtod if you need the lookahead. + */ +/* State table for the parser. */ +#define PNG_FP_INTEGER 0 /* before or in integer */ +#define PNG_FP_FRACTION 1 /* before or in fraction */ +#define PNG_FP_EXPONENT 2 /* before or in exponent */ +#define PNG_FP_STATE 3 /* mask for the above */ +#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ +#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ +#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ +#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ +#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ +#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ + +/* Result codes for the parser (boolean - true meants ok, false means + * not ok yet.) + */ +#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ +#define PNG_FP_OK 1 /* The number is valid */ + +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + +/* The actual parser. This can be called repeatedly. It updates + * the index into the string and the state variable (which must + * be initialized to 0). It returns a result code, as above. There + * is no point calling the parser any more if it fails to advance to + * the end of the string - it is stuck on an invalid character (or + * terminated by '\0'). + * + * Note that the pointer will consume an E or even an E+ and then leave + * a 'maybe' state even though a preceding integer.fraction is valid. + * The PNG_FP_WAS_VALID flag indicates that a preceding substring was + * a valid number. It's possible to recover from this by calling + * the parser again (from the start, with state 0) but with a string + * that omits the last character (i.e. set the size to the index of + * the problem character.) This has not been tested within libpng. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); + +/* This is the same but it checks a complete string and returns true + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); +#endif /* pCAL || sCAL */ + +#if defined(PNG_GAMMA_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* Added at libpng version 1.5.0 */ +/* This is a utility to provide a*times/div (rounded) and indicate + * if there is an overflow. The result is a boolean - false (0) + * for overflow, true (1) if no overflow, in which case *res + * holds the result. + */ +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* Same deal, but issue a warning on overflow and return 0. */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); +#endif + +#ifdef PNG_GAMMA_SUPPORTED +/* Calculate a reciprocal - used for gamma values. This returns + * 0 if the argument is 0 in order to maintain an undefined value; + * there are no warnings. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The same but gives a reciprocal of the product of two fixed point + * values. Accuracy is suitable for gamma calculations but this is + * not exact - use png_muldiv for that. Only required at present on read. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Internal fixed point gamma correction. These APIs are called as + * required to convert single values - they don't need to be fast, + * they are not used when processing image pixel values. + * + * While the input is an 'unsigned' value it must actually be the + * correct bit value - 0..255 or 0..65535 as required. + */ +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +/* Maintainer: Put new private prototypes here ^ */ + +#include "pngdebug.h" #ifdef __cplusplus } diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c index 92060d2b..6764dbe5 100644 --- a/thirdparty/libpng/pngread.c +++ b/thirdparty/libpng/pngread.c @@ -1,8 +1,8 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -14,190 +14,68 @@ * read a PNG file or stream. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED #include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif +#ifdef PNG_READ_SUPPORTED /* 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) +PNG_FUNCTION(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),PNG_ALLOCATED) { - -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL)); +#ifndef PNG_USER_MEM_SUPPORTED + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + 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) +PNG_FUNCTION(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),PNG_ALLOCATED) { -#endif /* PNG_USER_MEM_SUPPORTED */ + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; - volatile int png_cleanup_needed = 0; - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - - int i; - - png_debug(1, "in png_create_read_struct"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - malloc_fn, mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; -# ifdef PNG_USER_CHUNK_CACHE_MAX - /* Added at libpng-1.2.43 and 1.4.0 */ - png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; -# endif -# ifdef PNG_SET_USER_CHUNK_MALLOC_MAX - /* Added at libpng-1.2.43 and 1.4.1 */ - png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; -# endif -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - encounter a png_error() will longjmp here. Since the jmpbuf is - then meaningless we abort instead of returning. */ -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */ -#endif - PNG_ABORT(); -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif /* PNG_SETJMP_SUPPORTED */ - -#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); - - if (user_png_ver) + if (png_ptr != NULL) { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - else - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + png_ptr->mode = PNG_IS_READ_STRUCT; - - 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. + /* Added in libpng-1.6.0; this can be used to detect a read structure if + * required (it will be zero in a write structure.) */ - 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')) - { -#ifdef PNG_STDIO_SUPPORTED - char msg[80]; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "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_warning(png_ptr, - "Incompatible libpng version in application and library"); +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; +# endif - png_cleanup_needed = 1; - } +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + + /* In stable builds only warn if an application error can be completely + * handled. + */ +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +# endif +# endif + + /* TODO: delay this, it can be done in png_init_io (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_read_fn(png_ptr, NULL, NULL); } - if (!png_cleanup_needed) - { - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, - png_ptr->zbuf_size); - if (png_ptr->zbuf == NULL) - png_cleanup_needed = 1; - } - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - if (!png_cleanup_needed) - { - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: /* Do nothing */ break; - case Z_MEM_ERROR: - case Z_STREAM_ERROR: png_warning(png_ptr, "zlib memory error"); - png_cleanup_needed = 1; break; - case Z_VERSION_ERROR: png_warning(png_ptr, "zlib version error"); - png_cleanup_needed = 1; break; - default: png_warning(png_ptr, "Unknown zlib error"); - png_cleanup_needed = 1; - } - } - - if (png_cleanup_needed) - { - /* Clean up PNG structure and deallocate any memory. */ - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = 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 - return (NULL); - } - - 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); + return png_ptr; } @@ -211,231 +89,195 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, * 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_read_info(png_structrp png_ptr, png_inforp info_ptr) { - png_debug(1, "in png_read_info"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* 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; - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; #endif - png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); - png_ptr->sig_bytes = 8; + png_debug(1, "in png_read_info"); - 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; - } + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Read and check the PNG file signature. */ + png_read_sig(png_ptr, info_ptr); for (;;) { - PNG_IHDR; - PNG_IDAT; - PNG_IEND; - PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_sCAL; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_sPLT; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_sRGB; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_zTXt; -#endif png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + png_uint_32 chunk_name = png_ptr->chunk_name; + + /* IDAT logic needs to happen here to simplify getting the two flags + * right. + */ + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_chunk_error(png_ptr, "Missing PLTE before IDAT"); + + else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_chunk_benign_error(png_ptr, "Too many IDATs found"); + + png_ptr->mode |= PNG_HAVE_IDAT; + } + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; /* This should be a binary subdivision search or a hash for * matching the chunk name rather than a linear search. */ - if (!png_memcmp(chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - if (!png_memcmp(chunk_name, png_IHDR, 4)) + if (chunk_name == png_IHDR) png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) + + else if (chunk_name == png_IEND) png_handle_IEND(png_ptr, info_ptr, length); + #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - if (!png_memcmp(chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_unknown(png_ptr, info_ptr, length, keep); + + if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; - else if (!png_memcmp(chunk_name, png_IDAT, 4)) + + else if (chunk_name == png_IDAT) { - 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 = 0; /* It has been consumed */ break; } } #endif - else if (!png_memcmp(chunk_name, png_PLTE, 4)) + else if (chunk_name == png_PLTE) png_handle_PLTE(png_ptr, info_ptr, length); - else if (!png_memcmp(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"); + else if (chunk_name == png_IDAT) + { png_ptr->idat_size = length; - png_ptr->mode |= PNG_HAVE_IDAT; break; } + #ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(chunk_name, png_bKGD, 4)) + else if (chunk_name == png_bKGD) png_handle_bKGD(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(chunk_name, png_cHRM, 4)) + else if (chunk_name == png_cHRM) png_handle_cHRM(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(chunk_name, png_gAMA, 4)) + else if (chunk_name == png_gAMA) png_handle_gAMA(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(chunk_name, png_hIST, 4)) + else if (chunk_name == png_hIST) png_handle_hIST(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(chunk_name, png_oFFs, 4)) + else if (chunk_name == png_oFFs) png_handle_oFFs(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_pCAL, 4)) + else if (chunk_name == png_pCAL) png_handle_pCAL(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_sCAL, 4)) + else if (chunk_name == png_sCAL) png_handle_sCAL(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(chunk_name, png_pHYs, 4)) + else if (chunk_name == png_pHYs) png_handle_pHYs(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sBIT, 4)) + else if (chunk_name == png_sBIT) png_handle_sBIT(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(chunk_name, png_sRGB, 4)) + else if (chunk_name == png_sRGB) png_handle_sRGB(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(chunk_name, png_iCCP, 4)) + else if (chunk_name == png_iCCP) png_handle_iCCP(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sPLT, 4)) + else if (chunk_name == png_sPLT) png_handle_sPLT(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_tEXt, 4)) + else if (chunk_name == png_tEXt) png_handle_tEXt(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(chunk_name, png_tIME, 4)) + else if (chunk_name == png_tIME) png_handle_tIME(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(chunk_name, png_tRNS, 4)) + else if (chunk_name == png_tRNS) png_handle_tRNS(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_zTXt, 4)) + else if (chunk_name == png_zTXt) png_handle_zTXt(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_iTXt, 4)) + else if (chunk_name == png_iTXt) png_handle_iTXt(png_ptr, info_ptr, length); #endif + else - png_handle_unknown(png_ptr, info_ptr, length); + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ /* Optional call to update the users info_ptr structure */ void PNGAPI -png_read_update_info(png_structp png_ptr, png_infop info_ptr) +png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_update_info"); - - if (png_ptr == NULL) - return; - 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); + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + png_read_start_row(png_ptr); + +# ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_read_transform_info(png_ptr, info_ptr); +# else + PNG_UNUSED(info_ptr) +# endif + } + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_read_update_info/png_start_read_image: duplicate call"); + } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED @@ -445,72 +287,166 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr) * If the user doesn't call this, we will do it ourselves. */ void PNGAPI -png_start_read_image(png_structp png_ptr) +png_start_read_image(png_structrp png_ptr) { png_debug(1, "in png_start_read_image"); - - if (png_ptr == NULL) - return; - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_start_read_image/png_read_update_info: duplicate call"); + } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void PNGAPI -png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing, + * NOTE: this is apparently only supported in the 'sequential' reader. + */ +static void +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) { - PNG_IDAT; - PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, - 0xff}; - PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; - int ret; - + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + 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 = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 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 /* MNG_FEATURES */ + +void PNGAPI +png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) +{ + png_row_info row_info; + if (png_ptr == NULL) return; - - png_debug2(1, "in png_read_row (row %lu, pass %d)", - (unsigned long) png_ptr->row_number, png_ptr->pass); - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_debug2(1, "in png_read_row (row %lu, pass %d)", + (unsigned long)png_ptr->row_number, png_ptr->pass); + + /* png_read_start_row sets the information (in particular iwidth) for this + * interlace pass. + */ + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) png_read_start_row(png_ptr); + + /* 1.5.6: row_info moved out of png_struct to a local here. */ + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + +#ifdef PNG_WARNINGS_SUPPORTED 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) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) 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) + if ((png_ptr->transformations & PNG_FILLER) != 0) 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) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) 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) + if ((png_ptr->transformations & PNG_PACK) != 0) 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) + if ((png_ptr->transformations & PNG_SHIFT) != 0) 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) + if ((png_ptr->transformations & PNG_BGR) != 0) 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) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } +#endif /* WARNINGS */ #ifdef 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)) + /* If interlaced and we do not need a new row, combine row and return. + * Notice that the pixels we have from previous rows have been transformed + * already; we can only combine like with like (transformed or + * untransformed) and, because of the libpng API for interlaced images, this + * means we must transform before de-interlacing. + */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { @@ -518,64 +454,70 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) 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_combine_row(png_ptr, dsp_row, 1/*display*/); 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_combine_row(png_ptr, dsp_row, 1/*display*/); + 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_combine_row(png_ptr, dsp_row, 1/*display*/); + 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_combine_row(png_ptr, dsp_row, 1/*display*/); + 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_combine_row(png_ptr, dsp_row, 1/*display*/); + 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_combine_row(png_ptr, dsp_row, 1/*display*/); + png_read_finish_row(png_ptr); return; } break; + + default: case 6: - if (!(png_ptr->row_number & 1)) + if ((png_ptr->row_number & 1) == 0) { png_read_finish_row(png_ptr); return; @@ -585,110 +527,85 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - if (!(png_ptr->mode & PNG_HAVE_IDAT)) + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) 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_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1); - do + /* Fill the row with IDAT data: */ + png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } - png_ptr->idat_size = png_read_chunk_header(png_ptr); - 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_benign_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_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - 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(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ - png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); } #endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations) + png_do_read_transformations(png_ptr, &row_info); +#endif - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "sequential row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal sequential row size calculation error"); #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && - (png_ptr->transformations & PNG_INTERLACE)) + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { 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); + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); + png_combine_row(png_ptr, dsp_row, 1/*display*/); + if (row != NULL) - png_combine_row(png_ptr, row, - png_pass_mask[png_ptr->pass]); + png_combine_row(png_ptr, row, 0/*row*/); } + else #endif { if (row != NULL) - png_combine_row(png_ptr, row, 0xff); + png_combine_row(png_ptr, row, -1/*ignored*/); + if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 0xff); + png_combine_row(png_ptr, dsp_row, -1/*ignored*/); } 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); + } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, @@ -716,17 +633,18 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) */ void PNGAPI -png_read_rows(png_structp png_ptr, png_bytepp row, - png_bytepp display_row, png_uint_32 num_rows) +png_read_rows(png_structrp 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"); - + if (png_ptr == NULL) return; + rp = row; dp = display_row; if (rp != NULL && dp != NULL) @@ -737,6 +655,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, png_read_row(png_ptr, rptr, dptr); } + else if (rp != NULL) for (i = 0; i < num_rows; i++) { @@ -744,6 +663,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, png_read_row(png_ptr, rptr, NULL); rp++; } + else if (dp != NULL) for (i = 0; i < num_rows; i++) { @@ -752,7 +672,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, dp++; } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS @@ -768,29 +688,53 @@ png_read_rows(png_structp png_ptr, png_bytepp row, * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI -png_read_image(png_structp png_ptr, png_bytepp image) +png_read_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i, image_height; int pass, j; png_bytepp rp; png_debug(1, "in png_read_image"); - + if (png_ptr == NULL) return; #ifdef PNG_READ_INTERLACING_SUPPORTED - pass = png_set_interlace_handling(png_ptr); + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + pass = png_set_interlace_handling(png_ptr); + /* And make sure transforms are initialized. */ + png_start_read_image(png_ptr); + } + else + { + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) == 0) + { + /* Caller called png_start_read_image or png_read_update_info without + * first turning on the PNG_INTERLACE transform. We can fix this here, + * but the caller should do it! + */ + png_warning(png_ptr, "Interlace handling should be turned on when " + "using png_read_image"); + /* Make sure this is set correctly */ + png_ptr->num_rows = png_ptr->height; + } + + /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in + * the above error case. + */ + pass = png_set_interlace_handling(png_ptr); + } #else if (png_ptr->interlaced) png_error(png_ptr, - "Cannot read interlaced image -- interlace handler disabled"); + "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++) { @@ -802,7 +746,7 @@ png_read_image(png_structp png_ptr, png_bytepp image) } } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the @@ -810,384 +754,264 @@ png_read_image(png_structp png_ptr, png_bytepp image) * 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_read_end(png_structrp png_ptr, png_inforp info_ptr) { +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + png_debug(1, "in png_read_end"); - + if (png_ptr == NULL) return; - png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + + /* If png_read_end is called in the middle of reading the rows there may + * still be pending IDAT data and an owned zstream. Deal with this here. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) +#endif + png_read_finish_IDAT(png_ptr); + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Report invalid palette index; added at libng-1.5.10 */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Read palette index exceeding num_palette"); +#endif do { - PNG_IHDR; - PNG_IDAT; - PNG_IEND; - PNG_PLTE; -#ifdef PNG_READ_bKGD_SUPPORTED - PNG_bKGD; -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - PNG_cHRM; -#endif -#ifdef PNG_READ_gAMA_SUPPORTED - PNG_gAMA; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - PNG_hIST; -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - PNG_iCCP; -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - PNG_iTXt; -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - PNG_oFFs; -#endif -#ifdef PNG_READ_pCAL_SUPPORTED - PNG_pCAL; -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - PNG_pHYs; -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - PNG_sBIT; -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - PNG_sCAL; -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - PNG_sPLT; -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - PNG_sRGB; -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - PNG_tEXt; -#endif -#ifdef PNG_READ_tIME_SUPPORTED - PNG_tIME; -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - PNG_tRNS; -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - PNG_zTXt; -#endif png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; + png_uint_32 chunk_name = png_ptr->chunk_name; - if (!png_memcmp(chunk_name, png_IHDR, 4)) - png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) + if (chunk_name == png_IEND) png_handle_IEND(png_ptr, info_ptr, length); + + else if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); + + else if (info_ptr == NULL) + png_crc_finish(png_ptr, length); + #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - if (!png_memcmp(chunk_name, png_IDAT, 4)) + if (chunk_name == png_IDAT) { - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if ((length > 0) || + (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); } - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) + png_handle_unknown(png_ptr, info_ptr, length, keep); + if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } #endif - else if (!png_memcmp(chunk_name, png_IDAT, 4)) + + else if (chunk_name == png_IDAT) { /* 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_HAVE_CHUNK_AFTER_IDAT)) + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); + png_crc_finish(png_ptr, length); } - else if (!png_memcmp(chunk_name, png_PLTE, 4)) + else if (chunk_name == png_PLTE) png_handle_PLTE(png_ptr, info_ptr, length); + #ifdef PNG_READ_bKGD_SUPPORTED - else if (!png_memcmp(chunk_name, png_bKGD, 4)) + else if (chunk_name == png_bKGD) png_handle_bKGD(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_cHRM_SUPPORTED - else if (!png_memcmp(chunk_name, png_cHRM, 4)) + else if (chunk_name == png_cHRM) png_handle_cHRM(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_gAMA_SUPPORTED - else if (!png_memcmp(chunk_name, png_gAMA, 4)) + else if (chunk_name == png_gAMA) png_handle_gAMA(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_hIST_SUPPORTED - else if (!png_memcmp(chunk_name, png_hIST, 4)) + else if (chunk_name == png_hIST) png_handle_hIST(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_oFFs_SUPPORTED - else if (!png_memcmp(chunk_name, png_oFFs, 4)) + else if (chunk_name == png_oFFs) png_handle_oFFs(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_pCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_pCAL, 4)) + else if (chunk_name == png_pCAL) png_handle_pCAL(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sCAL_SUPPORTED - else if (!png_memcmp(chunk_name, png_sCAL, 4)) + else if (chunk_name == png_sCAL) png_handle_sCAL(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_pHYs_SUPPORTED - else if (!png_memcmp(chunk_name, png_pHYs, 4)) + else if (chunk_name == png_pHYs) png_handle_pHYs(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sBIT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sBIT, 4)) + else if (chunk_name == png_sBIT) png_handle_sBIT(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sRGB_SUPPORTED - else if (!png_memcmp(chunk_name, png_sRGB, 4)) + else if (chunk_name == png_sRGB) png_handle_sRGB(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_iCCP_SUPPORTED - else if (!png_memcmp(chunk_name, png_iCCP, 4)) + else if (chunk_name == png_iCCP) png_handle_iCCP(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_sPLT_SUPPORTED - else if (!png_memcmp(chunk_name, png_sPLT, 4)) + else if (chunk_name == png_sPLT) png_handle_sPLT(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tEXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_tEXt, 4)) + else if (chunk_name == png_tEXt) png_handle_tEXt(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tIME_SUPPORTED - else if (!png_memcmp(chunk_name, png_tIME, 4)) + else if (chunk_name == png_tIME) png_handle_tIME(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_tRNS_SUPPORTED - else if (!png_memcmp(chunk_name, png_tRNS, 4)) + else if (chunk_name == png_tRNS) png_handle_tRNS(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_zTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_zTXt, 4)) + else if (chunk_name == png_zTXt) png_handle_zTXt(png_ptr, info_ptr, length); #endif + #ifdef PNG_READ_iTXt_SUPPORTED - else if (!png_memcmp(chunk_name, png_iTXt, 4)) + else if (chunk_name == png_iTXt) 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)); + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); +} +#endif /* SEQUENTIAL_READ */ + +/* Free all memory used in the read struct */ +static void +png_read_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_read_destroy"); + +#ifdef PNG_READ_GAMMA_SUPPORTED + png_destroy_gamma_table(png_ptr); +#endif + + png_free(png_ptr, png_ptr->big_row_buf); + png_ptr->big_row_buf = NULL; + png_free(png_ptr, png_ptr->big_prev_row); + png_ptr->big_prev_row = NULL; + png_free(png_ptr, png_ptr->read_buffer); + png_ptr->read_buffer = NULL; + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_ptr->palette_lookup = NULL; + png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = NULL; +#endif + + if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) + { + png_zfree(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + } + png_ptr->free_me &= ~PNG_FREE_PLTE; + +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) + { + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; + } + png_ptr->free_me &= ~PNG_FREE_TRNS; +#endif + + inflateEnd(&png_ptr->zstream); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); + png_ptr->save_buffer = NULL; +#endif + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; +#endif + + /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error + * callbacks are still set at this point. They are required to complete the + * destruction of the png_struct itself. + */ } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ /* 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_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_structrp png_ptr = NULL; png_debug(1, "in png_destroy_read_struct"); - + if (png_ptr_ptr != NULL) png_ptr = *png_ptr_ptr; + if (png_ptr == NULL) return; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (end_info_ptr_ptr != NULL) - end_info_ptr = *end_info_ptr_ptr; - - png_read_destroy(png_ptr, info_ptr, end_info_ptr); - - if (info_ptr != NULL) - { -#ifdef 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 = NULL; - } - - if (end_info_ptr != NULL) - { -#ifdef 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 = 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 = 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"); - - 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->big_row_buf); - png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->chunkdata); -#ifdef PNG_READ_QUANTIZE_SUPPORTED - png_free(png_ptr, png_ptr->palette_lookup); - png_free(png_ptr, png_ptr->quantize_index); -#endif -#ifdef PNG_READ_GAMMA_SUPPORTED - png_free(png_ptr, png_ptr->gamma_table); -#endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED - png_free(png_ptr, png_ptr->gamma_from_1); - png_free(png_ptr, png_ptr->gamma_to_1); -#endif - if (png_ptr->free_me & PNG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->free_me &= ~PNG_FREE_PLTE; -#if defined(PNG_tRNS_SUPPORTED) || \ - defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->free_me & PNG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans_alpha); - png_ptr->free_me &= ~PNG_FREE_TRNS; -#endif -#ifdef PNG_READ_hIST_SUPPORTED - if (png_ptr->free_me & PNG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->free_me &= ~PNG_FREE_HIST; -#endif -#ifdef 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); - } -#ifdef 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 -#ifdef 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 - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -#ifdef PNG_TEXT_SUPPORTED - png_free(png_ptr, png_ptr->current_text); -#endif /* PNG_TEXT_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - - /* Save the important info out of the png_struct, in case it is - * being used again. + /* libpng 1.6.0: use the API to destroy info structs to ensure consistent + * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. + * The extra was, apparently, unnecessary yet this hides memory leak bugs. */ -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_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, png_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, png_sizeof(jmp_buf)); -#endif + png_destroy_info_struct(png_ptr, end_info_ptr_ptr); + png_destroy_info_struct(png_ptr, info_ptr_ptr); + *png_ptr_ptr = NULL; + png_read_destroy(png_ptr); + png_destroy_png_struct(png_ptr); } void PNGAPI -png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) { if (png_ptr == NULL) return; + png_ptr->read_row_fn = read_row_fn; } @@ -1195,132 +1019,173 @@ png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_read_png(png_structp png_ptr, png_infop info_ptr, +png_read_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { - int row; - - if (png_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL) return; /* 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); - if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ - -#ifdef PNG_READ_16_TO_8_SUPPORTED - /* Tell libpng to strip 16 bit/color files down to 8 bits per color. + /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM + * is not implemented. This will only happen in de-configured (non-default) + * libpng builds. The results can be unexpected - png_read_png may return + * short or mal-formed rows because the transform is skipped. */ - if (transforms & PNG_TRANSFORM_STRIP_16) - png_set_strip_16(png_ptr); + + /* Tell libpng to strip 16-bit/color files down to 8 bits per color. + */ + if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); +#endif + + /* If both SCALE and STRIP are required pngrtran will effectively cancel the + * latter by doing SCALE first. This is ok and allows apps not to check for + * which is supported to get the right answer. + */ + if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + png_set_strip_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); #endif -#ifdef 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) + if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED png_set_strip_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); #endif -#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ - if (transforms & PNG_TRANSFORM_PACKING) + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_READ_PACK_SUPPORTED png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif -#ifdef 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) + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_READ_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif -#ifdef 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); + if ((transforms & PNG_TRANSFORM_EXPAND) != 0) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_set_expand(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); #endif /* We don't handle background color or gamma transformation or quantizing. */ -#ifdef PNG_READ_INVERT_SUPPORTED /* Invert monochrome files to have 0 as white and 1 as black */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_READ_INVERT_SUPPORTED png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif -#ifdef 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); - } + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if ((transforms & PNG_TRANSFORM_BGR) != 0) #ifdef PNG_READ_BGR_SUPPORTED - /* Flip the RGB pixels to BGR (or RGBA to BGRA) - */ - if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef 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); + png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif + /* Swap bytes of 16-bit files to least significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef 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); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif /* Added at libpng-1.2.41 */ + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef 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); + png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* Added at libpng-1.2.41 */ + /* Expand grayscale image to RGB */ + if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Expand grayscale image to RGB - */ - if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) - png_set_gray_to_rgb(png_ptr); + png_set_gray_to_rgb(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); +#endif + +/* Added at libpng-1.5.4 */ + if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) +#ifdef PNG_READ_EXPAND_16_SUPPORTED + png_set_expand_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); #endif /* We don't handle adding filler bytes */ + /* We use png_read_image and rely on that for interlace handling, but we also + * call png_read_update_info therefore must turn on interlace handling now: + */ + (void)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 (i.e., you selected such a transform above). @@ -1332,18 +1197,19 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); if (info_ptr->row_pointers == NULL) { - png_uint_32 iptr; + png_uint_32 iptr; + + info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep)))); - info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * png_sizeof(png_bytep)); for (iptr=0; iptrheight; iptr++) info_ptr->row_pointers[iptr] = NULL; info_ptr->free_me |= PNG_FREE_ROWS; - 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)); + for (iptr = 0; iptr < info_ptr->height; iptr++) + info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, + png_malloc(png_ptr, info_ptr->rowbytes)); } png_read_image(png_ptr, info_ptr->row_pointers); @@ -1352,10 +1218,2917 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); - transforms = transforms; /* Quiet compiler warnings */ - params = params; - + PNG_UNUSED(params) } -#endif /* PNG_INFO_IMAGE_SUPPORTED */ -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ +#endif /* INFO_IMAGE */ +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* SIMPLIFIED READ + * + * This code currently relies on the sequential reader, though it could easily + * be made to work with the progressive one. + */ +/* Arguments to png_image_finish_read: */ + +/* Encoding of PNG data (used by the color-map code) */ +# define P_NOTSET 0 /* File encoding not yet known */ +# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define P_LINEAR8 4 /* 8-bit linear: only from a file value */ + +/* Color-map processing: after libpng has run on the PNG image further + * processing may be needed to convert the data to color-map indices. + */ +#define PNG_CMAP_NONE 0 +#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ +#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ +#define PNG_CMAP_RGB 3 /* Process RGB data */ +#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ + +/* The following document where the background is for each processing case. */ +#define PNG_CMAP_NONE_BACKGROUND 256 +#define PNG_CMAP_GA_BACKGROUND 231 +#define PNG_CMAP_TRANS_BACKGROUND 254 +#define PNG_CMAP_RGB_BACKGROUND 256 +#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 + +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_voidp buffer; + png_int_32 row_stride; + png_voidp colormap; + png_const_colorp background; + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ +} png_image_read_control; + +/* Do all the *safe* initialization - 'safe' means that png_error won't be + * called, so setting up the jmp_buf is not required. This means that anything + * called from here must *not* call png_malloc - it has to call png_malloc_warn + * instead so that control is returned safely back to this routine. + */ +static int +png_image_read_init(png_imagep image) +{ + if (image->opaque == NULL) + { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + /* And set the rest of the structure to NULL to ensure that the various + * fields are consistent. + */ + memset(image, 0, (sizeof *image)); + image->version = PNG_IMAGE_VERSION; + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 0; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_read_struct(&png_ptr, NULL, NULL); + } + + return png_image_error(image, "png_image_read: out of memory"); + } + + return png_image_error(image, "png_image_read: opaque pointer not NULL"); +} + +/* Utility to find the base format of a PNG file from a png_struct. */ +static png_uint_32 +png_image_format(png_structrp png_ptr) +{ + png_uint_32 format = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + format |= PNG_FORMAT_FLAG_COLOR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS + * sets the png_struct fields; that's all we are interested in here. The + * precise interaction with an app call to png_set_tRNS and PNG file reading + * is unclear. + */ + else if (png_ptr->num_trans > 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + if (png_ptr->bit_depth == 16) + format |= PNG_FORMAT_FLAG_LINEAR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) + format |= PNG_FORMAT_FLAG_COLORMAP; + + return format; +} + +/* Is the given gamma significantly different from sRGB? The test is the same + * one used in pngrtran.c when deciding whether to do gamma correction. The + * arithmetic optimizes the division by using the fact that the inverse of the + * file sRGB gamma is 2.2 + */ +static int +png_gamma_not_sRGB(png_fixed_point g) +{ + if (g < PNG_FP_1) + { + /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ + if (g == 0) + return 0; + + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + } + + return 1; +} + +/* Do the main body of a 'png_image_begin_read' function; read the PNG file + * header and fill in all the information. This is executed in a safe context, + * unlike the init routine above. + */ +static int +png_image_read_header(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_set_benign_errors(png_ptr, 1/*warn*/); + png_read_info(png_ptr, info_ptr); + + /* Do this the fast way; just read directly out of png_struct. */ + image->width = png_ptr->width; + image->height = png_ptr->height; + + { + png_uint_32 format = png_image_format(png_ptr); + + image->format = format; + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Does the colorspace match sRGB? If there is no color endpoint + * (colorant) information assume yes, otherwise require the + * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set. If the + * colorspace has been determined to be invalid ignore it. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags + & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| + PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) + image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; +#endif + } + + /* We need the maximum number of entries regardless of the format the + * application sets here. + */ + { + png_uint_32 cmap_entries; + + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + cmap_entries = 1U << png_ptr->bit_depth; + break; + + case PNG_COLOR_TYPE_PALETTE: + cmap_entries = png_ptr->num_palette; + break; + + default: + cmap_entries = 256; + break; + } + + if (cmap_entries > 256) + cmap_entries = 256; + + image->colormap_entries = cmap_entries; + } + + return 1; +} + +#ifdef PNG_STDIO_SUPPORTED +int PNGAPI +png_image_begin_read_from_stdio(png_imagep image, FILE* file) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_read_init(image) != 0) + { + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +int PNGAPI +png_image_begin_read_from_file(png_imagep image, const char *file_name) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "rb"); + + if (fp != NULL) + { + if (png_image_read_init(image) != 0) + { + image->opaque->png_ptr->io_ptr = fp; + image->opaque->owned_file = 1; + return png_safe_execute(image, png_image_read_header, image); + } + + /* Clean up: just the opened file. */ + (void)fclose(fp); + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_begin_read_from_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + + return 0; +} +#endif /* STDIO */ + +static void PNGCBAPI +png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) +{ + if (png_ptr != NULL) + { + png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); + if (image != NULL) + { + png_controlp cp = image->opaque; + if (cp != NULL) + { + png_const_bytep memory = cp->memory; + png_size_t size = cp->size; + + if (memory != NULL && size >= need) + { + memcpy(out, memory, need); + cp->memory = memory + need; + cp->size = size - need; + return; + } + + png_error(png_ptr, "read beyond end of data"); + } + } + + png_error(png_ptr, "invalid memory read"); + } +} + +int PNGAPI png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory != NULL && size > 0) + { + if (png_image_read_init(image) != 0) + { + /* Now set the IO functions to read from the memory buffer and + * store it into io_ptr. Again do this in-place to avoid calling a + * libpng function that requires error handling. + */ + image->opaque->memory = png_voidcast(png_const_bytep, memory); + image->opaque->size = size; + image->opaque->png_ptr->io_ptr = image; + image->opaque->png_ptr->read_data_fn = png_image_memory_read; + + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +/* Utility function to skip chunks that are not used by the simplified image + * read functions and an appropriate macro to call it. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static void +png_image_skip_unused_chunks(png_structrp png_ptr) +{ + /* Prepare the reader to ignore all recognized chunks whose data will not + * be used, i.e., all chunks recognized by libpng except for those + * involved in basic image reading: + * + * IHDR, PLTE, IDAT, IEND + * + * Or image data handling: + * + * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. + * + * This provides a small performance improvement and eliminates any + * potential vulnerability to security problems in the unused chunks. + * + * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored + * too. This allows the simplified API to be compiled without iCCP support, + * however if the support is there the chunk is still checked to detect + * errors (which are unfortunately quite common.) + */ + { + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ +# ifdef PNG_READ_iCCP_SUPPORTED + 105, 67, 67, 80, '\0', /* iCCP */ +# endif + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore unknown chunks and all other chunks except for the + * IHDR, PLTE, tRNS, IDAT, and IEND chunks. + */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, + NULL, -1); + + /* But do not ignore image data handling chunks */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, + chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); + } +} + +# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) +#else +# define PNG_SKIP_CHUNKS(p) ((void)0) +#endif /* HANDLE_AS_UNKNOWN */ + +/* The following macro gives the exact rounded answer for all values in the + * range 0..255 (it actually divides by 51.2, but the rounding still generates + * the correct numbers 0..5 + */ +#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) + +/* Utility functions to make particular color-maps */ +static void +set_file_encoding(png_image_read_control *display) +{ + png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; + if (png_gamma_significant(g) != 0) + { + if (png_gamma_not_sRGB(g) != 0) + { + display->file_encoding = P_FILE; + display->gamma_to_linear = png_reciprocal(g); + } + + else + display->file_encoding = P_sRGB; + } + + else + display->file_encoding = P_LINEAR8; +} + +static unsigned int +decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) +{ + if (encoding == P_FILE) /* double check */ + encoding = display->file_encoding; + + if (encoding == P_NOTSET) /* must be the file encoding */ + { + set_file_encoding(display); + encoding = display->file_encoding; + } + + switch (encoding) + { + case P_FILE: + value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); + break; + + case P_sRGB: + value = png_sRGB_table[value]; + break; + + case P_LINEAR: + break; + + case P_LINEAR8: + value *= 257; + break; + + default: + png_error(display->image->opaque->png_ptr, + "unexpected encoding (internal error)"); + break; + } + + return value; +} + +static png_uint_32 +png_colormap_compose(png_image_read_control *display, + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) +{ + /* The file value is composed on the background, the background has the given + * encoding and so does the result, the file is encoded with P_FILE and the + * file and alpha are 8-bit values. The (output) encoding will always be + * P_LINEAR or P_sRGB. + */ + png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); + png_uint_32 b = decode_gamma(display, background, encoding); + + /* The alpha is always an 8-bit value (it comes from the palette), the value + * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. + */ + f = f * alpha + b * (255-alpha); + + if (encoding == P_LINEAR) + { + /* Scale to 65535; divide by 255, approximately (in fact this is extremely + * accurate, it divides by 255.00000005937181414556, with no overflow.) + */ + f *= 257; /* Now scaled by 65535 */ + f += f >> 16; + f = (f+32768) >> 16; + } + + else /* P_sRGB */ + f = PNG_sRGB_FROM_LINEAR(f); + + return f; +} + +/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must + * be 8-bit. + */ +static void +png_create_colormap_entry(png_image_read_control *display, + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) +{ + png_imagep image = display->image; + const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); + + if (ip > 255) + png_error(image->opaque->png_ptr, "color-map index out of range"); + + /* Update the cache with whether the file gamma is significantly different + * from sRGB. + */ + if (encoding == P_FILE) + { + if (display->file_encoding == P_NOTSET) + set_file_encoding(display); + + /* Note that the cached value may be P_FILE too, but if it is then the + * gamma_to_linear member has been set. + */ + encoding = display->file_encoding; + } + + if (encoding == P_FILE) + { + png_fixed_point g = display->gamma_to_linear; + + red = png_gamma_16bit_correct(red*257, g); + green = png_gamma_16bit_correct(green*257, g); + blue = png_gamma_16bit_correct(blue*257, g); + + if (convert_to_Y != 0 || output_encoding == P_LINEAR) + { + alpha *= 257; + encoding = P_LINEAR; + } + + else + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + encoding = P_sRGB; + } + } + + else if (encoding == P_LINEAR8) + { + /* This encoding occurs quite frequently in test cases because PngSuite + * includes a gAMA 1.0 chunk with most images. + */ + red *= 257; + green *= 257; + blue *= 257; + alpha *= 257; + encoding = P_LINEAR; + } + + else if (encoding == P_sRGB && + (convert_to_Y != 0 || output_encoding == P_LINEAR)) + { + /* The values are 8-bit sRGB values, but must be converted to 16-bit + * linear. + */ + red = png_sRGB_table[red]; + green = png_sRGB_table[green]; + blue = png_sRGB_table[blue]; + alpha *= 257; + encoding = P_LINEAR; + } + + /* This is set if the color isn't gray but the output is. */ + if (encoding == P_LINEAR) + { + if (convert_to_Y != 0) + { + /* NOTE: these values are copied from png_do_rgb_to_gray */ + png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + + (png_uint_32)2366 * blue; + + if (output_encoding == P_LINEAR) + y = (y + 16384) >> 15; + + else + { + /* y is scaled by 32768, we need it scaled by 255: */ + y = (y + 128) >> 8; + y *= 255; + y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + + blue = red = green = y; + } + + else if (output_encoding == P_sRGB) + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + } + + if (encoding != output_encoding) + png_error(image->opaque->png_ptr, "bad encoding (internal error)"); + + /* Store the value. */ + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + if (output_encoding == P_LINEAR) + { + png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + /* The linear 16-bit values must be pre-multiplied by the alpha channel + * value, if less than 65535 (this is, effectively, composite on black + * if the alpha channel is removed.) + */ + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 3: + if (alpha < 65535) + { + if (alpha > 0) + { + blue = (blue * alpha + 32767U)/65535U; + green = (green * alpha + 32767U)/65535U; + red = (red * alpha + 32767U)/65535U; + } + + else + red = green = blue = 0; + } + entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; + entry[afirst + 1] = (png_uint_16)green; + entry[afirst + bgr] = (png_uint_16)red; + break; + + case 2: + entry[1 ^ afirst] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 1: + if (alpha < 65535) + { + if (alpha > 0) + green = (green * alpha + 32767U)/65535U; + + else + green = 0; + } + entry[afirst] = (png_uint_16)green; + break; + + default: + break; + } + } + + else /* output encoding is P_sRGB */ + { + png_bytep entry = png_voidcast(png_bytep, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_byte)alpha; + case 3: + entry[afirst + (2 ^ bgr)] = (png_byte)blue; + entry[afirst + 1] = (png_byte)green; + entry[afirst + bgr] = (png_byte)red; + break; + + case 2: + entry[1 ^ afirst] = (png_byte)alpha; + case 1: + entry[afirst] = (png_byte)green; + break; + + default: + break; + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + } +} + +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); + + return i; +} + +static int +make_gray_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); + + return i; +} +#define PNG_GRAY_COLORMAP_ENTRIES 256 + +static int +make_ga_colormap(png_image_read_control *display) +{ + unsigned int i, a; + + /* Alpha is retained, the output will be a color-map with entries + * selected by six levels of alpha. One transparent entry, 6 gray + * levels for all the intermediate alpha values, leaving 230 entries + * for the opaque grays. The color-map entries are the six values + * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the + * relevant entry. + * + * if (alpha > 229) // opaque + * { + * // The 231 entries are selected to make the math below work: + * base = 0; + * entry = (231 * gray + 128) >> 8; + * } + * else if (alpha < 26) // transparent + * { + * base = 231; + * entry = 0; + * } + * else // partially opaque + * { + * base = 226 + 6 * PNG_DIV51(alpha); + * entry = PNG_DIV51(gray); + * } + */ + i = 0; + while (i < 231) + { + unsigned int gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); + } + + /* 255 is used here for the component values for consistency with the code + * that undoes premultiplication in pngwrite.c. + */ + png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); + + for (a=1; a<5; ++a) + { + unsigned int g; + + for (g=0; g<6; ++g) + png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, + P_sRGB); + } + + return i; +} + +#define PNG_GA_COLORMAP_ENTRIES 256 + +static int +make_rgb_colormap(png_image_read_control *display) +{ + unsigned int i, r; + + /* Build a 6x6x6 opaque RGB cube */ + for (i=r=0; r<6; ++r) + { + unsigned int g; + + for (g=0; g<6; ++g) + { + unsigned int b; + + for (b=0; b<6; ++b) + png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, + P_sRGB); + } + } + + return i; +} + +#define PNG_RGB_COLORMAP_ENTRIES 216 + +/* Return a palette index to the above palette given three 8-bit sRGB values. */ +#define PNG_RGB_INDEX(r,g,b) \ + ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) + +static int +png_image_read_colormap(png_voidp argument) +{ + png_image_read_control *display = + png_voidcast(png_image_read_control*, argument); + const png_imagep image = display->image; + + const png_structrp png_ptr = image->opaque->png_ptr; + const png_uint_32 output_format = image->format; + const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + + unsigned int cmap_entries; + unsigned int output_processing; /* Output processing option */ + unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ + + /* Background information; the background color and the index of this color + * in the color-map if it exists (else 256). + */ + unsigned int background_index = 256; + png_uint_32 back_r, back_g, back_b; + + /* Flags to accumulate things that need to be done to the input. */ + int expand_tRNS = 0; + + /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is + * very difficult to do, the results look awful, and it is difficult to see + * what possible use it is because the application can't control the + * color-map. + */ + if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || + png_ptr->num_trans > 0) /* alpha in input */ && + ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) + { + if (output_encoding == P_LINEAR) /* compose on black */ + back_b = back_g = back_r = 0; + + else if (display->background == NULL /* no way to remove it */) + png_error(png_ptr, + "a background color must be supplied to remove alpha/transparency"); + + /* Get a copy of the background color (this avoids repeating the checks + * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the + * output format. + */ + else + { + back_g = display->background->green; + if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) + { + back_r = display->background->red; + back_b = display->background->blue; + } + else + back_b = back_r = back_g; + } + } + + else if (output_encoding == P_LINEAR) + back_b = back_r = back_g = 65535; + + else + back_b = back_r = back_g = 255; + + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* Decide what to do based on the PNG color type of the input data. The + * utility function png_create_colormap_entry deals with most aspects of the + * output transformations; this code works out how to produce bytes of + * color-map entries from the original format. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth <= 8) + { + /* There at most 256 colors in the output, regardless of + * transparency. + */ + unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; + + cmap_entries = 1U << png_ptr->bit_depth; + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "gray[8] color-map: too few entries"); + + step = 255 / (cmap_entries - 1); + output_processing = PNG_CMAP_NONE; + + /* If there is a tRNS chunk then this either selects a transparent + * value or, if the output has no alpha, the background color. + */ + if (png_ptr->num_trans > 0) + { + trans = png_ptr->trans_color.gray; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; + } + + /* png_create_colormap_entry just takes an RGBA and writes the + * corresponding color-map entry using the format from 'image', + * including the required conversion to sRGB or linear as + * appropriate. The input values are always either sRGB (if the + * gamma correction flag is 0) or 0..255 scaled file encoded values + * (if the function must gamma correct them). + */ + for (i=val=0; ibit_depth < 8) + png_set_packing(png_ptr); + } + + else /* bit depth is 16 */ + { + /* The 16-bit input values can be converted directly to 8-bit gamma + * encoded values; however, if a tRNS chunk is present 257 color-map + * entries are required. This means that the extra entry requires + * special processing; add an alpha channel, sacrifice gray level + * 254 and convert transparent (alpha==0) entries to that. + * + * Use libpng to chop the data to 8 bits. Convert it to sRGB at the + * same time to minimize quality loss. If a tRNS chunk is present + * this means libpng must handle it too; otherwise it is impossible + * to do the exact match on the 16-bit value. + * + * If the output has no alpha channel *and* the background color is + * gray then it is possible to let libpng handle the substitution by + * ensuring that the corresponding gray level matches the background + * color exactly. + */ + data_encoding = P_sRGB; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray[16] color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (png_ptr->num_trans > 0) + { + unsigned int back_alpha; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + back_alpha = 0; + + else + { + if (back_r == back_g && back_g == back_b) + { + /* Background is gray; no special processing will be + * required. + */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry + * matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * sRGB value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: does this work without expanding tRNS to alpha? + * It should be the color->gray case below apparently + * doesn't. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + break; + } +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ + back_alpha = 255; +#else + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; +#endif + } + + /* output_processing means that the libpng-processed row will be + * 8-bit GA and it has to be processing to single byte color-map + * values. Entry 254 is replaced by either a completely + * transparent entry or by the background color at full + * precision (and the background color is not a simple gray + * level in this case.) + */ + expand_tRNS = 1; + output_processing = PNG_CMAP_TRANS; + background_index = 254; + + /* And set (overwrite) color-map entry 254 to the actual + * background color at full precision. + */ + png_create_colormap_entry(display, 254, back_r, back_g, back_b, + back_alpha, output_encoding); + } + + else + output_processing = PNG_CMAP_NONE; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum + * of 65536 combinations. If, however, the alpha channel is to be + * removed there are only 256 possibilities if the background is gray. + * (Otherwise there is a subset of the 65536 possibilities defined by + * the triangle between black, white and the background color.) + * + * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to + * worry about tRNS matching - tRNS is ignored if there is an alpha + * channel. + */ + data_encoding = P_sRGB; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray+alpha color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else /* alpha is removed */ + { + /* Alpha must be removed as the PNG data is processed when the + * background is a color because the G and A channels are + * independent and the vector addition (non-parallel vectors) is a + * 2-D problem. + * + * This can be reduced to the same algorithm as above by making a + * colormap containing gray levels (for the opaque grays), a + * background entry (for a transparent pixel) and a set of four six + * level color values, one set for each intermediate alpha value. + * See the comments in make_ga_colormap for how this works in the + * per-pixel processing. + * + * If the background is gray, however, we only need a 256 entry gray + * level color map. It is sufficient to make the entry generated + * for the background color be exactly the color specified. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || + (back_r == back_g && back_g == back_b)) + { + /* Background is gray; no special processing will be required. */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray-alpha color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the sRGB + * value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + } + + else + { + png_uint_32 i, a; + + /* This is the same as png_make_ga_colormap, above, except that + * the entries are all opaque. + */ + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "ga-alpha color-map: too few entries"); + + i = 0; + while (i < 231) + { + png_uint_32 gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, + 255, P_sRGB); + } + + /* NOTE: this preserves the full precision of the application + * background color. + */ + background_index = i; + png_create_colormap_entry(display, i++, back_r, back_g, back_b, +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ 255U, +#else + output_encoding == P_LINEAR ? 65535U : 255U, +#endif + output_encoding); + + /* For non-opaque input composite on the sRGB background - this + * requires inverting the encoding for each component. The input + * is still converted to the sRGB encoding because this is a + * reasonable approximate to the logarithmic curve of human + * visual sensitivity, at least over the narrow range which PNG + * represents. Consequently 'G' is always sRGB encoded, while + * 'A' is linear. We need the linear background colors. + */ + if (output_encoding == P_sRGB) /* else already linear */ + { + /* This may produce a value not exactly matching the + * background, but that's ok because these numbers are only + * used when alpha != 0 + */ + back_r = png_sRGB_table[back_r]; + back_g = png_sRGB_table[back_g]; + back_b = png_sRGB_table[back_b]; + } + + for (a=1; a<5; ++a) + { + unsigned int g; + + /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled + * by an 8-bit alpha value (0..255). + */ + png_uint_32 alpha = 51 * a; + png_uint_32 back_rx = (255-alpha) * back_r; + png_uint_32 back_gx = (255-alpha) * back_g; + png_uint_32 back_bx = (255-alpha) * back_b; + + for (g=0; g<6; ++g) + { + png_uint_32 gray = png_sRGB_table[g*51] * alpha; + + png_create_colormap_entry(display, i++, + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); + } + } + + cmap_entries = i; + output_processing = PNG_CMAP_GA; + } + } + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + /* Exclude the case where the output is gray; we can always handle this + * with the cases above. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) + { + /* The color-map will be grayscale, so we may as well convert the + * input RGB values to a simple grayscale and use the grayscale + * code above. + * + * NOTE: calling this apparently damages the recognition of the + * transparent color in background color handling; call + * png_set_tRNS_to_alpha before png_set_background_fixed. + */ + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, + -1); + data_encoding = P_sRGB; + + /* The output will now be one or two 8-bit gray or gray+alpha + * channels. The more complex case arises when the input has alpha. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Both input and output have an alpha channel, so no background + * processing is required; just map the GA bytes to the right + * color-map entry. + */ + expand_tRNS = 1; + + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[ga] color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else + { + /* Either the input or the output has no alpha channel, so there + * will be no non-opaque pixels in the color-map; it will just be + * grayscale. + */ + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[gray] color-map: too few entries"); + + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0) + { + cmap_entries = make_gray_file_colormap(display); + data_encoding = P_FILE; + } + + else + cmap_entries = make_gray_colormap(display); + + /* But if the input has alpha or transparency it must be removed + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + png_color_16 c; + png_uint_32 gray = back_g; + + /* We need to ensure that the application background exists in + * the colormap and that completely transparent pixels map to + * it. Achieve this simply by ensuring that the entry + * selected for the background really is the background color. + */ + if (data_encoding == P_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (P_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == P_sRGB) + gray = png_sRGB_table[gray]; /* now P_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->colorspace.gamma)); /* now P_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: the following is apparently a bug in libpng. Without + * it the transparent color recognition in + * png_set_background_fixed seems to go wrong. + */ + expand_tRNS = 1; + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + output_processing = PNG_CMAP_NONE; + } + } + + else /* output is color */ + { + /* We could use png_quantize here so long as there is no transparent + * color or alpha; png_quantize ignores alpha. Easier overall just + * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. + * Consequently we always want libpng to produce sRGB data. + */ + data_encoding = P_sRGB; + + /* Is there any transparency or alpha? */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + /* Is there alpha in the output too? If so all four channels are + * processed into a special RGB cube with alpha support. + */ + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_uint_32 r; + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb+alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + /* Add a transparent entry. */ + png_create_colormap_entry(display, cmap_entries, 255, 255, + 255, 0, P_sRGB); + + /* This is stored as the background index for the processing + * algorithm. + */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with alpha 0.5. */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + png_uint_32 g; + + for (g=0; g<256; g = (g << 1) | 0x7f) + { + png_uint_32 b; + + /* This generates components with the values 0, 127 and + * 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + r, g, b, 128, P_sRGB); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else + { + /* Alpha/transparency must be removed. The background must + * exist in the color map (achieved by setting adding it after + * the 666 color-map). If the standard processing code will + * pick up this entry automatically that's all that is + * required; libpng can be called to do the background + * processing. + */ + unsigned int sample_size = + PNG_IMAGE_SAMPLE_SIZE(output_format); + png_uint_32 r, g, b; /* sRGB background */ + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb-alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + png_create_colormap_entry(display, cmap_entries, back_r, + back_g, back_b, 0/*unused*/, output_encoding); + + if (output_encoding == P_LINEAR) + { + r = PNG_sRGB_FROM_LINEAR(back_r * 255); + g = PNG_sRGB_FROM_LINEAR(back_g * 255); + b = PNG_sRGB_FROM_LINEAR(back_b * 255); + } + + else + { + r = back_r; + g = back_g; + b = back_g; + } + + /* Compare the newly-created color-map entry with the one the + * PNG_CMAP_RGB algorithm will use. If the two entries don't + * match, add the new one and set this as the background + * index. + */ + if (memcmp((png_const_bytep)display->colormap + + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), + sample_size) != 0) + { + /* The background color must be added. */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with created by composing with + * the background at alpha 0.5. + */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + for (g=0; g<256; g = (g << 1) | 0x7f) + { + /* This generates components with the values 0, 127 + * and 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + png_colormap_compose(display, r, P_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, P_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, P_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else /* background color is in the standard color-map */ + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = (png_uint_16)back_r; + c.gray = c.green = (png_uint_16)back_g; + c.blue = (png_uint_16)back_b; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_RGB; + } + } + } + + else /* no alpha or transparency in the input */ + { + /* Alpha in the output is irrelevant, simply map the opaque input + * pixels to the 6x6x6 color-map. + */ + if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + output_processing = PNG_CMAP_RGB; + } + } + break; + + case PNG_COLOR_TYPE_PALETTE: + /* It's already got a color-map. It may be necessary to eliminate the + * tRNS entries though. + */ + { + unsigned int num_trans = png_ptr->num_trans; + png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; + png_const_colorp colormap = png_ptr->palette; + const int do_background = trans != NULL && + (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; + unsigned int i; + + /* Just in case: */ + if (trans == NULL) + num_trans = 0; + + output_processing = PNG_CMAP_NONE; + data_encoding = P_FILE; /* Don't change from color-map indices */ + cmap_entries = png_ptr->num_palette; + if (cmap_entries > 256) + cmap_entries = 256; + + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "palette color-map: too few entries"); + + for (i=0; i < cmap_entries; ++i) + { + if (do_background != 0 && i < num_trans && trans[i] < 255) + { + if (trans[i] == 0) + png_create_colormap_entry(display, i, back_r, back_g, + back_b, 0, output_encoding); + + else + { + /* Must compose the PNG file color in the color-map entry + * on the sRGB color in 'back'. + */ + png_create_colormap_entry(display, i, + png_colormap_compose(display, colormap[i].red, P_FILE, + trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, P_FILE, + trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, P_FILE, + trans[i], back_b, output_encoding), + output_encoding == P_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); + } + } + + else + png_create_colormap_entry(display, i, colormap[i].red, + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); + } + + /* The PNG data may have indices packed in fewer than 8 bits, it + * must be expanded if so. + */ + if (png_ptr->bit_depth < 8) + png_set_packing(png_ptr); + } + break; + + default: + png_error(png_ptr, "invalid PNG color type"); + /*NOT REACHED*/ + break; + } + + /* Now deal with the output processing */ + if (expand_tRNS != 0 && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + png_set_tRNS_to_alpha(png_ptr); + + switch (data_encoding) + { + default: + png_error(png_ptr, "bad data option (internal error)"); + break; + + case P_sRGB: + /* Change to 8-bit sRGB */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALL THROUGH */ + + case P_FILE: + if (png_ptr->bit_depth > 8) + png_set_scale_16(png_ptr); + break; + } + + if (cmap_entries > 256 || cmap_entries > image->colormap_entries) + png_error(png_ptr, "color map overflow (BAD internal error)"); + + image->colormap_entries = cmap_entries; + + /* Double check using the recorded background index */ + switch (output_processing) + { + case PNG_CMAP_NONE: + if (background_index != PNG_CMAP_NONE_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_GA: + if (background_index != PNG_CMAP_GA_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_TRANS: + if (background_index >= cmap_entries || + background_index != PNG_CMAP_TRANS_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB: + if (background_index != PNG_CMAP_RGB_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB_ALPHA: + if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) + goto bad_background; + break; + + default: + png_error(png_ptr, "bad processing option (internal error)"); + + bad_background: + png_error(png_ptr, "bad background index (internal error)"); + } + + display->colormap_processing = output_processing; + + return 1/*ok*/; +} + +/* The final part of the color-map read called from png_image_finish_read. */ +static int +png_image_read_and_map(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + /* Called when the libpng data must be transformed into the color-mapped + * form. There is a local row buffer in display->local and this routine must + * do the interlace handling. + */ + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read read the libpng data into the temporary buffer. */ + png_read_row(png_ptr, inrow, NULL); + + /* Now process the row according to the processing option, note + * that the caller verifies that the format of the libpng output + * data is as required. + */ + outrow += startx; + switch (proc) + { + case PNG_CMAP_GA: + for (; outrow < end_row; outrow += stepx) + { + /* The data is always in the PNG order */ + unsigned int gray = *inrow++; + unsigned int alpha = *inrow++; + unsigned int entry; + + /* NOTE: this code is copied as a comment in + * make_ga_colormap above. Please update the + * comment if you change this code! + */ + if (alpha > 229) /* opaque */ + { + entry = (231 * gray + 128) >> 8; + } + else if (alpha < 26) /* transparent */ + { + entry = 231; + } + else /* partially opaque */ + { + entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); + } + + *outrow = (png_byte)entry; + } + break; + + case PNG_CMAP_TRANS: + for (; outrow < end_row; outrow += stepx) + { + png_byte gray = *inrow++; + png_byte alpha = *inrow++; + + if (alpha == 0) + *outrow = PNG_CMAP_TRANS_BACKGROUND; + + else if (gray != PNG_CMAP_TRANS_BACKGROUND) + *outrow = gray; + + else + *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); + } + break; + + case PNG_CMAP_RGB: + for (; outrow < end_row; outrow += stepx) + { + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); + inrow += 3; + } + break; + + case PNG_CMAP_RGB_ALPHA: + for (; outrow < end_row; outrow += stepx) + { + unsigned int alpha = inrow[3]; + + /* Because the alpha entries only hold alpha==0.5 values + * split the processing at alpha==0.25 (64) and 0.75 + * (196). + */ + + if (alpha >= 196) + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], + inrow[2]); + + else if (alpha < 64) + *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; + + else + { + /* Likewise there are three entries for each of r, g + * and b. We could select the entry by popcount on + * the top two bits on those architectures that + * support it, this is what the code below does, + * crudely. + */ + unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; + + /* Here are how the values map: + * + * 0x00 .. 0x3f -> 0 + * 0x40 .. 0xbf -> 1 + * 0xc0 .. 0xff -> 2 + * + * So, as above with the explicit alpha checks, the + * breakpoints are at 64 and 196. + */ + if (inrow[0] & 0x80) back_i += 9; /* red */ + if (inrow[0] & 0x40) back_i += 9; + if (inrow[0] & 0x80) back_i += 3; /* green */ + if (inrow[0] & 0x40) back_i += 3; + if (inrow[0] & 0x80) back_i += 1; /* blue */ + if (inrow[0] & 0x40) back_i += 1; + + *outrow = (png_byte)back_i; + } + + inrow += 4; + } + break; + + default: + break; + } + } + } + } + + return 1; +} + +static int +png_image_read_colormapped(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_controlp control = image->opaque; + png_structrp png_ptr = control->png_ptr; + png_inforp info_ptr = control->info_ptr; + + int passes = 0; /* As a flag */ + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + */ + if (display->colormap_processing == PNG_CMAP_NONE) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* The expected output can be deduced from the colormap_processing option. */ + switch (display->colormap_processing) + { + case PNG_CMAP_NONE: + /* Output must be one channel and one byte per pixel, the output + * encoding can be anything. + */ + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && + info_ptr->bit_depth == 8) + break; + + goto bad_output; + + case PNG_CMAP_TRANS: + case PNG_CMAP_GA: + /* Output must be two channels and the 'G' one must be sRGB, the latter + * can be checked with an exact number because it should have been set + * to this number above! + */ + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 256) + break; + + goto bad_output; + + case PNG_CMAP_RGB: + /* Output must be 8-bit sRGB encoded RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 216) + break; + + goto bad_output; + + case PNG_CMAP_RGB_ALPHA: + /* Output must be 8-bit sRGB encoded RGBA */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 244 /* 216 + 1 + 27 */) + break; + + /* goto bad_output; */ + /* FALL THROUGH */ + + default: + bad_output: + png_error(png_ptr, "bad color-map processing (internal error)"); + } + + /* Now read the rows. Do this here if it is possible to read directly into + * the output buffer, otherwise allocate a local row buffer of the maximum + * size libpng requires and call the relevant processing routine safely. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (passes == 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_and_map, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +/* Just the row reading part of png_image_read. */ +static int +png_image_read_composite(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = + (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * channels; + stepx = PNG_PASS_COL_OFFSET(pass) * channels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = channels; + stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow; + png_const_bytep end_row; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + outrow = png_voidcast(png_bytep, display->first_row); + outrow += y * step_row; + end_row = outrow + width * channels; + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[channels]; + + if (alpha > 0) /* else no change to the output */ + { + unsigned int c; + + for (c=0; cimage; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int pass, passes; + + /* Double check the convoluted logic below. We expect to get here with + * libpng doing rgb to gray and gamma correction but background processing + * left to the png_image_read_background function. The rows libpng produce + * might be 8 or 16-bit but should always have two channels; gray plus alpha. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + png_error(png_ptr, "lost rgb to gray"); + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, "unexpected compose"); + + if (png_get_channels(png_ptr, info_ptr) != 2) + png_error(png_ptr, "lost/gained channels"); + + /* Expect the 8-bit case to always remove the alpha channel */ + if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_error(png_ptr, "unexpected 8-bit transformation"); + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + /* Use direct access to info_ptr here because otherwise the simplified API + * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is + * checking the value after libpng expansions, not the original value in the + * PNG. + */ + switch (info_ptr->bit_depth) + { + default: + png_error(png_ptr, "unexpected bit depth"); + break; + + case 8: + /* 8-bit sRGB gray values with an alpha channel; the alpha channel is + * to be removed by composing on a background: either the row if + * display->background is NULL or display->background->green if not. + * Unlike the code above ALPHA_OPTIMIZED has *not* been done. + */ + { + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + + for (pass = 0; pass < passes; ++pass) + { + png_bytep row = png_voidcast(png_bytep, + display->first_row); + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + if (display->background == NULL) + { + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else no change to the output */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + /* Since PNG_OPTIMIZED_ALPHA was not set it is + * necessary to invert the sRGB transfer + * function and multiply the alpha out. + */ + component = png_sRGB_table[component] * alpha; + component += png_sRGB_table[outrow[0]] * + (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + inrow += 2; /* gray and alpha channel */ + } + } + } + + else /* constant background value */ + { + png_byte background8 = display->background->green; + png_uint_16 background = png_sRGB_table[background8]; + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else use background */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + component = png_sRGB_table[component] * alpha; + component += background * (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + else + outrow[0] = background8; + + inrow += 2; /* gray and alpha channel */ + } + + row += display->row_bytes; + } + } + } + } + break; + + case 16: + /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must + * still be done and, maybe, the alpha channel removed. This code also + * handles the alpha-first option. + */ + { + png_uint_16p first_row = png_voidcast(png_uint_16p, + display->first_row); + /* The division by two is safe because the caller passed in a + * stride which was multiplied by 2 (below) to get row_bytes. + */ + ptrdiff_t step_row = display->row_bytes / 2; + int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1+preserve_alpha; + int swap_alpha = 0; + +# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED + if (preserve_alpha != 0 && + (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + swap_alpha = 1; +# endif + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + /* The 'x' start and step are adjusted to output components here. + */ + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * outchannels; + stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = outchannels; + stepy = 1; + } + + for (; ylocal_row), NULL); + inrow = png_voidcast(png_const_uint_16p, display->local_row); + + /* Now do the pre-multiplication on each pixel in this row. + */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_uint_32 component = inrow[0]; + png_uint_16 alpha = inrow[1]; + + if (alpha > 0) /* else 0 */ + { + if (alpha < 65535) /* else just use component */ + { + component *= alpha; + component += 32767; + component /= 65535; + } + } + + else + component = 0; + + outrow[swap_alpha] = (png_uint_16)component; + if (preserve_alpha != 0) + outrow[1 ^ swap_alpha] = alpha; + + inrow += 2; /* components and alpha channel */ + } + } + } + } + break; + } + + return 1; +} + +/* The guts of png_image_finish_read as a png_safe_execute callback. */ +static int +png_image_read_direct(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_uint_32 format = image->format; + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check + * that the required implementation support is there. Always expand; always + * need 8 bits minimum, no palette and expanded tRNS. + */ + png_set_expand(png_ptr); + + /* Now check the format to see if it was modified. */ + { + png_uint_32 base_format = png_image_format(png_ptr) & + ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; + png_uint_32 change = format ^ base_format; + png_fixed_point output_gamma; + int mode; /* alpha mode */ + + /* Do this first so that we have a record if rgb to gray is happening. */ + if ((change & PNG_FORMAT_FLAG_COLOR) != 0) + { + /* gray<->color transformation required. */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_gray_to_rgb(png_ptr); + + else + { + /* libpng can't do both rgb to gray and + * background/pre-multiplication if there is also significant gamma + * correction, because both operations require linear colors and + * the code only supports one transform doing the gamma correction. + * Handle this by doing the pre-multiplication or background + * operation in this code, if necessary. + * + * TODO: fix this by rewriting pngrtran.c (!) + * + * For the moment (given that fixing this in pngrtran.c is an + * enormous change) 'do_local_background' is used to indicate that + * the problem exists. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + do_local_background = 1/*maybe*/; + + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + } + + change &= ~PNG_FORMAT_FLAG_COLOR; + } + + /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. + */ + { + png_fixed_point input_gamma_default; + + if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + input_gamma_default = PNG_GAMMA_LINEAR; + else + input_gamma_default = PNG_DEFAULT_sRGB; + + /* Call png_set_alpha_mode to set the default for the input gamma; the + * output gamma is set by a second call below. + */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); + } + + if (linear != 0) + { + /* If there *is* an alpha channel in the input it must be multiplied + * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + mode = PNG_ALPHA_STANDARD; /* associated alpha */ + + else + mode = PNG_ALPHA_PNG; + + output_gamma = PNG_GAMMA_LINEAR; + } + + else + { + mode = PNG_ALPHA_PNG; + output_gamma = PNG_DEFAULT_sRGB; + } + + /* If 'do_local_background' is set check for the presence of gamma + * correction; this is part of the work-round for the libpng bug + * described above. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + { + png_fixed_point gtest; + + /* This is 'png_gamma_threshold' from pngrtran.c; the test used for + * gamma correction, the screen gamma hasn't been set on png_struct + * yet; it's set below. png_struct::gamma, however, is set to the + * final value. + */ + if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, + PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0) + do_local_background = 0; + + else if (mode == PNG_ALPHA_STANDARD) + { + do_local_background = 2/*required*/; + mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ + } + + /* else leave as 1 for the checks below */ + } + + /* If the bit-depth changes then handle that here. */ + if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) + { + if (linear != 0 /*16-bit output*/) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ + png_set_scale_16(png_ptr); + + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + + /* Now the background/alpha channel changes. */ + if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Removing an alpha channel requires composition for the 8-bit + * formats; for the 16-bit it is already done, above, by the + * pre-multiplication and the channel just needs to be stripped. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* If RGB->gray is happening the alpha channel must be left and the + * operation completed locally. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + do_local_background = 2/*required*/; + + /* 16-bit output: just remove the channel */ + else if (linear != 0) /* compose on black (well, pre-multiply) */ + png_set_strip_alpha(png_ptr); + + /* 8-bit output: do an appropriate compose */ + else if (display->background != NULL) + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = display->background->red; + c.green = display->background->green; + c.blue = display->background->blue; + c.gray = display->background->green; + + /* This is always an 8-bit sRGB value, using the 'green' channel + * for gray is much better than calculating the luminance here; + * we can get off-by-one errors in that calculation relative to + * the app expectations and that will show up in transparent + * pixels. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + else /* compose on row: implemented below. */ + { + do_local_compose = 1; + /* This leaves the alpha channel in the output, so it has to be + * removed by the code below. Set the encoding to the 'OPTIMIZE' + * one so the code only has to hack on the pixels that require + * composition. + */ + mode = PNG_ALPHA_OPTIMIZED; + } + } + + else /* output needs an alpha channel */ + { + /* This is tricky because it happens before the swap operation has + * been accomplished; however, the swap does *not* swap the added + * alpha channel (weird API), so it must be added in the correct + * place. + */ + png_uint_32 filler; /* opaque filler */ + int where; + + if (linear != 0) + filler = 65535; + + else + filler = 255; + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } + + else +# endif + where = PNG_FILLER_AFTER; + + png_set_add_alpha(png_ptr, filler, where); + } + + /* This stops the (irrelevant) call to swap_alpha below. */ + change &= ~PNG_FORMAT_FLAG_ALPHA; + } + + /* Now set the alpha mode correctly; this is always done, even if there is + * no alpha channel in either the input or the output because it correctly + * sets the output gamma. + */ + png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((change & PNG_FORMAT_FLAG_BGR) != 0) + { + /* Check only the output format; PNG is never BGR; don't do this if + * the output is gray, but fix up the 'format' value in that case. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + + else + format &= ~PNG_FORMAT_FLAG_BGR; + + change &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) + { + /* Only relevant if there is an alpha channel - it's particularly + * important to handle this correctly because do_local_compose may + * be set above and then libpng will keep the alpha channel for this + * code to remove. + */ + if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Disable this if doing a local background, + * TODO: remove this when local background is no longer required. + */ + if (do_local_background != 2) + png_set_swap_alpha(png_ptr); + } + + else + format &= ~PNG_FORMAT_FLAG_AFIRST; + + change &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If the *output* is 16-bit then we need to check for a byte-swap on this + * architecture. + */ + if (linear != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + + /* If change is not now 0 some transformation is missing - error out. */ + if (change != 0) + png_error(png_ptr, "png_read_image: unsupported transformation"); + } + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + * + * TODO: remove the do_local_background fixup below. + */ + if (do_local_compose == 0 && do_local_background != 2) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + { + png_uint_32 info_format = 0; + + if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_format |= PNG_FORMAT_FLAG_COLOR; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + /* do_local_compose removes this channel below. */ + if (do_local_compose == 0) + { + /* do_local_background does the same if required. */ + if (do_local_background != 2 || + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + info_format |= PNG_FORMAT_FLAG_ALPHA; + } + } + + else if (do_local_compose != 0) /* internal error */ + png_error(png_ptr, "png_image_read: alpha channel lost"); + + if (info_ptr->bit_depth == 16) + info_format |= PNG_FORMAT_FLAG_LINEAR; + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + info_format |= PNG_FORMAT_FLAG_BGR; +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (do_local_background == 2) + { + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + info_format |= PNG_FORMAT_FLAG_AFIRST; + } + + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || + ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && + (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) + { + if (do_local_background == 2) + png_error(png_ptr, "unexpected alpha swap transformation"); + + info_format |= PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* This is actually an internal error. */ + if (info_format != format) + png_error(png_ptr, "png_read_image: invalid transformations"); + } + + /* Now read the rows. If do_local_compose is set then it is necessary to use + * a local row buffer. The output will be GA, RGBA or BGRA and must be + * converted to G, RGB or BGR as appropriate. The 'local_row' member of the + * display acts as a flag. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= 2; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (do_local_compose != 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_composite, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else if (do_local_background == 2) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +int PNGAPI +png_image_finish_read(png_imagep image, png_const_colorp background, + void *buffer, png_int_32 row_stride, void *colormap) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + png_uint_32 check; + + if (row_stride == 0) + row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && + check >= PNG_IMAGE_ROW_STRIDE(*image)) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case all the + * setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = + png_safe_execute(image, png_image_read_colormap, &display) && + png_safe_execute(image, png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + + return 0; +} + +#endif /* SIMPLIFIED_READ */ +#endif /* READ */ diff --git a/thirdparty/libpng/pngrio.c b/thirdparty/libpng/pngrio.c index 59059caf..bb5c8251 100644 --- a/thirdparty/libpng/pngrio.c +++ b/thirdparty/libpng/pngrio.c @@ -1,8 +1,8 @@ /* pngrio.c - functions for data input * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -18,24 +18,24 @@ * libpng use it at run time with png_set_read_fn(...). */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED #include "pngpriv.h" +#ifdef PNG_READ_SUPPORTED + /* 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. + * to read more than 64K on a 16 bit machine. */ void /* PRIVATE */ -png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) { png_debug1(4, "reading %d bytes", (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"); } @@ -46,80 +46,34 @@ png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) * read_data function and use it at run time with png_set_read_fn(), rather * than changing the library. */ -#ifndef USE_FAR_KEYWORD -void PNGAPI +void PNGCBAPI png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { png_size_t check; if (png_ptr == NULL) return; + /* 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. */ - check = fread(data, 1, length, (png_FILE_p)png_ptr->io_ptr); + check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); 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 PNGAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - png_byte *n_data; - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - /* 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) - { - check = fread(n_data, 1, length, io_ptr); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - err = fread(buf, 1, read, io_ptr); - 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 @@ -130,34 +84,37 @@ png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) * be used. */ void PNGAPI -png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, +png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn) { if (png_ptr == NULL) return; + png_ptr->io_ptr = io_ptr; #ifdef PNG_STDIO_SUPPORTED 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 +#ifdef PNG_WRITE_SUPPORTED /* 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"); + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); } +#endif #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->output_flush_fn = NULL; #endif } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c index b5e8f1a2..cad7a8da 100644 --- a/thirdparty/libpng/pngrtran.c +++ b/thirdparty/libpng/pngrtran.c @@ -1,8 +1,8 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.4.2 [May 6, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -16,17 +16,16 @@ * in pngtrans.c. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED #include "pngpriv.h" +#ifdef PNG_READ_SUPPORTED + /* 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_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) { png_debug(1, "in png_set_crc_action"); - + if (png_ptr == NULL) return; @@ -89,94 +88,345 @@ png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) } } -#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) +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Is it OK to set a transformation now? Only if png_start_read_image or + * png_read_update_info have not been called. It is not necessary for the IHDR + * to have been read in all cases; the need_IHDR parameter allows for this + * check too. + */ +static int +png_rtran_ok(png_structrp png_ptr, int need_IHDR) { - png_debug(1, "in png_set_background"); - - if (png_ptr == NULL) + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + png_app_error(png_ptr, + "invalid after png_start_read_image or png_read_update_info"); + + else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_app_error(png_ptr, "invalid before the PNG header has been read"); + + else + { + /* Turn on failure to initialize correctly for all transforms. */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; + + return 1; /* Ok */ + } + } + + return 0; /* no png_error possible! */ +} +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS via a background color */ +void PNGFAPI +png_set_background_fixed(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma) +{ + png_debug(1, "in png_set_background_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) return; + 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, - png_sizeof(png_color_16)); - png_ptr->background_gamma = (float)background_gamma; + png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + png_ptr->background = *background_color; + png_ptr->background_gamma = background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); + if (need_expand != 0) + png_ptr->transformations |= PNG_BACKGROUND_EXPAND; + else + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_background(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_set_background_fixed(png_ptr, background_color, background_gamma_code, + need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); +} +# endif /* FLOATING_POINT */ +#endif /* READ_BACKGROUND */ + +/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the + * one that pngrtran does first (scale) happens. This is necessary to allow the + * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +void PNGAPI +png_set_scale_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_scale_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_SCALE_16_TO_8; } #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Strip 16 bit depth files to 8 bit depth */ +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +/* Chop 16-bit depth files to 8-bit depth */ void PNGAPI -png_set_strip_16(png_structp png_ptr) +png_set_strip_16(png_structrp png_ptr) { png_debug(1, "in png_set_strip_16"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; + png_ptr->transformations |= PNG_16_TO_8; } #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED void PNGAPI -png_set_strip_alpha(png_structp png_ptr) +png_set_strip_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_strip_alpha"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; - png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; + + png_ptr->transformations |= PNG_STRIP_ALPHA; } #endif +#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) +static png_fixed_point +translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, + int is_screen) +{ + /* Check for flag values. The main reason for having the old Mac value as a + * flag is that it is pretty near impossible to work out what the correct + * value is from Apple documentation - a working Mac system is needed to + * discover the value! + */ + if (output_gamma == PNG_DEFAULT_sRGB || + output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) + { + /* If there is no sRGB support this just sets the gamma to the standard + * sRGB value. (This is a side effect of using this function!) + */ +# ifdef PNG_READ_sRGB_SUPPORTED + png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# else + PNG_UNUSED(png_ptr) +# endif + if (is_screen != 0) + output_gamma = PNG_GAMMA_sRGB; + else + output_gamma = PNG_GAMMA_sRGB_INVERSE; + } + + else if (output_gamma == PNG_GAMMA_MAC_18 || + output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) + { + if (is_screen != 0) + output_gamma = PNG_GAMMA_MAC_OLD; + else + output_gamma = PNG_GAMMA_MAC_INVERSE; + } + + return output_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +static png_fixed_point +convert_gamma_value(png_structrp png_ptr, double output_gamma) +{ + /* The following silently ignores cases where fixed point (times 100,000) + * gamma values are passed to the floating point API. This is safe and it + * means the fixed point constants work just fine with the floating point + * API. The alternative would just lead to undetected errors and spurious + * bug reports. Negative values fail inside the _fixed API unless they + * correspond to the flag values. + */ + if (output_gamma > 0 && output_gamma < 128) + output_gamma *= PNG_FP_1; + + /* This preserves -1 and -2 exactly: */ + output_gamma = floor(output_gamma + .5); + + if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) + png_fixed_error(png_ptr, "gamma value"); + + return (png_fixed_point)output_gamma; +} +# endif +#endif /* READ_ALPHA_MODE || READ_GAMMA */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +void PNGFAPI +png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, + png_fixed_point output_gamma) +{ + int compose = 0; + png_fixed_point file_gamma; + + png_debug(1, "in png_set_alpha_mode"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); + + /* Validate the value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out users of this API + * who use the inverse of the gamma value accidentally! Since some of these + * values are reasonable this may have to be changed. + */ + if (output_gamma < 70000 || output_gamma > 300000) + png_error(png_ptr, "output gamma out of expected range"); + + /* The default file gamma is the inverse of the output gamma; the output + * gamma may be changed below so get the file value first: + */ + file_gamma = png_reciprocal(output_gamma); + + /* There are really 8 possibilities here, composed of any combination + * of: + * + * premultiply the color channels + * do not encode non-opaque pixels + * encode the alpha as well as the color channels + * + * The differences disappear if the input/output ('screen') gamma is 1.0, + * because then the encoding is a no-op and there is only the choice of + * premultiplying the color channels or not. + * + * png_set_alpha_mode and png_set_background interact because both use + * png_compose to do the work. Calling both is only useful when + * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along + * with a default gamma value. Otherwise PNG_COMPOSE must not be set. + */ + switch (mode) + { + case PNG_ALPHA_PNG: /* default: png standard */ + /* No compose, but it may be set by png_set_background! */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + /* The output is linear: */ + output_gamma = PNG_FP_1; + break; + + case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; + /* output_gamma records the encoding of opaque pixels! */ + break; + + case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ + compose = 1; + png_ptr->transformations |= PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + default: + png_error(png_ptr, "invalid alpha mode"); + } + + /* Only set the default gamma if the file gamma has not been set (this has + * the side effect that the gamma in a second call to png_set_alpha_mode will + * be ignored.) + */ + if (png_ptr->colorspace.gamma == 0) + { + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* But always set the output gamma: */ + png_ptr->screen_gamma = output_gamma; + + /* Finally, if pre-multiplying, set the background fields to achieve the + * desired result. + */ + if (compose != 0) + { + /* And obtain alpha pre-multiplication by composing on black: */ + memset(&png_ptr->background, 0, (sizeof png_ptr->background)); + png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, + "conflicting calls to set alpha mode and background"); + + png_ptr->transformations |= PNG_COMPOSE; + } +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) +{ + png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, + output_gamma)); +} +# endif +#endif + #ifdef PNG_READ_QUANTIZE_SUPPORTED -/* Quantize file to 8 bit. Supply a palette, the current number +/* 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 + * of colors is greater than the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates - * whether we need a quantizeing cube set up for RGB images, or if we + * whether we need a quantizing 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; + struct png_dsort_struct * next; png_byte left; png_byte right; } png_dsort; -typedef png_dsort FAR * png_dsortp; -typedef png_dsort FAR * FAR * png_dsortpp; +typedef png_dsort * png_dsortp; +typedef png_dsort * * png_dsortpp; void PNGAPI -png_set_quantize(png_structp png_ptr, png_colorp palette, - int num_palette, int maximum_colors, png_uint_16p histogram, - int full_quantize) +png_set_quantize(png_structrp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_const_uint_16p histogram, + int full_quantize) { png_debug(1, "in png_set_quantize"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; + png_ptr->transformations |= PNG_QUANTIZE; - if (!full_quantize) + if (full_quantize == 0) { int i; png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); for (i = 0; i < num_palette; i++) png_ptr->quantize_index[i] = (png_byte)i; } @@ -193,7 +443,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, /* Initialize an array to sort colors */ png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); /* Initialize the quantize_sort array */ for (i = 0; i < num_palette; i++) @@ -225,12 +475,13 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, done = 0; } } - if (done) + + if (done != 0) break; } /* Swap the palette around, and set up a table, if necessary */ - if (full_quantize) + if (full_quantize != 0) { int j = num_palette; @@ -244,6 +495,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, do j--; while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + palette[i] = palette[j]; } } @@ -325,9 +577,9 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, /* Initialize palette index arrays */ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); /* Initialize the sort array */ for (i = 0; i < num_palette; i++) @@ -337,7 +589,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, } hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * - png_sizeof(png_dsortp))); + (sizeof (png_dsortp)))); num_new_palette = num_palette; @@ -367,9 +619,11 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, { t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(png_sizeof(png_dsort))); + (png_uint_32)(sizeof (png_dsort))); + if (t == NULL) break; + t->next = hash[d]; t->left = (png_byte)i; t->right = (png_byte)j; @@ -390,9 +644,9 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, for (p = hash[i]; p; p = p->next) { if ((int)png_ptr->index_to_palette[p->left] - < num_new_palette && - (int)png_ptr->index_to_palette[p->right] - < num_new_palette) + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) { int j, next_j; @@ -409,31 +663,34 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, num_new_palette--; palette[png_ptr->index_to_palette[j]] - = palette[num_new_palette]; - if (!full_quantize) + = palette[num_new_palette]; + if (full_quantize == 0) { int k; for (k = 0; k < num_palette; k++) { if (png_ptr->quantize_index[k] == - png_ptr->index_to_palette[j]) + png_ptr->index_to_palette[j]) png_ptr->quantize_index[k] = - png_ptr->index_to_palette[next_j]; + png_ptr->index_to_palette[next_j]; + if ((int)png_ptr->quantize_index[k] == - num_new_palette) + num_new_palette) png_ptr->quantize_index[k] = - png_ptr->index_to_palette[j]; + png_ptr->index_to_palette[j]; } } png_ptr->index_to_palette[png_ptr->palette_to_index - [num_new_palette]] = png_ptr->index_to_palette[j]; + [num_new_palette]] = png_ptr->index_to_palette[j]; + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] - = png_ptr->palette_to_index[num_new_palette]; + = png_ptr->palette_to_index[num_new_palette]; png_ptr->index_to_palette[j] = (png_byte)num_new_palette; + png_ptr->palette_to_index[num_new_palette] = (png_byte)j; } @@ -475,23 +732,24 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, } png_ptr->num_palette = (png_uint_16)num_palette; - if (full_quantize) + if (full_quantize != 0) { int i; png_bytep distance; int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + - PNG_QUANTIZE_BLUE_BITS; + PNG_QUANTIZE_BLUE_BITS; int num_red = (1 << PNG_QUANTIZE_RED_BITS); int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); png_size_t num_entries = ((png_size_t)1 << total_bits); - png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr, - (png_uint_32)(num_entries * png_sizeof(png_byte))); + png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, + (png_uint_32)(num_entries * (sizeof (png_byte)))); distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - png_sizeof(png_byte))); - png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); + (sizeof (png_byte)))); + + memset(distance, 0xff, num_entries * (sizeof (png_byte))); for (i = 0; i < num_palette; i++) { @@ -536,34 +794,57 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, png_free(png_ptr, distance); } } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#endif /* READ_QUANTIZE */ -#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. - * - * We will turn off gamma transformation later if no semitransparent entries - * are present in the tRNS array for palette images. We can't do it here - * because we don't necessarily have the tRNS chunk yet. - */ -void PNGAPI -png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +#ifdef PNG_READ_GAMMA_SUPPORTED +void PNGFAPI +png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, + png_fixed_point file_gamma) { - png_debug(1, "in png_set_gamma"); + png_debug(1, "in png_set_gamma_fixed"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; - if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) - png_ptr->transformations |= PNG_GAMMA; - png_ptr->gamma = (float)file_gamma; - png_ptr->screen_gamma = (float)scrn_gamma; + /* New in libpng-1.5.4 - reserve particular negative values as flags. */ + scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); + + /* Checking the gamma values for being >0 was added in 1.5.4 along with the + * premultiplied alpha support; this actually hides an undocumented feature + * of the previous implementation which allowed gamma processing to be + * disabled in background handling. There is no evidence (so far) that this + * was being used; however, png_set_background itself accepted and must still + * accept '0' for the gamma value it takes, because it isn't always used. + * + * Since this is an API change (albeit a very minor one that removes an + * undocumented API feature) the following checks were only enabled in + * libpng-1.6.0. + */ + if (file_gamma <= 0) + png_error(png_ptr, "invalid file gamma in png_set_gamma"); + + if (scrn_gamma <= 0) + png_error(png_ptr, "invalid screen gamma in png_set_gamma"); + + /* Set the gamma values unconditionally - this overrides the value in the PNG + * file if a gAMA chunk was present. png_set_alpha_mode provides a + * different, easier, way to default the file gamma. + */ + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + png_ptr->screen_gamma = scrn_gamma; } -#endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) +{ + png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), + convert_gamma_value(png_ptr, file_gamma)); +} +# endif /* FLOATING_POINT */ +#endif /* READ_GAMMA */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted images to RGB, expand grayscale images of @@ -571,15 +852,14 @@ png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) * to alpha channels. */ void PNGAPI -png_set_expand(png_structp png_ptr) +png_set_expand(png_structrp png_ptr) { png_debug(1, "in png_set_expand"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } /* GRR 19990627: the following three functions currently are identical @@ -602,138 +882,183 @@ png_set_expand(png_structp png_ptr) /* Expand paletted images to RGB. */ void PNGAPI -png_set_palette_to_rgb(png_structp png_ptr) +png_set_palette_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_palette_to_rgb"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } /* Expand grayscale images of less than 8-bit depth to 8 bits. */ void PNGAPI -png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) +png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) { png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_EXPAND; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } - - /* Expand tRNS chunks to alpha channels. */ void PNGAPI -png_set_tRNS_to_alpha(png_structp png_ptr) +png_set_tRNS_to_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_tRNS_to_alpha"); + if (png_rtran_ok(png_ptr, 0) == 0) + return; + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } -#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ +#endif /* READ_EXPAND */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise + * it may not work correctly.) + */ +void PNGAPI +png_set_expand_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED void PNGAPI -png_set_gray_to_rgb(png_structp png_ptr) +png_set_gray_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_gray_to_rgb"); + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* Because rgb must be 8 bits or more: */ + png_set_expand_gray_1_2_4_to_8(png_ptr); png_ptr->transformations |= PNG_GRAY_TO_RGB; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void PNGFAPI +png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray"); + + /* Need the IHDR here because of the check on color_type below. */ + /* TODO: fix this */ + if (png_rtran_ok(png_ptr, 1) == 0) + return; + + switch (error_action) + { + case PNG_ERROR_ACTION_NONE: + png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case PNG_ERROR_ACTION_WARN: + png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case PNG_ERROR_ACTION_ERROR: + png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + break; + + default: + png_error(png_ptr, "invalid error action to rgb_to_gray"); + break; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + /* Make this an error in 1.6 because otherwise the application may assume + * that it just worked and get a memory overwrite. + */ + png_error(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + + /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ + } +#endif + { + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) + { + png_uint_16 red_int, green_int; + + /* NOTE: this calculation does not round, but this behavior is retained + * for consistency; the inaccuracy is very small. The code here always + * overwrites the coefficients, regardless of whether they have been + * defaulted or set already. + */ + red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); + green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); + + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_coefficients_set = 1; + } + + else + { + if (red >= 0 && green >= 0) + png_app_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); + + /* Use the defaults, from the cHRM chunk if set, else the historical + * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See + * png_do_rgb_to_gray for more discussion of the values. In this case + * the coefficients are not marked as 'set' and are not overwritten if + * something has already provided a default. + */ + if (png_ptr->rgb_to_gray_red_coeff == 0 && + png_ptr->rgb_to_gray_green_coeff == 0) + { + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + } + } + } +} + #ifdef 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, +png_set_rgb_to_gray(png_structrp 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); - if (png_ptr == NULL) - return; - png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); + png_set_rgb_to_gray_fixed(png_ptr, error_action, + png_fixed(png_ptr, red, "rgb to gray red coefficient"), + png_fixed(png_ptr, green, "rgb to gray green coefficient")); } -#endif +#endif /* FLOATING POINT */ -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"); - - if (png_ptr == NULL) - return; - - 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) -#ifdef 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 +#endif /* RGB_TO_GRAY */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) void PNGAPI -png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr - read_user_transform_fn) +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + read_user_transform_fn) { png_debug(1, "in png_set_read_user_transform_fn"); - if (png_ptr == NULL) - return; - #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED png_ptr->transformations |= PNG_USER_TRANSFORM; png_ptr->read_user_transform_fn = read_user_transform_fn; @@ -741,26 +1066,361 @@ png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr } #endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +/* In the case of gamma transformations 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. + */ +static int /* PRIVATE */ +png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) +{ + /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma + * correction as a difference of the overall transform from 1.0 + * + * We want to compare the threshold with s*f - 1, if we get + * overflow here it is because of wacky gamma values so we + * turn on processing anyway. + */ + png_fixed_point gtest; + return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || + png_gamma_significant(gtest); +} +#endif + /* Initialize everything needed for the read. This includes modifying * the palette. */ + +/* For the moment 'png_init_palette_transformations' and + * 'png_init_rgb_transformations' only do some flag canceling optimizations. + * The intent is that these two routines should have palette or rgb operations + * extracted from 'png_init_read_transformations'. + */ +static void /* PRIVATE */ +png_init_palette_transformations(png_structrp png_ptr) +{ + /* Called to handle the (input) palette case. In png_do_read_transformations + * the first step is to expand the palette if requested, so this code must + * take care to only make changes that are invariant with respect to the + * palette expansion, or only do them if there is no expansion. + * + * STRIP_ALPHA has already been handled in the caller (by setting num_trans + * to 0.) + */ + int input_has_alpha = 0; + int input_has_transparency = 0; + + if (png_ptr->num_trans > 0) + { + int i; + + /* Ignore if all the entries are opaque (unlikely!) */ + for (i=0; inum_trans; ++i) + { + if (png_ptr->trans_alpha[i] == 255) + continue; + else if (png_ptr->trans_alpha[i] == 0) + input_has_transparency = 1; + else + { + input_has_transparency = 1; + input_has_alpha = 1; + break; + } + } + } + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) + { + { + 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; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + { + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; + + for (i=0; itrans_alpha[i] = (png_byte)(255 - + png_ptr->trans_alpha[i]); + } + } +#endif /* READ_INVERT_ALPHA */ + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + +static void /* PRIVATE */ +png_init_rgb_transformations(png_structrp png_ptr) +{ + /* Added to libpng-1.5.4: check the color type to determine whether there + * is any alpha or transparency in the image and simply cancel the + * background and alpha mode stuff if there isn't. + */ + int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; + int input_has_transparency = png_ptr->num_trans > 0; + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; +# endif + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0 && + (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + /* i.e., GRAY or GRAY_ALPHA */ + { + { + /* Expand background and tRNS chunks */ + int gray = png_ptr->background.gray; + int trans_gray = png_ptr->trans_color.gray; + + switch (png_ptr->bit_depth) + { + case 1: + gray *= 0xff; + trans_gray *= 0xff; + break; + + case 2: + gray *= 0x55; + trans_gray *= 0x55; + break; + + case 4: + gray *= 0x11; + trans_gray *= 0x11; + break; + + default: + + case 8: + /* FALL THROUGH (Already 8 bits) */ + + case 16: + /* Already a full 16 bits */ + break; + } + + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = (png_uint_16)gray; + + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + png_ptr->trans_color.red = png_ptr->trans_color.green = + png_ptr->trans_color.blue = (png_uint_16)trans_gray; + } + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + void /* PRIVATE */ -png_init_read_transformations(png_structp png_ptr) +png_init_read_transformations(png_structrp png_ptr) { png_debug(1, "in png_init_read_transformations"); - { -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_SHIFT_SUPPORTED) || \ - defined(PNG_READ_GAMMA_SUPPORTED) - int color_type = png_ptr->color_type; + /* This internal function is called from png_read_start_row in pngrutil.c + * and it is called before the 'rowbytes' calculation is done, so the code + * in here can change or update the transformations flags. + * + * First do updates that do not depend on the details of the PNG image data + * being processed. + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds + * png_set_alpha_mode and this is another source for a default file gamma so + * the test needs to be performed later - here. In addition prior to 1.5.4 + * the tests were repeated for the PALETTE color type here - this is no + * longer necessary (and doesn't seem to have been necessary before.) + */ + { + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; + + if (png_ptr->colorspace.gamma != 0) /* has been set */ + { + if (png_ptr->screen_gamma != 0) /* screen set too */ + gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); + } + + else if (png_ptr->screen_gamma != 0) + /* The converse - assume the file matches the screen, note that this + * perhaps undesireable default can (from 1.5.4) be changed by calling + * png_set_alpha_mode (even if the alpha handling mode isn't required + * or isn't changed from the default.) + */ + png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); + + else /* neither are set */ + /* Just in case the following prevents any processing - file and screen + * are both assumed to be linear and there is no way to introduce a + * third gamma value other than png_set_background with 'UNIQUE', and, + * prior to 1.5.4 + */ + png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; + + /* We have a gamma value now. */ + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Now turn the gamma transformation on or off as appropriate. Notice + * that PNG_GAMMA just refers to the file->screen correction. Alpha + * composition may independently cause gamma correction because it needs + * linear data (e.g. if the file has a gAMA chunk but the screen gamma + * hasn't been specified.) In any case this flag may get turned off in + * the code immediately below if the transform can be handled outside the + * row loop. + */ + if (gamma_correction != 0) + png_ptr->transformations |= PNG_GAMMA; + + else + png_ptr->transformations &= ~PNG_GAMMA; + } #endif -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Certain transformations have the effect of preventing other + * transformations that happen afterward in png_do_read_transformations; + * resolve the interdependencies here. From the code of + * png_do_read_transformations the order is: + * + * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) + * 2) PNG_STRIP_ALPHA (if no compose) + * 3) PNG_RGB_TO_GRAY + * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY + * 5) PNG_COMPOSE + * 6) PNG_GAMMA + * 7) PNG_STRIP_ALPHA (if compose) + * 8) PNG_ENCODE_ALPHA + * 9) PNG_SCALE_16_TO_8 + * 10) PNG_16_TO_8 + * 11) PNG_QUANTIZE (converts to palette) + * 12) PNG_EXPAND_16 + * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY + * 14) PNG_INVERT_MONO + * 15) PNG_INVERT_ALPHA + * 16) PNG_SHIFT + * 17) PNG_PACK + * 18) PNG_BGR + * 19) PNG_PACKSWAP + * 20) PNG_FILLER (includes PNG_ADD_ALPHA) + * 21) PNG_SWAP_ALPHA + * 22) PNG_SWAP_BYTES + * 23) PNG_USER_TRANSFORM [must be last] + */ +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0) + { + /* Stripping the alpha channel happens immediately after the 'expand' + * transformations, before all other transformation, so it cancels out + * the alpha handling. It has the side effect negating the effect of + * PNG_EXPAND_tRNS too: + */ + png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | + PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen + * so transparency information would remain just so long as it wasn't + * expanded. This produces unexpected API changes if the set of things + * that do PNG_EXPAND_tRNS changes (perfectly possible given the + * documentation - which says ask for what you want, accept what you + * get.) This makes the behavior consistent from 1.5.4: + */ + png_ptr->num_trans = 0; + } +#endif /* STRIP_ALPHA supported, no COMPOSE */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA + * settings will have no effect. + */ + if (png_gamma_significant(png_ptr->screen_gamma) == 0) + { + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + } +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Make sure the coefficients for the rgb to gray conversion are set + * appropriately. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_colorspace_set_rgb_coefficients(png_ptr); +#endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Detect gray background and attempt to enable optimization - * for gray --> RGB case +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Detect gray background and attempt to enable optimization for + * gray --> RGB case. * * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or * RGB_ALPHA (in which case need_expand is superfluous anyway), the @@ -768,142 +1428,174 @@ png_init_read_transformations(png_structp png_ptr) * 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. + * + * TODO: this code needs to be revised to avoid the complexity and + * interdependencies. The color type of the background should be recorded in + * png_set_background, along with the bit depth, then the code has a record + * of exactly what color space the background is currently in. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - !(color_type & PNG_COLOR_MASK_COLOR)) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - } else if ((png_ptr->transformations & PNG_BACKGROUND) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_GRAY_TO_RGB) && - png_ptr->background.red == png_ptr->background.green && - png_ptr->background.red == png_ptr->background.blue) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - png_ptr->background.gray = png_ptr->background.red; + /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if + * the file was grayscale the background value is gray. + */ + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } -#endif - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND)) + else if ((png_ptr->transformations & PNG_COMPOSE) != 0) { - if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + /* PNG_COMPOSE: png_set_background was called with need_expand false, + * so the color is in the color space of the output or png_set_alpha_mode + * was called and the color is black. Ignore RGB_TO_GRAY because that + * happens before GRAY_TO_RGB. + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { - /* Expand background and tRNS chunks */ - switch (png_ptr->bit_depth) + if (png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) { - 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; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_color.gray *= (png_uint_16)0xff; - png_ptr->trans_color.red = png_ptr->trans_color.green - = png_ptr->trans_color.blue = png_ptr->trans_color.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; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_color.gray *= (png_uint_16)0x55; - png_ptr->trans_color.red = png_ptr->trans_color.green - = png_ptr->trans_color.blue = png_ptr->trans_color.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; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_color.gray *= (png_uint_16)0x11; - png_ptr->trans_color.red = png_ptr->trans_color.green - = png_ptr->trans_color.blue = png_ptr->trans_color.gray; - } - break; - - case 8: - - case 16: - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - break; + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; } } - 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; - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - { -#ifdef PNG_READ_EXPAND_SUPPORTED - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) -#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_alpha[i] = (png_byte)(255 - png_ptr->trans_alpha[i]); - } - } -#endif - - } } -#endif +#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* READ_GRAY_TO_RGB */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - png_ptr->background_1 = png_ptr->background; -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations + * can be performed directly on the palette, and some (such as rgb to gray) + * can be optimized inside the palette. This is particularly true of the + * composite (background and alpha) stuff, which can be pretty much all done + * in the palette even if the result is expanded to RGB or gray afterward. + * + * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and + * earlier and the palette stuff is actually handled on the first row. This + * leads to the reported bug that the palette returned by png_get_PLTE is not + * updated. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_init_palette_transformations(png_ptr); - if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) - && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) - < PNG_GAMMA_THRESHOLD)) + else + png_init_rgb_transformations(png_ptr); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_EXPAND_16_SUPPORTED) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth != 16) { - int i, k; - k=0; - for (i=0; inum_trans; i++) - { - if (png_ptr->trans_alpha[i] != 0 && png_ptr->trans_alpha[i] != 0xff) - k=1; /* Partial transparency is present */ - } - if (k == 0) - png_ptr->transformations &= ~PNG_GAMMA; + /* TODO: fix this. Because the expand_16 operation is after the compose + * handling the background color must be 8, not 16, bits deep, but the + * application will supply a 16-bit value so reduce it here. + * + * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at + * present, so that case is ok (until do_expand_16 is moved.) + * + * NOTE: this discards the low 16 bits of the user supplied background + * color, but until expand_16 works properly there is no choice! + */ +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) + CHOP(png_ptr->background.red); + CHOP(png_ptr->background.green); + CHOP(png_ptr->background.blue); + CHOP(png_ptr->background.gray); +# undef CHOP } +#endif /* READ_BACKGROUND && READ_EXPAND_16 */ - if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && - png_ptr->gamma != 0.0) +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ + defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth == 16) + { + /* On the other hand, if a 16-bit file is to be reduced to 8-bits per + * component this will also happen after PNG_COMPOSE and so the background + * color must be pre-expanded here. + * + * TODO: fix this too. + */ + png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); + png_ptr->background.green = + (png_uint_16)(png_ptr->background.green * 257); + png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); + png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); + } +#endif + + /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the + * background support (see the comments in scripts/pnglibconf.dfa), this + * allows pre-multiplication of the alpha channel to be implemented as + * compositing on black. This is probably sub-optimal and has been done in + * 1.5.4 betas simply to enable external critique and testing (i.e. to + * implement the new API quickly, without lots of internal changes.) + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* Includes ALPHA_MODE */ + png_ptr->background_1 = png_ptr->background; +# endif + + /* This needs to change - in the palette image case a whole set of tables are + * built when it would be quicker to just calculate the correct value for + * each palette entry directly. Also, the test is too tricky - why check + * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that + * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the + * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction + * the gamma tables will not be built even if composition is required on a + * gamma encoded value. + * + * In 1.5.4 this is addressed below by an additional check on the individual + * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the + * tables. + */ + if ((png_ptr->transformations & PNG_GAMMA) != 0 || + ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0)) || + ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0 +# ifdef PNG_READ_BACKGROUND_SUPPORTED + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && + png_gamma_significant(png_ptr->background_gamma) != 0) +# endif + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + png_gamma_significant(png_ptr->screen_gamma) != 0)) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) { - if (color_type == PNG_COLOR_TYPE_PALETTE) + /* Issue a warning about this combination: because RGB_TO_GRAY is + * optimized to do the gamma transform if present yet do_background has + * to do the same thing if both options are set a + * double-gamma-correction happens. This is true in all versions of + * libpng to date. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_warning(png_ptr, + "libpng does not support gamma+background+rgb_to_gray"); + + if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) { - /* Could skip if no transparency */ + /* We don't get to here unless there is a tRNS chunk with non-opaque + * entries - see the checking code at the start of this function. + */ 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]; @@ -914,57 +1606,71 @@ png_init_read_transformations(png_structp png_ptr) } else { - double g, gs; + png_fixed_point g, gs; switch (png_ptr->background_gamma_type) { case PNG_BACKGROUND_GAMMA_SCREEN: g = (png_ptr->screen_gamma); - gs = 1.0; + gs = PNG_FP_1; break; case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.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); + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); break; default: - g = 1.0; /* back_1 */ - gs = 1.0; /* back */ + g = PNG_FP_1; /* back_1 */ + gs = PNG_FP_1; /* back */ + break; } - if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) + if (png_gamma_significant(gs) != 0) + { + back.red = png_gamma_8bit_correct(png_ptr->background.red, + gs); + back.green = png_gamma_8bit_correct(png_ptr->background.green, + gs); + back.blue = png_gamma_8bit_correct(png_ptr->background.blue, + gs); + } + + else { 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 + + if (png_gamma_significant(g) != 0) { - back.red = (png_byte)(pow( - (double)png_ptr->background.red/255.0, gs) * 255.0 + .5); - back.green = (png_byte)(pow( - (double)png_ptr->background.green/255.0, gs) * 255.0 - + .5); - back.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255.0, gs) * 255.0 + .5); + back_1.red = png_gamma_8bit_correct(png_ptr->background.red, + g); + back_1.green = png_gamma_8bit_correct( + png_ptr->background.green, g); + back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, + g); } - back_1.red = (png_byte)(pow( - (double)png_ptr->background.red/255.0, g) * 255.0 + .5); - back_1.green = (png_byte)(pow( - (double)png_ptr->background.green/255.0, g) * 255.0 + .5); - back_1.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255.0, g) * 255.0 + .5); + else + { + back_1.red = (png_byte)png_ptr->background.red; + back_1.green = (png_byte)png_ptr->background.green; + back_1.blue = (png_byte)png_ptr->background.blue; + } } + for (i = 0; i < num_palette; i++) { - if (i < (int)png_ptr->num_trans && png_ptr->trans_alpha[i] != 0xff) + if (i < (int)png_ptr->num_trans && + png_ptr->trans_alpha[i] != 0xff) { if (png_ptr->trans_alpha[i] == 0) { @@ -994,84 +1700,120 @@ png_init_read_transformations(png_structp png_ptr) palette[i].blue = png_ptr->gamma_table[palette[i].blue]; } } - /* Prevent the transformations being done again, and make sure - * that the now spurious alpha channel is stripped - the code - * has just reduced background composition and gamma correction - * to a simple alpha channel strip. + + /* Prevent the transformations being done again. + * + * NOTE: this is highly dubious; it removes the transformations in + * place. This seems inconsistent with the general treatment of the + * transformations elsewhere. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations &= ~PNG_GAMMA; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); + } /* color_type == PNG_COLOR_TYPE_PALETTE */ + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ - else - /* color_type != PNG_COLOR_TYPE_PALETTE */ + 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; + int gs_sig, g_sig; + png_fixed_point g = PNG_FP_1; /* Correction to linear */ + png_fixed_point gs = PNG_FP_1; /* Correction to screen */ switch (png_ptr->background_gamma_type) { case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = 1.0; + g = png_ptr->screen_gamma; + /* gs = PNG_FP_1; */ break; case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.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); + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); break; + + default: + png_error(png_ptr, "invalid background gamma type"); } - 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); + g_sig = png_gamma_significant(g); + gs_sig = png_gamma_significant(gs); + + if (g_sig != 0) + png_ptr->background_1.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, g); + + if (gs_sig != 0) + png_ptr->background.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, gs); if ((png_ptr->background.red != png_ptr->background.green) || (png_ptr->background.red != png_ptr->background.blue) || (png_ptr->background.red != png_ptr->background.gray)) { /* RGB or RGBA with color background */ - 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); + if (g_sig != 0) + { + png_ptr->background_1.red = png_gamma_correct(png_ptr, + png_ptr->background.red, g); + + png_ptr->background_1.green = png_gamma_correct(png_ptr, + png_ptr->background.green, g); + + png_ptr->background_1.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, g); + } + + if (gs_sig != 0) + { + png_ptr->background.red = png_gamma_correct(png_ptr, + png_ptr->background.red, gs); + + png_ptr->background.green = png_gamma_correct(png_ptr, + png_ptr->background.green, gs); + + png_ptr->background.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, gs); + } } + else { /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ png_ptr->background_1.red = png_ptr->background_1.green - = png_ptr->background_1.blue = png_ptr->background_1.gray; + = png_ptr->background_1.blue = png_ptr->background_1.gray; + png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; + = png_ptr->background.blue = png_ptr->background.gray; } - } - } + + /* The background is now in screen gamma: */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; + } /* color_type != PNG_COLOR_TYPE_PALETTE */ + }/* png_ptr->transformations & PNG_BACKGROUND */ + else /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (color_type == PNG_COLOR_TYPE_PALETTE) +#endif /* READ_BACKGROUND */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ + && ((png_ptr->transformations & PNG_EXPAND) == 0 || + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) +#endif + ) { png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; + /* NOTE: there are other transformations that should probably be in + * here too. + */ for (i = 0; i < num_palette; i++) { palette[i].red = png_ptr->gamma_table[palette[i].red]; @@ -1081,16 +1823,17 @@ png_init_read_transformations(png_structp png_ptr) /* Done the gamma correction. */ png_ptr->transformations &= ~PNG_GAMMA; - } + } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ } #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif -#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ +#endif /* READ_GAMMA */ + #ifdef PNG_READ_BACKGROUND_SUPPORTED - /* No GAMMA transformation */ - if ((png_ptr->transformations & PNG_BACKGROUND) && - (color_type == PNG_COLOR_TYPE_PALETTE)) + /* No GAMMA transformation (see the hanging else 4 lines above) */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; int istop = (int)png_ptr->num_trans; @@ -1107,54 +1850,70 @@ png_init_read_transformations(png_structp png_ptr) { palette[i] = back; } + else if (png_ptr->trans_alpha[i] != 0xff) { /* The png_composite() macro is defined in png.h */ png_composite(palette[i].red, palette[i].red, - png_ptr->trans_alpha[i], back.red); + png_ptr->trans_alpha[i], back.red); + png_composite(palette[i].green, palette[i].green, - png_ptr->trans_alpha[i], back.green); + png_ptr->trans_alpha[i], back.green); + png_composite(palette[i].blue, palette[i].blue, - png_ptr->trans_alpha[i], back.blue); + png_ptr->trans_alpha[i], back.blue); } } - /* Handled alpha, still need to strip the channel. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations |= PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_COMPOSE; } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_BACKGROUND */ #ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) && - (color_type == PNG_COLOR_TYPE_PALETTE)) + if ((png_ptr->transformations & PNG_SHIFT) != 0 && + (png_ptr->transformations & PNG_EXPAND) == 0 && + (png_ptr->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; + int i; + int istop = png_ptr->num_palette; + int shift = 8 - png_ptr->sig_bit.red; - 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; - } + png_ptr->transformations &= ~PNG_SHIFT; + + /* significant bits can be in the range 1 to 7 for a meaninful result, if + * the number of significant bits is 0 then no shift is done (this is an + * error condition which is silently ignored.) + */ + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].red; + + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.green; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].green; + + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.blue; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].blue; + + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } } -#endif /* PNG_READ_SHIFT_SUPPORTED */ - } -#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ - && !defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr) - return; -#endif +#endif /* READ_SHIFT */ } /* Modify the info structure to reflect the transformations. The @@ -1162,388 +1921,210 @@ png_init_read_transformations(png_structp png_ptr) * assuming the transformations result in valid PNG data. */ void /* PRIVATE */ -png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_transform_info"); #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) + /* This check must match what actually happens in + * png_do_expand_palette; if it ever checks the tRNS chunk to see if + * it is all opaque we must do the same (at present it does not.) + */ + if (png_ptr->num_trans > 0) 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; + + if (png_ptr->palette == NULL) + png_error (png_ptr, "Palette is NULL in indexed image"); } else { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { - if (png_ptr->transformations & PNG_EXPAND_tRNS) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + 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 -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) - { - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; - info_ptr->num_trans = 0; +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* The following is almost certainly wrong unless the background value is in + * the screen space! + */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0) info_ptr->background = png_ptr->background; - } #endif #ifdef 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 - } + /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), + * however it seems that the code in png_init_read_transformations, which has + * been called before this from png_read_update_info->png_read_start_row + * sometimes does the gamma transform and cancels the flag. + * + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. + */ + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; #endif -#ifdef 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 (info_ptr->bit_depth == 16) + { +# ifdef PNG_READ_16BIT_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# else + /* No 16 bit support: force chopping 16-bit input down to 8, in this case + * the app program can chose if both APIs are available by setting the + * correct scaling to use. + */ +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* For compatibility with previous versions use the strip method by + * default. This code works because if PNG_SCALE_16_TO_8 is already + * set the code below will do that in preference to the chop. + */ + png_ptr->transformations |= PNG_16_TO_8; + info_ptr->bit_depth = 8; +# else + +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_ptr->transformations |= PNG_SCALE_16_TO_8; + info_ptr->bit_depth = 8; +# else + + CONFIGURATION ERROR: you must enable at least one 16 to 8 method +# endif +# endif +#endif /* !READ_16BIT */ + } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - info_ptr->color_type |= PNG_COLOR_MASK_COLOR; + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type | + PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) { 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) + png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) { info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; } } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + if ((png_ptr->transformations & PNG_PACK) != 0 && + (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; #endif if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; + else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) + { + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_ALPHA); + info_ptr->num_trans = 0; + } #endif - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; #ifdef 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))) + if ((png_ptr->transformations & PNG_FILLER) != 0 && + (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) { info_ptr->channels++; /* If adding a true alpha channel not just filler */ - if (png_ptr->transformations & PNG_ADD_ALPHA) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } #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) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + 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) + + 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->bit_depth); info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + /* Adding in 1.5.4: cache the above value in png_struct so that we can later + * check in png_rowbytes that the user buffer won't get overwritten. Note + * that the field is not always set - if png_read_update_info isn't called + * the application has to either not do any transforms or get the calculation + * right itself. + */ + png_ptr->info_rowbytes = info_ptr->rowbytes; + #ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr) + if (png_ptr != NULL) 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"); - - if (png_ptr->row_buf == NULL) - { -#ifdef PNG_STDIO_SUPPORTED - char msg[50]; - - png_snprintf2(msg, 50, - "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, - png_ptr->pass); - png_error(png_ptr, msg); -#else - png_error(png_ptr, "NULL row buffer"); -#endif - } -#ifdef PNG_WARN_UNINITIALIZED_ROW - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - /* Application has failed to call either png_read_start_image() - * or png_read_update_info() after setting transforms that expand - * pixels. This check added to libpng-1.2.19 - */ -#if (PNG_WARN_UNINITIALIZED_ROW==1) - png_error(png_ptr, "Uninitialized row"); -#else - png_warning(png_ptr, "Uninitialized row"); -#endif -#endif - -#ifdef 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_alpha, png_ptr->num_trans); - } - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_color)); - else - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - NULL); - } - } -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); -#endif - -#ifdef 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) == - 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) == - 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. - */ - -#ifdef 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 - -#ifdef 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_color), &(png_ptr->background) -#ifdef PNG_READ_GAMMA_SUPPORTED - , &(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 -); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) && -#ifdef 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 - -#ifdef 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 - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) - { - png_do_quantize((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->quantize_index); - if (png_ptr->row_info.rowbytes == (png_uint_32)0) - png_error(png_ptr, "png_do_quantize returned rowbytes=0"); - } -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef 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 - -#ifdef PNG_READ_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef 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 - -#ifdef 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 - -#ifdef 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 - -#ifdef 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 - -#ifdef PNG_READ_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef 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 */ -#ifdef 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_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - } -#endif - -} - #ifdef 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 @@ -1551,7 +2132,7 @@ png_do_read_transformations(png_structp png_ptr) * the numbers 0 or 1. If you would rather they contain 0 and 255, use * png_do_shift() after this. */ -void /* PRIVATE */ +static void png_do_unpack(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_unpack"); @@ -1571,11 +2152,13 @@ png_do_unpack(png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x01); + if (shift == 7) { shift = 0; sp--; } + else shift++; @@ -1593,11 +2176,13 @@ png_do_unpack(png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x03); + if (shift == 6) { shift = 0; sp--; } + else shift += 2; @@ -1614,11 +2199,13 @@ png_do_unpack(png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x0f); + if (shift == 4) { shift = 0; sp--; } + else shift = 4; @@ -1626,6 +2213,9 @@ png_do_unpack(png_row_infop row_info, png_bytep row) } break; } + + default: + break; } row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); @@ -1640,159 +2230,223 @@ png_do_unpack(png_row_infop row_info, png_bytep row) * 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) +static void +png_do_unshift(png_row_infop row_info, png_bytep row, + png_const_color_8p sig_bits) { + int color_type; + png_debug(1, "in png_do_unshift"); - if ( - row_info->color_type != PNG_COLOR_TYPE_PALETTE) + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (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; + int bit_depth = row_info->bit_depth; - if (row_info->color_type & PNG_COLOR_MASK_COLOR) + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { - 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; + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = 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; + shift[channels++] = bit_depth - sig_bits->gray; } - for (c = 0; c < channels; c++) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { - if (shift[c] <= 0) - shift[c] = 0; - else - value = 1; + shift[channels++] = bit_depth - sig_bits->alpha; } - if (!value) - return; - - switch (row_info->bit_depth) { - case 2: + int c, have_shift; + + for (c = have_shift = 0; c < channels; ++c) { - png_bytep bp; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; + /* A shift of more than the bit depth is an error condition but it + * gets ignored here. + */ + if (shift[c] <= 0 || shift[c] >= bit_depth) + shift[c] = 0; - for (bp = row, i = 0; i < istop; i++) + else + have_shift = 1; + } + + if (have_shift == 0) + return; + } + + switch (bit_depth) + { + default: + /* Must be 1bpp gray: should not be here! */ + /* NOTREACHED */ + break; + + case 2: + /* Must be 2bpp gray */ + /* assert(channels == 1 && shift[0] == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + + while (bp < bp_end) { - *bp >>= 1; - *bp++ &= 0x55; + int b = (*bp >> 1) & 0x55; + *bp++ = (png_byte)b; } break; } case 4: + /* Must be 4bpp gray */ + /* assert(channels == 1) */ { 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])); + png_bytep bp_end = bp + row_info->rowbytes; + int gray_shift = shift[0]; + int mask = 0xf >> gray_shift; - for (i = 0; i < istop; i++) + mask |= mask << 4; + + while (bp < bp_end) { - *bp >>= shift[0]; - *bp++ &= mask; + int b = (*bp >> gray_shift) & mask; + *bp++ = (png_byte)b; } break; } case 8: + /* Single byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_width * channels; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; - for (i = 0; i < istop; i++) + while (bp < bp_end) { - *bp++ >>= shift[i%channels]; + int b = *bp >> shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)b; } break; } +#ifdef PNG_READ_16BIT_SUPPORTED case 16: + /* Double byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_width; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; - for (i = 0; i < istop; i++) + while (bp < bp_end) { - value = (png_uint_16)((*bp << 8) + *(bp + 1)); - value >>= shift[i%channels]; + int value = (bp[0] << 8) + bp[1]; + + value >>= shift[channel]; + if (++channel >= channels) + channel = 0; *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); + *bp++ = (png_byte)value; } break; } +#endif } } } #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Chop rows of bit depth 16 down to 8 */ -void /* PRIVATE */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale rows of bit depth 16 down to 8 accurately */ +static void +png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_scale_16_to_8"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + /* The input is an array of 16 bit components, these must be scaled to + * 8 bits each. For a 16 bit value V the required value (from the PNG + * specification) is: + * + * (V * 255) / 65535 + * + * This reduces to round(V / 257), or floor((V + 128.5)/257) + * + * Represent V as the two byte value vhi.vlo. Make a guess that the + * result is the top byte of V, vhi, then the correction to this value + * is: + * + * error = floor(((V-vhi.vhi) + 128.5) / 257) + * = floor(((vlo-vhi) + 128.5) / 257) + * + * This can be approximated using integer arithmetic (and a signed + * shift): + * + * error = (vlo-vhi+128) >> 8; + * + * The approximate differs from the exact answer only when (vlo-vhi) is + * 128; it then gives a correction of +1 when the exact correction is + * 0. This gives 128 errors. The exact answer (correct for all 16 bit + * input values) is: + * + * error = (vlo-vhi+128)*65535 >> 24; + * + * An alternative arithmetic calculation which also gives no errors is: + * + * (V * 255 + 32895) >> 16 + */ + + png_int_32 tmp = *sp++; /* must be signed! */ + tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; + *dp++ = (png_byte)tmp; + } + + 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 + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +static void +/* Simply discard the low byte. This was the default behavior prior + * to libpng-1.5.4. + */ png_do_chop(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_chop"); if (row_info->bit_depth == 16) { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - png_uint_32 istop = row_info->width * row_info->channels; + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ - 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 + *dp++ = *sp; + sp += 2; /* skip low byte */ } + row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); row_info->rowbytes = row_info->width * row_info->channels; @@ -1801,7 +2455,7 @@ png_do_chop(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_swap_alpha"); @@ -1827,6 +2481,8 @@ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) *(--dp) = save; } } + +#ifdef PNG_READ_16BIT_SUPPORTED /* This converts from RRGGBBAA to AARRGGBB */ else { @@ -1849,7 +2505,9 @@ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) *(--dp) = save[1]; } } +#endif } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { /* This converts from GA to AG */ @@ -1867,6 +2525,8 @@ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) *(--dp) = save; } } + +#ifdef PNG_READ_16BIT_SUPPORTED /* This converts from GGAA to AAGG */ else { @@ -1885,118 +2545,126 @@ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) *(--dp) = save[1]; } } +#endif } } } #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { + png_uint_32 row_width; png_debug(1, "in png_do_read_invert_alpha"); + row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + if (row_info->bit_depth == 8) { /* 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++) { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; + *(--dp) = (png_byte)(255 - *(--sp)); - 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: +/* 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; - } + sp-=3; + dp=sp; } } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + +#ifdef PNG_READ_16BIT_SUPPORTED + /* 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; + } + } +#endif + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) { /* 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; + 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 + for (i = 0; i < row_width; i++) { - 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; - } + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); } } + +#ifdef PNG_READ_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + 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 } } #endif #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ -void /* PRIVATE */ +static void png_do_read_filler(png_row_infop row_info, png_bytep row, - png_uint_32 filler, png_uint_32 flags) + 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); +#ifdef PNG_READ_16BIT_SUPPORTED + png_byte hi_filler = (png_byte)(filler>>8); +#endif + png_byte lo_filler = (png_byte)filler; png_debug(1, "in png_do_read_filler"); @@ -2005,9 +2673,9 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { if (row_info->bit_depth == 8) { - /* This changes the data from G to GX */ - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { + /* This changes the data from G to GX */ 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++) @@ -2020,9 +2688,10 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, row_info->pixel_depth = 16; row_info->rowbytes = row_width * 2; } - /* This changes the data from G to XG */ + else { + /* This changes the data from G to XG */ 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++) @@ -2035,51 +2704,55 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, row_info->rowbytes = row_width * 2; } } + +#ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - /* This changes the data from GG to GGXX */ - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { + /* This changes the data from GG to GGXX */ png_bytep sp = row + (png_size_t)row_width * 2; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_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 { + /* This changes the data from GG to XXGG */ png_bytep sp = row + (png_size_t)row_width * 2; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } } +#endif } /* 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) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { + /* This changes the data from RGB to RGBX */ 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++) @@ -2094,9 +2767,10 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } - /* This changes the data from RGB to XRGB */ + else { + /* This changes the data from RGB to XRGB */ 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++) @@ -2111,17 +2785,19 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, row_info->rowbytes = row_width * 4; } } + +#ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - /* This changes the data from RRGGBB to RRGGBBXX */ - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { + /* This changes the data from RRGGBB to RRGGBBXX */ png_bytep sp = row + (png_size_t)row_width * 6; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); @@ -2129,15 +2805,16 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_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 { + /* This changes the data from RRGGBB to XXRRGGBB */ png_bytep sp = row + (png_size_t)row_width * 6; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) @@ -2148,21 +2825,23 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } + row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; } } +#endif } /* COLOR_TYPE == RGB */ } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ +static void png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { png_uint_32 i; @@ -2171,12 +2850,13 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) png_debug(1, "in png_do_gray_to_rgb"); if (row_info->bit_depth >= 8 && - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { if (row_info->bit_depth == 8) { + /* This changes G to RGB */ 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++) @@ -2186,8 +2866,10 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) *(dp--) = *(sp--); } } + else { + /* This changes GG to RRGGBB */ 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++) @@ -2201,10 +2883,12 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) } } } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (row_info->bit_depth == 8) { + /* This changes GA to RGBA */ 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++) @@ -2215,8 +2899,10 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) *(dp--) = *(sp--); } } + else { + /* This changes GGAA to RRGGBBAA */ 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++) @@ -2232,10 +2918,10 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) } } } - row_info->channels += (png_byte)2; + row_info->channels = (png_byte)(row_info->channels + 2); row_info->color_type |= PNG_COLOR_MASK_COLOR; row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); + row_info->bit_depth); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } } @@ -2243,341 +2929,281 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ at - * (THIS LINK IS DEAD June 2008) - * New link: - * + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * * 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. + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: * - * Other integer coefficents can be used via png_set_rgb_to_gray(). + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 + * + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 + * + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) +static int +png_do_rgb_to_gray(png_structrp 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"); - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { - 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; + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; - if (row_info->color_type == PNG_COLOR_TYPE_RGB) + if (row_info->bit_depth == 8) { - if (row_info->bit_depth == 8) +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) { -#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; + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; - 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 + for (i = 0; i < row_width; i++) { - 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) { - 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); + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue + 16384)>>15]; } + + else + { + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha != 0) + *(dp++) = *(sp++); } } - - 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 + else #endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) { - 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) { - 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); + rgb_error |= 1; + /* NOTE: this is the historical approach which simply + * truncates the results. + */ + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); } + + else + *(dp++) = red; + + if (have_alpha != 0) + *(dp++) = *(sp++); } } } - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + + else /* RGB bit_depth == 16 */ { - if (row_info->bit_depth == 8) +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) { -#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)((rc*red + gc*green + bc*blue)>>15); - *(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; + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; - 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; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red & 0xff) + >> png_ptr->gamma_shift][red >> 8]; - 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; - } + w = red; + } - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - *(dp++) = *(sp++); /* alpha */ + 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 + 16384)>>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); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); *(dp++) = *(sp++); } } - else + } + else #endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) + png_uint_16 red, green, blue, gray16; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red != green || red != blue) + rgb_error |= 1; + + /* From 1.5.5 in the 16 bit case do the accurate conversion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16 bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); + *(dp++) = (png_byte)((gray16 >> 8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + + if (have_alpha != 0) { - 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++); *(dp++) = *(sp++); } } } } - row_info->channels -= (png_byte)2; - row_info->color_type &= ~PNG_COLOR_MASK_COLOR; + + row_info->channels = (png_byte)(row_info->channels - 2); + row_info->color_type = (png_byte)(row_info->color_type & + ~PNG_COLOR_MASK_COLOR); row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); + row_info->bit_depth); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } 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 PNGAPI -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"); - - 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; - } -} - - -#ifdef PNG_READ_BACKGROUND_SUPPORTED +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_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_color, png_color_16p background -#ifdef PNG_READ_GAMMA_SUPPORTED - , 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 - ) +static void +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { - png_bytep sp, dp; +#ifdef PNG_READ_GAMMA_SUPPORTED + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; + png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; + png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; + png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; + png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; + int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; +#endif + + png_bytep sp; png_uint_32 i; - png_uint_32 row_width=row_info->width; + png_uint_32 row_width = row_info->width; int shift; - png_debug(1, "in png_do_background"); + png_debug(1, "in png_do_compose"); - if (background != NULL && - (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || - (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color))) { switch (row_info->color_type) { @@ -2592,16 +3218,19 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x01) - == trans_color->gray) + == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + + if (shift == 0) { shift = 7; sp++; } + else shift--; } @@ -2618,28 +3247,34 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_color->gray) + == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } + 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); + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + + if (shift == 0) { shift = 6; sp++; } + else shift -= 2; } } + else #endif { @@ -2648,16 +3283,19 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_color->gray) + == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + + if (shift == 0) { shift = 6; sp++; } + else shift -= 2; } @@ -2675,28 +3313,34 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_color->gray) + == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } + 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); + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + + if (shift == 0) { shift = 4; sp++; } + else shift -= 4; } } + else #endif { @@ -2705,16 +3349,19 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_color->gray) + == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + + if (shift == 0) { shift = 4; sp++; } + else shift -= 4; } @@ -2730,14 +3377,11 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp++) { - if (*sp == trans_color->gray) - { - *sp = (png_byte)background->gray; - } + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + else - { *sp = gamma_table[*sp]; - } } } else @@ -2746,10 +3390,8 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp++) { - if (*sp == trans_color->gray) - { - *sp = (png_byte)background->gray; - } + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; } } break; @@ -2766,12 +3408,16 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 v; v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_color->gray) + + if (v == png_ptr->trans_color.gray) { /* Background is already in screen gamma */ - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } + else { v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; @@ -2789,15 +3435,21 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 v; v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_color->gray) + + if (v == png_ptr->trans_color.gray) { - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } } } break; } + + default: + break; } break; } @@ -2812,14 +3464,15 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == trans_color->red && - *(sp + 1) == trans_color->green && - *(sp + 2) == trans_color->blue) + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } + else { *sp = gamma_table[*sp]; @@ -2834,13 +3487,13 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == trans_color->red && - *(sp + 1) == trans_color->green && - *(sp + 2) == trans_color->blue) + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } } } @@ -2854,52 +3507,73 @@ png_do_background(png_row_infop row_info, png_bytep 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_color->red && g == trans_color->green && - b == trans_color->blue) + + 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 == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.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); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->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)); + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (r == trans_color->red && g == trans_color->green && - b == trans_color->blue) + 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 == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.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); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } } } @@ -2916,27 +3590,28 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_table != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) + for (i = 0; i < row_width; i++, sp += 2) { png_uint_16 a = *(sp + 1); if (a == 0xff) - { - *dp = gamma_table[*sp]; - } + *sp = gamma_table[*sp]; + else if (a == 0) { /* Background is already in screen gamma */ - *dp = (png_byte)background->gray; + *sp = (png_byte)png_ptr->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]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (optimize == 0) + w = gamma_from_1[w]; + *sp = w; } } } @@ -2944,27 +3619,15 @@ png_do_background(png_row_infop row_info, png_bytep row, #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) + for (i = 0; i < row_width; i++, sp += 2) { png_byte a = *(sp + 1); - if (a == 0xff) - { - *dp = *sp; - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) - { - *dp = (png_byte)background->gray; - } - else - { - png_composite(*dp, *sp, a, background_1->gray); - } -#else - *dp = (png_byte)background->gray; -#endif + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; + + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background.gray); } } } @@ -2975,75 +3638,69 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_16_to_1 != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) + for (i = 0; i < row_width; i++, sp += 4) { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + 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); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED + else if (a == 0) -#else - else -#endif { /* Background is already in screen gamma */ - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED + 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); + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize != 0) + w = v; + else + w = gamma_16_from_1[(v & 0xff) >> + gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); } -#endif } } else #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) + for (i = 0; i < row_width; i++, sp += 4) { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - if (a == (png_uint_16)0xffff) + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == 0) { - png_memcpy(dp, sp, 2); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) -#else - else -#endif - { - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); - } -#ifdef PNG_READ_GAMMA_SUPPORTED - else + + else if (a < 0xffff) { 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); + png_composite_16(v, g, a, png_ptr->background.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); } -#endif } } } @@ -3059,37 +3716,43 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_table != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) + for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); if (a == 0xff) { - *dp = gamma_table[*sp]; - *(dp + 1) = gamma_table[*(sp + 1)]; - *(dp + 2) = gamma_table[*(sp + 2)]; + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 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; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->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]; + png_composite(w, v, a, png_ptr->background_1.red); + if (optimize == 0) w = gamma_from_1[w]; + *sp = w; + v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, background_1->green); - *(dp + 1) = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.green); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 1) = w; + v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, background_1->blue); - *(dp + 2) = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 2) = w; } } } @@ -3097,30 +3760,26 @@ png_do_background(png_row_infop row_info, png_bytep row, #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) + for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); - if (a == 0xff) + if (a == 0) { - *dp = *sp; - *(dp + 1) = *(sp + 1); - *(dp + 2) = *(sp + 2); + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } - else if (a == 0) + + else if (a < 0xff) { - *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); + png_composite(*sp, *sp, a, png_ptr->background.red); + + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); + + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); } } } @@ -3132,80 +3791,98 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_16_to_1 != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) + for (i = 0; i < row_width; i++, sp += 8) { 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); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 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); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 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); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 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); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } + else { - png_uint_16 v, w, x; + png_uint_16 v, w; v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, background_1->red); - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *dp = (png_byte)((x >> 8) & 0xff); - *(dp + 1) = (png_byte)(x & 0xff); + png_composite_16(w, v, a, png_ptr->background_1.red); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, background_1->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); + png_composite_16(w, v, a, png_ptr->background_1.green); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, background_1->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); + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); } } } + else #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) + for (i = 0; i < row_width; i++, sp += 8) { png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == 0) { - png_memcpy(dp, sp, 6); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } - 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 + + else if (a < 0xffff) { png_uint_16 v; @@ -3215,34 +3892,30 @@ png_do_background(png_row_infop row_info, png_bytep row, 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); + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 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 = PNG_ROWBYTES(row_info->pixel_depth, row_width); + default: + break; } } } -#endif +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure @@ -3251,20 +3924,21 @@ png_do_background(png_row_infop row_info, png_bytep row, * 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) +static void +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; + int gamma_shift = png_ptr->gamma_shift; + png_bytep sp; png_uint_32 i; png_uint_32 row_width=row_info->width; png_debug(1, "in png_do_gamma"); - if ( - ((row_info->bit_depth <= 8 && gamma_table != NULL) || - (row_info->bit_depth == 16 && gamma_16_table != NULL))) + if (((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) { switch (row_info->color_type) { @@ -3283,6 +3957,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row, sp++; } } + else /* if (row_info->bit_depth == 16) */ { sp = row; @@ -3294,10 +3969,12 @@ png_do_gamma(png_row_infop row_info, png_bytep row, *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); @@ -3316,13 +3993,17 @@ png_do_gamma(png_row_infop row_info, png_bytep row, { *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; @@ -3332,10 +4013,12 @@ png_do_gamma(png_row_infop row_info, png_bytep row, *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); @@ -3356,6 +4039,7 @@ png_do_gamma(png_row_infop row_info, png_bytep row, sp += 2; } } + else /* if (row_info->bit_depth == 16) */ { sp = row; @@ -3428,18 +4112,88 @@ png_do_gamma(png_row_infop row_info, png_bytep row, } break; } + + default: + break; } } } #endif +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* Encode the alpha channel to the output gamma (the input channel is always + * linear.) Called only with color types that have an alpha channel. Needs the + * from_1 tables. + */ +static void +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_encode_alpha"); + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + if (row_info->bit_depth == 8) + { + PNG_CONST png_bytep table = png_ptr->gamma_from_1; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + + /* The alpha channel is the last component: */ + row += step - 1; + + for (; row_width > 0; --row_width, row += step) + *row = table[*row]; + + return; + } + } + + else if (row_info->bit_depth == 16) + { + PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; + PNG_CONST int gamma_shift = png_ptr->gamma_shift; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + + /* The alpha channel is the last component: */ + row += step - 2; + + for (; row_width > 0; --row_width, row += step) + { + png_uint_16 v; + + v = table[*(row + 1) >> gamma_shift][*row]; + *row = (png_byte)((v >> 8) & 0xff); + *(row + 1) = (png_byte)(v & 0xff); + } + + return; + } + } + } + + /* Only get to here if called with a weird row_info; no harm has been done, + * so just issue a warning. + */ + png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); +} +#endif + #ifdef 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 */ +static void png_do_expand_palette(png_row_infop row_info, png_bytep row, - png_colorp palette, png_bytep trans_alpha, int num_trans) + png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { int shift, value; png_bytep sp, dp; @@ -3448,8 +4202,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, png_debug(1, "in png_do_expand_palette"); - if ( - row_info->color_type == PNG_COLOR_TYPE_PALETTE) + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) { if (row_info->bit_depth < 8) { @@ -3464,13 +4217,16 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, { if ((*sp >> shift) & 0x01) *dp = 1; + else *dp = 0; + if (shift == 7) { shift = 0; sp--; } + else shift++; @@ -3493,6 +4249,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, shift = 0; sp--; } + else shift += 2; @@ -3515,6 +4272,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, shift = 0; sp--; } + else shift += 4; @@ -3522,16 +4280,19 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, } break; } + + default: + break; } row_info->bit_depth = 8; row_info->pixel_depth = 8; row_info->rowbytes = row_width; } - switch (row_info->bit_depth) + + if (row_info->bit_depth == 8) { - case 8: { - if (trans_alpha != NULL) + if (num_trans > 0) { sp = row + (png_size_t)row_width - 1; dp = row + (png_size_t)(row_width << 2) - 1; @@ -3540,8 +4301,10 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, { if ((int)(*sp) >= num_trans) *dp-- = 0xff; + else *dp-- = trans_alpha[*sp]; + *dp-- = palette[*sp].blue; *dp-- = palette[*sp].green; *dp-- = palette[*sp].red; @@ -3553,6 +4316,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, row_info->color_type = 6; row_info->channels = 4; } + else { sp = row + (png_size_t)row_width - 1; @@ -3572,7 +4336,6 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, row_info->color_type = 2; row_info->channels = 3; } - break; } } } @@ -3581,9 +4344,9 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ -void /* PRIVATE */ +static void png_do_expand(png_row_infop row_info, png_bytep row, - png_color_16p trans_value) + png_const_color_16p trans_color) { int shift, value; png_bytep sp, dp; @@ -3595,7 +4358,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + unsigned int gray = trans_color != NULL ? trans_color->gray : 0; if (row_info->bit_depth < 8) { @@ -3603,7 +4366,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, { case 1: { - gray = (png_uint_16)((gray&0x01)*0xff); + gray = (gray & 0x01) * 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); @@ -3611,13 +4374,16 @@ png_do_expand(png_row_infop row_info, png_bytep row, { if ((*sp >> shift) & 0x01) *dp = 0xff; + else *dp = 0; + if (shift == 7) { shift = 0; sp--; } + else shift++; @@ -3628,7 +4394,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, case 2: { - gray = (png_uint_16)((gray&0x03)*0x55); + gray = (gray & 0x03) * 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); @@ -3642,6 +4408,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, shift = 0; sp--; } + else shift += 2; @@ -3652,7 +4419,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, case 4: { - gray = (png_uint_16)((gray&0x0f)*0x11); + gray = (gray & 0x0f) * 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); @@ -3665,6 +4432,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, shift = 0; sp--; } + else shift = 4; @@ -3672,6 +4440,9 @@ png_do_expand(png_row_infop row_info, png_bytep row, } break; } + + default: + break; } row_info->bit_depth = 8; @@ -3679,27 +4450,30 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_info->rowbytes = row_width; } - if (trans_value != NULL) + if (trans_color != NULL) { if (row_info->bit_depth == 8) { gray = gray & 0xff; 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) { - png_byte gray_high = (gray >> 8) & 0xff; - png_byte gray_low = gray & 0xff; + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; sp = row + row_info->rowbytes - 1; dp = row + (row_info->rowbytes << 1) - 1; for (i = 0; i < row_width; i++) @@ -3709,11 +4483,13 @@ png_do_expand(png_row_infop row_info, png_bytep row, *dp-- = 0; *dp-- = 0; } + else { *dp-- = 0xff; *dp-- = 0xff; } + *dp-- = *sp--; *dp-- = *sp--; } @@ -3726,21 +4502,24 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_width); } } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && + trans_color != NULL) { if (row_info->bit_depth == 8) { - png_byte red = trans_value->red & 0xff; - png_byte green = trans_value->green & 0xff; - png_byte blue = trans_value->blue & 0xff; + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); 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) == red && *(sp - 1) == green && *(sp) == blue) *dp-- = 0; + else *dp-- = 0xff; + *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; @@ -3748,31 +4527,33 @@ png_do_expand(png_row_infop row_info, png_bytep row, } else if (row_info->bit_depth == 16) { - png_byte red_high = (trans_value->red >> 8) & 0xff; - png_byte green_high = (trans_value->green >> 8) & 0xff; - png_byte blue_high = (trans_value->blue >> 8) & 0xff; - png_byte red_low = trans_value->red & 0xff; - png_byte green_low = trans_value->green & 0xff; - png_byte blue_low = trans_value->blue & 0xff; + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); sp = row + row_info->rowbytes - 1; dp = row + (png_size_t)(row_width << 3) - 1; for (i = 0; i < row_width; i++) { if (*(sp - 5) == red_high && - *(sp - 4) == red_low && - *(sp - 3) == green_high && - *(sp - 2) == green_low && - *(sp - 1) == blue_high && - *(sp ) == blue_low) + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) { *dp-- = 0; *dp-- = 0; } + else { *dp-- = 0xff; *dp-- = 0xff; } + *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; @@ -3790,10 +4571,41 @@ png_do_expand(png_row_infop row_info, png_bytep row, } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* If the bit depth is 8 and the color type is not a palette type expand the + * whole row to 16 bits. Has no effect otherwise. + */ +static void +png_do_expand_16(png_row_infop row_info, png_bytep row) +{ + if (row_info->bit_depth == 8 && + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + /* The row have a sequence of bytes containing [0..255] and we need + * to turn it into another row containing [0..65535], to do this we + * calculate: + * + * (input / 255) * 65535 + * + * Which happens to be exactly input * 257 and this can be achieved + * simply by byte replication in place (copying backwards). + */ + png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ + png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ + while (dp > sp) + dp[-2] = dp[-1] = *--sp, dp -= 2; + + row_info->rowbytes *= 2; + row_info->bit_depth = 16; + row_info->pixel_depth = (png_byte)(row_info->channels * 16); + } +} +#endif + #ifdef PNG_READ_QUANTIZE_SUPPORTED -void /* PRIVATE */ +static void png_do_quantize(png_row_infop row_info, png_bytep row, - png_bytep palette_lookup, png_bytep quantize_lookup) + png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { png_bytep sp, dp; png_uint_32 i; @@ -3801,9 +4613,9 @@ png_do_quantize(png_row_infop row_info, png_bytep row, png_debug(1, "in png_do_quantize"); + if (row_info->bit_depth == 8) { - if (row_info->color_type == PNG_COLOR_TYPE_RGB && - palette_lookup && row_info->bit_depth == 8) + if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) { int r, g, b, p; sp = row; @@ -3822,23 +4634,25 @@ png_do_quantize(png_row_infop row_info, png_bytep row, * ((b >> 3) & 0x1f); */ p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & - ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << - (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | - (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & - ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << - (PNG_QUANTIZE_BLUE_BITS)) | - ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & - ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_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 = PNG_ROWBYTES(row_info->pixel_depth, row_width); } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - palette_lookup != NULL && row_info->bit_depth == 8) + palette_lookup != NULL) { int r, g, b, p; sp = row; @@ -3851,25 +4665,28 @@ png_do_quantize(png_row_infop row_info, png_bytep row, sp++; p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & - ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << - (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | - (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & - ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << - (PNG_QUANTIZE_BLUE_BITS)) | - ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & - ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_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 = PNG_ROWBYTES(row_info->pixel_depth, row_width); } + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - quantize_lookup && row_info->bit_depth == 8) + quantize_lookup) { sp = row; + for (i = 0; i < row_width; i++, sp++) { *sp = quantize_lookup[*sp]; @@ -3877,327 +4694,304 @@ png_do_quantize(png_row_infop row_info, png_bytep row, } } } -#endif +#endif /* READ_QUANTIZE */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -#ifdef PNG_READ_GAMMA_SUPPORTED -static PNG_CONST int png_gamma_shift[] = - {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00}; - -/* 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. - * - * See the PNG extensions document for an integer algorithm for creating - * the gamma tables. Maybe we will implement that here someday. - * - * We should only reach this point if - * - * the file_gamma is known (i.e., the gAMA or sRGB chunk is present, - * or the application has provided a file_gamma) - * - * AND - * { - * the screen_gamma is known - * - * OR - * - * RGB_to_gray transformation is being performed - * } - * - * AND - * { - * the screen_gamma is different from the reciprocal of the - * file_gamma by more than the specified threshold - * - * OR - * - * a background color has been specified and the file_gamma - * and screen_gamma are not 1.0, within the specified threshold. - * } +/* 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_build_gamma_table(png_structp png_ptr, png_byte bit_depth) +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_build_gamma_table"); + png_debug(1, "in png_do_read_transformations"); - if (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_calloc(png_ptr, - (png_uint_32)(num * png_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 * png_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 * png_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_calloc(png_ptr, - (png_uint_32)(num * png_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 * png_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_calloc(png_ptr, - (png_uint_32)(num * png_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 * png_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 - -#ifdef 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"); - - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if (png_ptr->row_buf == NULL) { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) { - 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); - } + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); } - else if (row_info->bit_depth == 16) + + else { - 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; + if (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); 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 = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); - *(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); - } + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); } } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error != 0) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + 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) == + 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. + */ + +#ifdef 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) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) != 0 && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) != 0 && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t 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 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth != 0) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +#endif /* READ_TRANSFORMS */ +#endif /* READ */ diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c index 11e412b7..6c5c3752 100644 --- a/thirdparty/libpng/pngrutil.c +++ b/thirdparty/libpng/pngrutil.c @@ -1,8 +1,8 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.4.4 [August 26, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -14,32 +14,66 @@ * libpng itself during the course of reading an image. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_READ_SUPPORTED #include "pngpriv.h" -# define png_strtod(p,a,b) strtod(a,b) +#ifdef PNG_READ_SUPPORTED + png_uint_32 PNGAPI -png_get_uint_31(png_structp png_ptr, png_bytep buf) +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) { - png_uint_32 i = png_get_uint_32(buf); - if (i > PNG_UINT_31_MAX) - png_error(png_ptr, "PNG unsigned integer out of range"); - return (i); + png_uint_32 uval = png_get_uint_32(buf); + + if (uval > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range"); + + return (uval); } -#ifndef PNG_USE_READ_MACROS + +#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) +/* The following is a variation on the above for use with the fixed + * point values used for gAMA and cHRM. Instead of png_error it + * issues a warning and returns (-1) - an invalid value because both + * gAMA and cHRM use *unsigned* integers for fixed point values. + */ +#define PNG_FIXED_ERROR (-1) + +static png_fixed_point /* PRIVATE */ +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval <= PNG_UINT_31_MAX) + return (png_fixed_point)uval; /* known to be in range */ + + /* The caller can turn off the warning by passing NULL. */ + if (png_ptr != NULL) + png_warning(png_ptr, "PNG fixed point integer out of range"); + + return PNG_FIXED_ERROR; +} +#endif + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +/* NOTE: the read macros will obscure these definitions, so that if + * PNG_USE_READ_MACROS is set the library will not use them internally, + * but the APIs will still be available externally. + * + * The parentheses around "PNGAPI function_name" in the following three + * functions are necessary because they allow the macros to co-exist with + * these (unused but exported) functions. + */ + /* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ png_uint_32 (PNGAPI -png_get_uint_32)(png_bytep buf) +png_get_uint_32)(png_const_bytep buf) { - png_uint_32 i = + png_uint_32 uval = ((png_uint_32)(*(buf )) << 24) + ((png_uint_32)(*(buf + 1)) << 16) + ((png_uint_32)(*(buf + 2)) << 8) + ((png_uint_32)(*(buf + 3)) ) ; - return (i); + return uval; } /* Grab a signed 32-bit integer from a buffer in big-endian format. The @@ -48,65 +82,100 @@ png_get_uint_32)(png_bytep buf) * the following code does a two's complement to native conversion. */ png_int_32 (PNGAPI -png_get_int_32)(png_bytep buf) +png_get_int_32)(png_const_bytep buf) { - png_uint_32 u = png_get_uint_32(buf); - if ((u & 0x80000000) == 0) /* non-negative */ - return u; + png_uint_32 uval = png_get_uint_32(buf); + if ((uval & 0x80000000) == 0) /* non-negative */ + return uval; - u = (u ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ - return -(png_int_32)u; + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + return -(png_int_32)uval; } /* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ png_uint_16 (PNGAPI -png_get_uint_16)(png_bytep buf) +png_get_uint_16)(png_const_bytep buf) { - png_uint_16 i = - ((png_uint_32)(*buf) << 8) + - ((png_uint_32)(*(buf + 1))); + /* ANSI-C requires an int value to accomodate at least 16 bits so this + * works and allows the compiler not to worry about possible narrowing + * on 32 bit systems. (Pre-ANSI systems did not make integers smaller + * than 16 bits either.) + */ + unsigned int val = + ((unsigned int)(*buf) << 8) + + ((unsigned int)(*(buf + 1))); - return (i); + return (png_uint_16)val; +} + +#endif /* READ_INT_FUNCTIONS */ + +/* Read and check the PNG file signature */ +void /* PRIVATE */ +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + png_size_t num_checked, num_to_check; + + /* Exit if the user application does not expect a signature. */ + if (png_ptr->sig_bytes >= 8) + return; + + num_checked = png_ptr->sig_bytes; + num_to_check = 8 - num_checked; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + + /* The signature must be serialized in a single I/O call. */ + 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) != 0) + { + 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; } -#endif /* PNG_USE_READ_MACROS */ /* Read the chunk header (length + type name). * Put the type name into png_ptr->chunk_name, and return the length. */ png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structp png_ptr) +png_read_chunk_header(png_structrp png_ptr) { png_byte buf[8]; png_uint_32 length; #ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that the chunk header is being read. - * PNG_IO_CHUNK_HDR requires a single I/O call. - */ png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; #endif - /* Read the length and the chunk name */ + /* Read the length and the chunk name. + * This must be performed in a single I/O call. + */ png_read_data(png_ptr, buf, 8); length = png_get_uint_31(png_ptr, buf); - /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, buf + 4, 4); + /* Put the chunk name into png_ptr->chunk_name. */ + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); - png_debug2(0, "Reading %s chunk, length = %lu", - png_ptr->chunk_name, length); + png_debug2(0, "Reading %lx chunk, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); - /* Reset the crc and run it over the chunk name */ + /* Reset the crc and run it over the chunk name. */ png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); + png_calculate_crc(png_ptr, buf + 4, 4); - /* Check to see if chunk name is valid */ + /* Check to see if chunk name is valid. */ png_check_chunk_name(png_ptr, png_ptr->chunk_name); #ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that chunk data will (possibly) be read. - * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. - */ png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; #endif @@ -115,48 +184,51 @@ png_read_chunk_header(png_structp png_ptr) /* 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_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) { if (png_ptr == NULL) return; + 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 + * are reading an 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_crc_finish(png_structrp png_ptr, png_uint_32 skip) { - png_size_t i; - png_size_t istop = png_ptr->zbuf_size; + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) + { + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_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); + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); } - if (png_crc_error(png_ptr)) + if (png_crc_error(png_ptr) != 0) { - 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))) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? + (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) { png_chunk_warning(png_ptr, "CRC error"); } + else - { - png_chunk_benign_error(png_ptr, "CRC error"); - return (0); - } + png_chunk_error(png_ptr, "CRC error"); + return (1); } @@ -167,257 +239,558 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip) * the data it has read thus far. */ int /* PRIVATE */ -png_crc_error(png_structp png_ptr) +png_crc_error(png_structrp 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_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) need_crc = 0; } - else /* critical */ + + else /* critical */ { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } #ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that the chunk CRC is being read */ - /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */ png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; #endif + /* The chunk CRC must be serialized in a single I/O call. */ png_read_data(png_ptr, crc_bytes, 4); - if (need_crc) + if (need_crc != 0) { 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) -static png_size_t -png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, - png_bytep output, png_size_t output_size) +#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ + defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ + defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) { - png_size_t count = 0; + png_bytep buffer = png_ptr->read_buffer; - png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ - png_ptr->zstream.avail_in = size; - - while (1) + if (buffer != NULL && new_size > png_ptr->read_buffer_size) { - int ret, avail; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } - /* Reset the output buffer each time round - we empty it - * after every inflate call. - */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; + if (buffer == NULL) + { + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); - ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); - avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; - - /* First copy/count any new output - but only if we didn't - * get an error code. - */ - if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) + if (buffer != NULL) { - if (output != 0 && output_size > count) - { - int copy = output_size - count; - if (avail < copy) copy = avail; - png_memcpy(output + count, png_ptr->zbuf, copy); - } - count += avail; + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + + else if (warn < 2) /* else silent */ + { + if (warn != 0) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); + + else + png_chunk_error(png_ptr, "insufficient memory to read chunk"); + } + } + + return buffer; +} +#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */ + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +#else + png_chunk_error(png_ptr, msg); +#endif + } + + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +#if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + window_bits = 15; + + else + window_bits = 0; +# else +# define window_bits 0 +# endif +#endif + + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateReset(&png_ptr->zstream); +#else + ret = inflateReset2(&png_ptr->zstream, window_bits); +#endif + } + + else + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +#else + ret = inflateInit2(&png_ptr->zstream, window_bits); +#endif + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } if (ret == Z_OK) - continue; + png_ptr->zowner = owner; - /* Termination conditions - always reset the zstream, it - * must be left in inflateInit state. - */ - png_ptr->zstream.avail_in = 0; - inflateReset(&png_ptr->zstream); + else + png_zstream_error(png_ptr, ret); - if (ret == Z_STREAM_END) - return count; /* NOTE: may be zero. */ + return ret; + } - /* Now handle the error codes - the API always returns 0 - * and the error message is dumped into the uncompressed - * buffer if available. - */ - { - PNG_CONST char *msg; - if (png_ptr->zstream.msg != 0) - msg = png_ptr->zstream.msg; - else - { -#ifdef PNG_STDIO_SUPPORTED - char umsg[52]; - - switch (ret) - { - case Z_BUF_ERROR: - msg = "Buffer error in compressed datastream in %s chunk"; - break; - case Z_DATA_ERROR: - msg = "Data error in compressed datastream in %s chunk"; - break; - default: - msg = "Incomplete compressed datastream in %s chunk"; - break; - } - - png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); - msg = umsg; -#else - msg = "Damaged compressed datastream in chunk other than IDAT"; +#ifdef window_bits +# undef window_bits #endif +} + +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.avail_out = 0; + + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). + */ + if (output != NULL) + png_ptr->zstream.next_out = output; + + do + { + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ + + avail = ZLIB_IO_MAX; + + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ + + avail_in -= avail; + png_ptr->zstream.avail_in = avail; + + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) + { + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); } - png_warning(png_ptr, msg); - } + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ - /* 0 means an error - notice that this code simple ignores - * zero length compressed chunks as a result. + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; + + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. */ - return 0; + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; } } /* - * Decompress trailing data in a chunk. The assumption is that chunkdata + * Decompress trailing data in a chunk. The assumption is that read_buffer * 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). */ -void /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) { - /* The caller should guarantee this */ - if (prefix_size > chunklength) + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = PNG_SIZE_MAX; + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (limit >= prefix_size + (terminate != 0)) { - /* The recovery is to delete the chunk. */ - png_warning(png_ptr, "invalid chunklength"); - prefix_size = 0; /* To delete everything */ - } + int ret; - else if (comp_type == PNG_COMPRESSION_TYPE_BASE) - { - png_size_t expanded_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - 0/*output*/, 0/*output size*/); + limit -= prefix_size + (terminate != 0); - /* Now check the limits on this chunk - if the limit fails the - * compressed data will be removed, the prefix will remain. - */ -#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - if (png_ptr->user_chunk_malloc_max && - (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) -#else -# ifdef PNG_USER_CHUNK_MALLOC_MAX - if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && - prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) -# endif -#endif - png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + if (limit < *newlength) + *newlength = limit; - /* If the size is zero either there was an error and a message - * has already been output (warning) or the size really is zero - * and we have nothing to do - the code will exit through the - * error case below. - */ -#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \ - defined(PNG_USER_CHUNK_MALLOC_MAX) - else -#endif - if (expanded_size > 0) + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) { - /* Success (maybe) - really uncompress the chunk. */ - png_size_t new_size = 0; - png_charp text = png_malloc_warn(png_ptr, - prefix_size + expanded_size + 1); + png_uint_32 lzsize = chunklength - prefix_size; - if (text != NULL) + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) { - png_memcpy(text, png_ptr->chunkdata, prefix_size); - new_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - (png_bytep)(text + prefix_size), expanded_size); - text[prefix_size + expanded_size] = 0; /* just in case */ - - if (new_size == expanded_size) + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength = prefix_size + expanded_size; - return; /* The success return! */ + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate != 0) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + text = NULL; + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } } - png_warning(png_ptr, "png_inflate logic error"); - png_free(png_ptr, text); + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } } - else - png_warning(png_ptr, "Not enough memory to decompress chunk"); + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; } - else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + else { -#ifdef PNG_STDIO_SUPPORTED - char umsg[50]; - - png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", - comp_type); - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, "Unknown zTXt compression type"); -#endif - - /* The recovery is to simply drop the data. */ + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; } +} +#endif /* READ_COMPRESSED_TEXT */ - /* Generic error return - leave the prefix, delete the compressed - * data, reallocate the chunkdata to remove the potentially large - * amount of compressed data. - */ +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) { - png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); - if (text != NULL) + int ret; + + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do { - if (prefix_size > 0) - png_memcpy(text, png_ptr->chunkdata, prefix_size); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; - /* This is an extra zero in the 'uncompressed' part. */ - *(png_ptr->chunkdata + prefix_size) = 0x00; + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } + + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } + + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = inflate(&png_ptr->zstream, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } - /* Ignore a malloc error here - it is safe. */ + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; } - *newlength = prefix_size; + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } } #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_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; png_uint_32 width, height; @@ -426,12 +799,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_IHDR"); - if (png_ptr->mode & PNG_HAVE_IHDR) - png_error(png_ptr, "Out of place IHDR"); + if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) + png_chunk_error(png_ptr, "out of place"); /* Check the length */ if (length != 13) - png_error(png_ptr, "Invalid IHDR chunk"); + png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; @@ -460,6 +833,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Find number of channels */ switch (png_ptr->color_type) { + default: /* invalid, png_set_IHDR calls png_error */ case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: png_ptr->channels = 1; @@ -479,19 +853,18 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); - png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); + png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, - color_type, interlace_type, compression_type, filter_type); + 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_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; int num, i; @@ -501,28 +874,36 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_PLTE"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before PLTE"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) + */ + else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) + png_chunk_error(png_ptr, "duplicate"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid PLTE after IDAT"); + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. + */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); 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)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { - png_warning(png_ptr, - "Ignoring PLTE chunk in grayscale PNG"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); return; } + #ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { @@ -533,19 +914,18 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) { + png_crc_finish(png_ptr, length); + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_warning(png_ptr, "Invalid palette chunk"); - png_crc_finish(png_ptr, length); - return; - } + png_chunk_benign_error(png_ptr, "invalid"); else - { - png_error(png_ptr, "Invalid palette chunk"); - } + png_chunk_error(png_ptr, "invalid"); + + return; } + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ num = (int)length / 3; #ifdef PNG_POINTER_INDEXING_SUPPORTED @@ -571,7 +951,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - /* If we actually NEED the PLTE chunk (ie for a paletted image), we do + /* 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. @@ -582,212 +962,205 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_crc_finish(png_ptr, 0); } + #ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + else if (png_crc_error(png_ptr) != 0) /* 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)) + * 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). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. + */ + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0) { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_benign_error(png_ptr, "CRC error"); - } - else - { - png_chunk_warning(png_ptr, "CRC error"); + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) return; - } + + else + png_chunk_error(png_ptr, "CRC error"); } + /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { + else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0) png_chunk_warning(png_ptr, "CRC error"); - } } #endif + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ png_set_PLTE(png_ptr, info_ptr, palette, num); + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ #ifdef PNG_READ_tRNS_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) { - 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; - } - } + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; + + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); } #endif +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif } void /* PRIVATE */ -png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_debug(1, "in png_handle_IEND"); - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - { - png_error(png_ptr, "No image in file"); - } + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 || + (png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_chunk_error(png_ptr, "out of place"); 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); - info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ + if (length != 0) + png_chunk_benign_error(png_ptr, "invalid"); + + PNG_UNUSED(info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED void /* PRIVATE */ -png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_gAMA(png_structrp png_ptr, png_inforp 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"); - 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"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Duplicate gAMA chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 4) { - png_warning(png_ptr, "Incorrect gAMA chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 4); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 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; - } + igamma = png_get_fixed_point(NULL, buf); -#ifdef PNG_READ_sRGB_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "gamma = (%d/100000)", (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 + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sBIT_SUPPORTED void /* PRIVATE */ -png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen, i; + png_byte sample_depth; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); - buf[0] = buf[1] = buf[2] = buf[3] = 0; + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sBIT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid sBIT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0) { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sBIT chunk"); - } - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) - { - png_warning(png_ptr, "Duplicate sBIT chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { truelen = 3; + sample_depth = 8; + } + else - truelen = (png_size_t)png_ptr->channels; + { + truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } if (length != truelen || length > 4) { - png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_chunk_benign_error(png_ptr, "invalid"); png_crc_finish(png_ptr, length); return; } + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 0) return; - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { 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]; @@ -796,384 +1169,425 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) 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 #ifdef PNG_READ_cHRM_SUPPORTED void /* PRIVATE */ -png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[32]; -#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_uint_32 uint_x, uint_y; + png_xy xy; png_debug(1, "in png_handle_cHRM"); - 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"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Duplicate cHRM chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 32) { - png_warning(png_ptr, "Incorrect cHRM chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 32); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 0) return; - uint_x = png_get_uint_32(buf); - uint_y = png_get_uint_32(buf + 4); - int_x_white = (png_fixed_point)uint_x; - int_y_white = (png_fixed_point)uint_y; + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); - uint_x = png_get_uint_32(buf + 8); - uint_y = png_get_uint_32(buf + 12); - int_x_red = (png_fixed_point)uint_x; - int_y_red = (png_fixed_point)uint_y; + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) + { + png_chunk_benign_error(png_ptr, "invalid values"); + return; + } - uint_x = png_get_uint_32(buf + 16); - uint_y = png_get_uint_32(buf + 20); - int_x_green = (png_fixed_point)uint_x; - int_y_green = (png_fixed_point)uint_y; + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; - uint_x = png_get_uint_32(buf + 24); - uint_y = png_get_uint_32(buf + 28); - int_x_blue = (png_fixed_point)uint_x; - int_y_blue = (png_fixed_point)uint_y; + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); + 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 - -#ifdef PNG_READ_sRGB_SUPPORTED - if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED -#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", - (long)int_x_white, (long)int_y_white, - (long)int_x_red, (long)int_y_red); - fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", - (long)int_x_green, (long)int_y_green, - (long)int_x_blue, (long)int_y_blue); -#endif -#endif /* PNG_CONSOLE_IO_SUPPORTED */ - } - 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 + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sRGB_SUPPORTED void /* PRIVATE */ -png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - int intent; - png_byte buf[1]; + png_byte intent; png_debug(1, "in png_handle_sRGB"); - 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"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Duplicate sRGB chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 1) { - png_warning(png_ptr, "Incorrect sRGB chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, buf, 1); - if (png_crc_finish(png_ptr, 0)) + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0) != 0) return; - intent = buf[0]; - /* Check for bad intent */ - if (intent >= PNG_sRGB_INTENT_LAST) + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0) { - png_warning(png_ptr, "Unknown sRGB intent"); + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); return; } -#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) - { - png_fixed_point igamma; -#ifdef PNG_FIXED_POINT_SUPPORTED - igamma=info_ptr->int_gamma; -#else -# ifdef PNG_FLOATING_POINT_SUPPORTED - igamma=(png_fixed_point)(info_ptr->gamma * 100000.); -# endif -#endif - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED -# 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 != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 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); + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); } -#endif /* PNG_READ_sRGB_SUPPORTED */ +#endif /* READ_sRGB */ #ifdef 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_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ { - png_byte compression_type; - png_bytep pC; - png_charp profile; - png_uint_32 skip = 0; - png_uint_32 profile_size, profile_length; - png_size_t slength, prefix_length, data_length; + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ png_debug(1, "in png_handle_iCCP"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iCCP"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - 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"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) - { - png_warning(png_ptr, "Duplicate iCCP chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); 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 - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (profile = png_ptr->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 + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and + * 4 byte checksum. The keyword must be at least one character and there is + * a terminator (0) byte and the compression method. */ - if ( profile >= png_ptr->chunkdata + slength - 1) + if (length < 9) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Malformed iCCP chunk"); + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); return; } - /* Compression_type should always be zero */ - compression_type = *profile++; - if (compression_type) + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) { - 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 - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, compression_type, - slength, prefix_length, &data_length); - - profile_length = data_length - prefix_length; - - if ( prefix_length > data_length || profile_length < 4) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Profile size field missing from iCCP chunk"); + png_crc_finish(png_ptr, length); return; } - /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(png_ptr->chunkdata + prefix_length); - profile_size = ((*(pC ))<<24) | - ((*(pC + 1))<<16) | - ((*(pC + 2))<< 8) | - ((*(pC + 3)) ); - - if (profile_size < profile_length) - profile_length = profile_size; - - if (profile_size > profile_length) + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) { -#ifdef PNG_STDIO_SUPPORTED - char umsg[50]; + uInt read_length, keyword_length; + char keyword[81]; + + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)length; + + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; + + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; + + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; + + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); + + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + const png_uint_32 profile_length = + png_get_uint_32(profile_header); + + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length) != 0) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type) != 0) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of these stuff will overflow. + */ + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length, 2/*silent*/); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + &png_ptr->colorspace, keyword, profile_length, + profile) != 0) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; + errmsg = "out of memory"; + } + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return; + } + } + + else if (size > 0) + errmsg = "truncated"; + +#ifndef __COVERITY__ + else + errmsg = png_ptr->zstream.msg; #endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Ignoring truncated iCCP profile"); -#ifdef PNG_STDIO_SUPPORTED + } - png_snprintf(umsg, 50, "declared profile size = %lu", - (unsigned long)profile_size); - png_warning(png_ptr, umsg); - png_snprintf(umsg, 50, "actual profile length = %lu", - (unsigned long)profile_length); - png_warning(png_ptr, umsg); -#endif - return; + /* else png_icc_check_tag_table output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "out of memory"; + } + + /* else png_icc_check_header output an error */ + } + + /* else png_icc_check_length output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; } - png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, - compression_type, png_ptr->chunkdata + prefix_length, profile_length); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + else + errmsg = "too many profiles"; + + /* Failure: the reason is in 'errmsg' */ + if (finished == 0) + png_crc_finish(png_ptr, length); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); } -#endif /* PNG_READ_iCCP_SUPPORTED */ +#endif /* READ_iCCP */ #ifdef PNG_READ_sPLT_SUPPORTED void /* PRIVATE */ -png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep entry_start; + png_bytep entry_start, buffer; png_sPLT_t new_palette; -#ifdef PNG_POINTER_INDEXING_SUPPORTED png_sPLT_entryp pp; -#endif - int data_length, entry_size, i; + png_uint_32 data_length; + int entry_size, i; png_uint_32 skip = 0; - png_size_t slength; + png_uint_32 dl; + png_size_t max_dl; png_debug(1, "in png_handle_sPLT"); #ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) @@ -1181,6 +1595,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } + if (--png_ptr->user_chunk_cache_max == 1) { png_warning(png_ptr, "No space in chunk cache for sPLT"); @@ -1190,74 +1605,85 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sPLT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid sPLT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "sPLT chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + if (buffer == NULL) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - png_ptr->chunkdata[slength] = 0x00; - for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; - entry_start++) + /* WARNING: this may break if size_t is less than 32 bits; it is assumed + * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a + * potential breakage point if the types in pngconf.h aren't exactly right. + */ + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) + return; + + buffer[length] = 0; + + for (entry_start = buffer; *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 > (png_bytep)png_ptr->chunkdata + slength - 2) + if (entry_start > buffer + length - 2) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; 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 - (png_bytep)png_ptr->chunkdata)); + /* This must fit in a png_uint_32 because it is derived from the original + * chunk data length. + */ + data_length = length - (png_uint_32)(entry_start - buffer); /* Integrity-check the data length */ - if (data_length % entry_size) + if ((data_length % entry_size) != 0) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_warning(png_ptr, "sPLT chunk has bad length"); return; } - new_palette.nentries = (png_int_32) ( data_length / entry_size); - if ((png_uint_32) new_palette.nentries > - (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) + dl = (png_int_32)(data_length / entry_size); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); + + if (dl > max_dl) { png_warning(png_ptr, "sPLT chunk too long"); return; } + + new_palette.nentries = (png_int_32)(data_length / entry_size); + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); + if (new_palette.entries == NULL) { png_warning(png_ptr, "sPLT chunk requires too much memory"); @@ -1271,74 +1697,79 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (new_palette.depth == 8) { - pp->red = *entry_start++; - pp->green = *entry_start++; - pp->blue = *entry_start++; - pp->alpha = *entry_start++; + 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->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++; + 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[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; + + pp[i].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_ptr->chunkdata; + new_palette.name = (png_charp)buffer; png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, new_palette.entries); } -#endif /* PNG_READ_sPLT_SUPPORTED */ +#endif /* READ_sPLT */ #ifdef PNG_READ_tRNS_SUPPORTED void /* PRIVATE */ -png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_tRNS"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tRNS"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid tRNS after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) { - png_warning(png_ptr, "Duplicate tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } @@ -1348,8 +1779,8 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length != 2) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1357,188 +1788,202 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_ptr->num_trans = 1; png_ptr->trans_color.gray = png_get_uint_16(buf); } + 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); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, buf, (png_size_t)length); + + png_crc_read(png_ptr, buf, length); png_ptr->num_trans = 1; png_ptr->trans_color.red = png_get_uint_16(buf); png_ptr->trans_color.green = png_get_uint_16(buf + 2); png_ptr->trans_color.blue = png_get_uint_16(buf + 4); } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) { - /* Should be an error, but we can cope with it. */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - if (length > (png_uint_32)png_ptr->num_palette || - length > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); + /* TODO: is this actually an error in the ISO spec? */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - if (length == 0) + + if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || + length == 0) { - png_warning(png_ptr, "Zero length tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, readbuf, (png_size_t)length); + + png_crc_read(png_ptr, readbuf, length); png_ptr->num_trans = (png_uint_16)length; } + else { - png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); return; } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) { png_ptr->num_trans = 0; return; } + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, - &(png_ptr->trans_color)); + &(png_ptr->trans_color)); } #endif #ifdef PNG_READ_bKGD_SUPPORTED void /* PRIVATE */ -png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen; png_byte buf[6]; + png_color_16 background; png_debug(1, "in png_handle_bKGD"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before bKGD"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0)) { - png_warning(png_ptr, "Invalid bKGD after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) { - 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); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) truelen = 1; - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) truelen = 6; + else truelen = 2; if (length != truelen) { - png_warning(png_ptr, "Incorrect bKGD chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 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. */ + * from the info_ptr struct. + */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - png_ptr->background.index = buf[0]; - if (info_ptr && info_ptr->num_palette) + background.index = buf[0]; + + if (info_ptr != NULL && info_ptr->num_palette != 0) { - 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; + if (buf[0] >= info_ptr->num_palette) + { + png_chunk_benign_error(png_ptr, "invalid index"); + return; + } + + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + 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); + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; } - png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ + { + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); + } + + else + { + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; + } + + png_set_bKGD(png_ptr, info_ptr, &background); } #endif #ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ -png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_hIST"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before hIST"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->mode & PNG_HAVE_PLTE) == 0) { - png_warning(png_ptr, "Invalid hIST after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) { - 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); + png_chunk_benign_error(png_ptr, "duplicate"); return; } num = length / 2 ; - if (num != (unsigned int) png_ptr->num_palette || num > - (unsigned int) PNG_MAX_PALETTE_LENGTH) + + if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) { - png_warning(png_ptr, "Incorrect hIST chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1550,7 +1995,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) readbuf[i] = png_get_uint_16(buf); } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; png_set_hIST(png_ptr, info_ptr, readbuf); @@ -1559,7 +2004,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_pHYs_SUPPORTED void /* PRIVATE */ -png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_uint_32 res_x, res_y; @@ -1567,30 +2012,33 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_pHYs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pHYs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pHYs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { - png_warning(png_ptr, "Duplicate pHYs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect pHYs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 0) return; res_x = png_get_uint_32(buf); @@ -1602,7 +2050,7 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_oFFs_SUPPORTED void /* PRIVATE */ -png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_int_32 offset_x, offset_y; @@ -1610,30 +2058,33 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_oFFs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before oFFs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid oFFs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { - png_warning(png_ptr, "Duplicate oFFs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect oFFs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 0) return; offset_x = png_get_int_32(buf); @@ -1646,66 +2097,64 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef 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_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_int_32 X0, X1; png_byte type, nparams; - png_charp buf, units, endptr; + png_bytep buffer, buf, units, endptr; png_charpp params; - png_size_t slength; int i; png_debug(1, "in png_handle_pCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pCAL after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0) { - png_warning(png_ptr, "Duplicate pCAL chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } - png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", - length + 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory for pCAL purpose"); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", + length + 1); - if (png_crc_finish(png_ptr, 0)) + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + buffer[length] = 0; /* Null terminate the last string */ png_debug(3, "Finding end of pCAL purpose string"); - for (buf = png_ptr->chunkdata; *buf; buf++) + for (buf = buffer; *buf; buf++) /* Empty loop */ ; - endptr = png_ptr->chunkdata + slength; + endptr = buffer + length; /* We need to have at least 12 bytes after the purpose string - in order to get the parameter information. */ + * in order to get the parameter information. + */ if (endptr <= buf + 12) { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1718,61 +2167,58 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(3, "Checking pCAL equation type and number of parameters"); /* Check that we have the right number of parameters for known - equation types. */ + * 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, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid parameter count"); return; } + else if (type >= PNG_EQUATION_LAST) { - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + png_chunk_benign_error(png_ptr, "unrecognized equation type"); } for (buf = units; *buf; buf++) /* Empty loop to move past the units string. */ ; png_debug(3, "Allocating pCAL parameters array"); - params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)(nparams * png_sizeof(png_charp))); + + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); + if (params == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "No memory for pCAL params"); - return; - } + { + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } /* Get pointers to the start of each parameter string. */ - for (i = 0; i < (int)nparams; i++) + for (i = 0; i < nparams; i++) { buf++; /* Skip the null string terminator from previous parameter. */ png_debug1(3, "Reading pCAL parameter %d", i); - for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) + + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; 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, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); return; } } - png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, - units, params); + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, params); } #endif @@ -1780,185 +2226,129 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef 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_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_charp 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_bytep buffer; + png_size_t i; + int state; png_debug(1, "in png_handle_sCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - 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); + png_chunk_benign_error(png_ptr, "out of place"); return; } - png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", length + 1); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); png_crc_finish(png_ptr, length); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* Validate the unit. */ + if (buffer[0] != 1 && buffer[0] != 2) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid unit"); return; } - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + /* Validate the ASCII numbers, need two ASCII numbers separated by + * a '\0' and they need to fit exactly in the chunk data. + */ + i = 1; + state = 0; - ep = png_ptr->chunkdata + 1; /* Skip unit byte */ + if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); -#ifdef PNG_FLOATING_POINT_SUPPORTED - width = png_strtod(png_ptr, ep, &vp); - if (*vp) + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive width"); + + else { - png_warning(png_ptr, "malformed width string in sCAL chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; + png_size_t heighti = i; + + state = 0; + if (png_check_fp_number((png_const_charp)buffer, length, + &state, &i) == 0 || i != length) + png_chunk_benign_error(png_ptr, "bad height format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive height"); + + else + /* This is the (only) success case. */ + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (swidth == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - png_memcpy(swidth, ep, png_strlen(ep)); -#endif -#endif - - for (ep = png_ptr->chunkdata; *ep; ep++) - /* Empty loop */ ; - ep++; - - if (png_ptr->chunkdata + slength < ep) - { - png_warning(png_ptr, "Truncated sCAL chunk"); -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); -#endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - -#ifdef PNG_FLOATING_POINT_SUPPORTED - height = png_strtod(png_ptr, ep, &vp); - if (*vp) - { - png_warning(png_ptr, "malformed height string in sCAL chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (sheight == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, swidth); - return; - } - png_memcpy(sheight, ep, png_strlen(ep)); -#endif -#endif - - if (png_ptr->chunkdata + slength < ep -#ifdef PNG_FLOATING_POINT_SUPPORTED - || width <= 0. || height <= 0. -#endif - ) - { - png_warning(png_ptr, "Invalid sCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#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, png_ptr->chunkdata[0], width, height); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); -#endif -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); - png_free(png_ptr, sheight); -#endif } #endif #ifdef PNG_READ_tIME_SUPPORTED void /* PRIVATE */ -png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[7]; png_time mod_time; png_debug(1, "in png_handle_tIME"); - 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)) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0) { - png_warning(png_ptr, "Duplicate tIME chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; if (length != 7) { - png_warning(png_ptr, "Incorrect tIME chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0)) + + if (png_crc_finish(png_ptr, 0) != 0) return; mod_time.second = buf[6]; @@ -1975,14 +2365,13 @@ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef 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_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; + png_text text_info; + png_bytep buffer; png_charp key; png_charp text; png_uint_32 skip = 0; - png_size_t slength; - int ret; png_debug(1, "in png_handle_tEXt"); @@ -1994,97 +2383,74 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } + if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for tEXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tEXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "No memory to process text chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) return; - } - key = png_ptr->chunkdata; - - key[slength] = 0x00; + key = (png_charp)buffer; + key[length] = 0; for (text = key; *text; text++) /* Empty loop to find end of key */ ; - if (text != key + slength) + if (text != key + length) text++; - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process text chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - 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); + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, text_ptr); - if (ret) - png_warning(png_ptr, "Insufficient memory to process text chunk"); + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0) + png_warning(png_ptr, "Insufficient memory to process text chunk"); } #endif #ifdef 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_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp text; - int comp_type; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; png_debug(1, "in png_handle_zTXt"); @@ -2096,116 +2462,104 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } + if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for zTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before zTXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) 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 + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "Out of memory processing zTXt chunk"); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - png_ptr->chunkdata[slength] = 0x00; + png_crc_read(png_ptr, buffer, length); - for (text = png_ptr->chunkdata; *text; text++) - /* Empty loop */ ; - - /* zTXt must have some text after the chunkdataword */ - if (text >= png_ptr->chunkdata + slength - 2) - { - png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, 0) != 0) return; - } + + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; + + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; + + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; + + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; + 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 */ + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; + + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } + + else + errmsg = png_ptr->zstream.msg; } - prefix_len = text - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, comp_type, - (png_size_t)length, prefix_len, &data_len); - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = comp_type; - text_ptr->key = png_ptr->chunkdata; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; -#endif - text_ptr->text = png_ptr->chunkdata + prefix_len; - text_ptr->text_length = data_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk"); + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #endif #ifdef 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_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp key, lang, text, lang_key; - int comp_flag; - int comp_type = 0; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; png_debug(1, "in png_handle_iTXt"); @@ -2217,491 +2571,926 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } + if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for iTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iTXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) 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 + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "No memory to process iTXt chunk"); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - png_ptr->chunkdata[slength] = 0x00; + png_crc_read(png_ptr, buffer, length); - for (lang = png_ptr->chunkdata; *lang; lang++) + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) /* 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 + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; + + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. */ + else if (prefix_length + 5 > length) + errmsg = "truncated"; - if (lang >= png_ptr->chunkdata + slength - 3) + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; + + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocation may overflow. + */ + ++prefix_length; + + if (compressed == 0 && prefix_length <= length) + uncompressed_length = length - prefix_length; + + else if (compressed != 0 && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; + + else + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "truncated"; + + if (errmsg == NULL) + { + png_text text; + + buffer[uncompressed_length+prefix_length] = 0; + + if (compressed == 0) + text.compression = PNG_ITXT_COMPRESSION_NONE; + + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; + + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } } + else - { - comp_flag = *lang++; - comp_type = *lang++; - } + errmsg = "bad compression info"; - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; - lang_key++; /* Skip NUL separator */ - - if (lang_key >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - for (text = lang_key; *text; text++) - /* Empty loop */ ; - text++; /* Skip NUL separator */ - if (text >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - prefix_len = text - png_ptr->chunkdata; - - key=png_ptr->chunkdata; - if (comp_flag) - png_decompress_chunk(png_ptr, comp_type, - (size_t)length, prefix_len, &data_len); - else - data_len = png_strlen(png_ptr->chunkdata + prefix_len); - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); - text_ptr->lang = png_ptr->chunkdata + (lang - key); - text_ptr->itxt_length = data_len; - text_ptr->text_length = 0; - text_ptr->key = png_ptr->chunkdata; - text_ptr->text = png_ptr->chunkdata + prefix_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk"); + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #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) +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { - png_uint_32 skip = 0; + png_alloc_size_t limit = PNG_SIZE_MAX; + + if (png_ptr->unknown_chunk.data != NULL) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (length <= limit) + { + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; + + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else + { + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); + } + } + + if (png_ptr->unknown_chunk.data == NULL && length > 0) + { + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; + } + + else + { + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; + } +} +#endif /* READ_UNKNOWN_CHUNKS */ + +/* Handle an unknown, or known but disabled, chunk */ +void /* PRIVATE */ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + int handled = 0; /* the chunk was handled */ png_debug(1, "in png_handle_unknown"); -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for unknown chunk"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - PNG_IDAT; - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ - png_ptr->mode |= PNG_AFTER_IDAT; - } - - if (!(png_ptr->chunk_name[0] & 0x20)) - { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - } - #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - || (png_ptr->read_user_chunk_fn != NULL) -#endif - ) - { -#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_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] - = '\0'; - png_ptr->unknown_chunk.size = (png_size_t)length; - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - else - { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); - } -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - if (png_ptr->read_user_chunk_fn != NULL) - { - /* Callback to user unknown chunk handler */ - int ret; - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - if (ret == 0) - { - if (!(png_ptr->chunk_name[0] & 0x20)) -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - } - } - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - else -#endif - skip = length; + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif - png_crc_finish(png_ptr, skip); + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ + if (png_ptr->read_user_chunk_fn != NULL) + { + if (png_cache_unknown_chunk(png_ptr, length) != 0) + { + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); -#ifndef PNG_READ_USER_CHUNKS_SUPPORTED - info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ -#endif + /* ret is: + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) + { + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + } + + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ + } + + else + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* READ_USER_CHUNKS */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + { + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (png_cache_unknown_chunk(png_ptr, length) == 0) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif + + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); + + png_crc_finish(png_ptr, length); + } +# endif + +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; + + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* USER_LIMITS */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif + } +# else /* no store support: the chunk must be handled by the user callback */ + PNG_UNUSED(info_ptr) +# endif + + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !READ_UNKNOWN_CHUNKS */ + + /* Check for unhandled critical chunks */ + if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); } /* 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. */ + * 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) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: + * + * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + */ void /* PRIVATE */ -png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) { + int i; + png_debug(1, "in png_check_chunk_name"); - if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || - isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) + + for (i=1; i<=4; ++i) { - png_chunk_error(png_ptr, "invalid chunk type"); + int c = chunk_name & 0xff; + + if (c < 65 || c > 122 || (c > 90 && c < 97)) + png_chunk_error(png_ptr, "invalid chunk type"); + + chunk_name >>= 8; } } -/* 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. */ - +/* 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 'display' value; if 'display' is true then the whole row + * (dp) is filled from the start by replicating the available pixels. If + * 'display' is false only those pixels present in the pass are filled in. + */ void /* PRIVATE */ -png_combine_row(png_structp png_ptr, png_bytep row, int mask) +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) { + unsigned int pixel_depth = png_ptr->transformed_pixel_depth; + png_const_bytep sp = png_ptr->row_buf + 1; + png_alloc_size_t row_width = png_ptr->width; + unsigned int pass = png_ptr->pass; + png_bytep end_ptr = 0; + png_byte end_byte = 0; + unsigned int end_mask; + png_debug(1, "in png_combine_row"); - if (mask == 0xff) + + /* Added in 1.5.6: it should not be possible to enter this routine until at + * least one row has been read from the PNG data and transformed. + */ + if (pixel_depth == 0) + png_error(png_ptr, "internal row logic error"); + + /* Added in 1.5.4: the pixel depth should match the information returned by + * any call to png_read_update_info at this point. Do not continue if we got + * this wrong. + */ + if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != + PNG_ROWBYTES(pixel_depth, row_width)) + png_error(png_ptr, "internal row size calculation error"); + + /* Don't expect this to ever happen: */ + if (row_width == 0) + png_error(png_ptr, "internal row width error"); + + /* Preserve the last byte in cases where only part of it will be overwritten, + * the multiply below may overflow, we don't care because ANSI-C guarantees + * we get the low bits. + */ + end_mask = (pixel_depth * row_width) & 7; + if (end_mask != 0) { - png_memcpy(row, png_ptr->row_buf + 1, - PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); + /* end_ptr == NULL is a flag to say do nothing */ + end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; + end_byte = *end_ptr; +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + /* little-endian byte */ + end_mask = 0xff << end_mask; + + else /* big-endian byte */ +# endif + end_mask = 0xff >> end_mask; + /* end_mask is now the bits to *keep* from the destination row */ } - else + + /* For non-interlaced images this reduces to a memcpy(). A memcpy() + * will also happen if interlacing isn't supported or if the application + * does not call png_set_interlace_handling(). In the latter cases the + * caller just gets a sequence of the unexpanded rows from each interlace + * pass. + */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0 && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) { - switch (png_ptr->row_info.pixel_depth) + /* Narrow images may have no bits in a pass; the caller should handle + * this, but this test is cheap: + */ + if (row_width <= PNG_PASS_START_COL(pass)) + return; + + if (pixel_depth < 8) { - 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; + /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit + * into 32 bits, then a single loop over the bytes using the four byte + * values in the 32-bit mask can be used. For the 'display' option the + * expanded mask may also not require any masking within a byte. To + * make this work the PACKSWAP option must be taken into account - it + * simply requires the pixels to be reversed in each byte. + * + * The 'regular' case requires a mask for each of the first 6 passes, + * the 'display' case does a copy for the even passes in the range + * 0..6. This has already been handled in the test above. + * + * The masks are arranged as four bytes with the first byte to use in + * the lowest bits (little-endian) regardless of the order (PACKSWAP or + * not) of the pixels in each byte. + * + * NOTE: the whole of this logic depends on the caller of this function + * only calling it on rows appropriate to the pass. This function only + * understands the 'x' logic; the 'y' logic is handled by the caller. + * + * The following defines allow generation of compile time constant bit + * masks for each pixel depth and each possibility of swapped or not + * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, + * is in the range 0..7; and the result is 1 if the pixel is to be + * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' + * for the block method. + * + * With some compilers a compile time expression of the general form: + * + * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) + * + * Produces warnings with values of 'shift' in the range 33 to 63 + * because the right hand side of the ?: expression is evaluated by + * the compiler even though it isn't used. Microsoft Visual C (various + * versions) and the Intel C compiler are known to do this. To avoid + * this the following macros are used in 1.5.6. This is a temporary + * solution to avoid destabilizing the code during the release process. + */ +# if PNG_USE_COMPILE_TIME_MASKS +# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) +# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) +# else +# define PNG_LSR(x,s) ((x)>>(s)) +# define PNG_LSL(x,s) ((x)<<(s)) +# endif +# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) +# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) + + /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is + * little endian - the first pixel is at bit 0 - however the extra + * parameter 's' can be set to cause the mask position to be swapped + * within each byte, to match the PNG format. This is done by XOR of + * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. + */ +# define PIXEL_MASK(p,x,d,s) \ + (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) + + /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. + */ +# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) +# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) + + /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp + * cases the result needs replicating, for the 4-bpp case the above + * generates a full 32 bits. + */ +# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) + +# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ + S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ + S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) + +# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ + B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ + B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) + +#if PNG_USE_COMPILE_TIME_MASKS + /* Utility macros to construct all the masks for a depth/swap + * combination. The 's' parameter says whether the format is PNG + * (big endian bytes) or not. Only the three odd-numbered passes are + * required for the display/block algorithm. + */ +# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ + S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } + +# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } + +# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) + + /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and + * then pass: + */ + static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = + { + /* Little-endian byte masks for PACKSWAP */ + { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } + }; + + /* display_mask has only three entries for the odd passes, so index by + * pass>>1. + */ + static PNG_CONST png_uint_32 display_mask[2][3][3] = + { + /* Little-endian byte masks for PACKSWAP */ + { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } + }; + +# define MASK(pass,depth,display,png)\ + ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ + row_mask[png][DEPTH_INDEX(depth)][pass]) + +#else /* !PNG_USE_COMPILE_TIME_MASKS */ + /* This is the runtime alternative: it seems unlikely that this will + * ever be either smaller or faster than the compile time approach. + */ +# define MASK(pass,depth,display,png)\ + ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) +#endif /* !USE_COMPILE_TIME_MASKS */ + + /* Use the appropriate mask to copy the required bits. In some cases + * the byte mask will be 0 or 0xff; optimize these cases. row_width is + * the number of pixels, but the code copies bytes, so it is necessary + * to special case the end. + */ + png_uint_32 pixels_per_byte = 8 / pixel_depth; + png_uint_32 mask; + +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + mask = MASK(pass, pixel_depth, display, 0); -#ifdef 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; - } +# endif + mask = MASK(pass, pixel_depth, display, 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: + for (;;) { - 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; + png_uint_32 m; -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) + /* It doesn't matter in the following if png_uint_32 has more than + * 32 bits because the high bits always match those in m<<24; it is, + * however, essential to use OR here, not +, because of this. + */ + m = mask; + mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ + m &= 0xff; + + if (m != 0) /* something to copy */ { - 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++; - } + if (m != 0xff) + *dp = (png_byte)((*dp & ~m) | (*sp & m)); else - shift += s_inc; - if (m == 1) - m = 0x80; - else - m >>= 1; + *dp = *sp; } - 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; -#ifdef 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; + /* NOTE: this may overwrite the last byte with garbage if the image + * is not an exact number of bytes wide; libpng has always done + * this. + */ + if (row_width <= pixels_per_byte) + break; /* May need to restore part of the last byte */ - 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; + row_width -= pixels_per_byte; + ++dp; + ++sp; } } + + else /* pixel_depth >= 8 */ + { + unsigned int bytes_to_copy, bytes_to_jump; + + /* Validate the depth - it must be a multiple of 8 */ + if (pixel_depth & 7) + png_error(png_ptr, "invalid user transform pixel depth"); + + pixel_depth >>= 3; /* now in bytes */ + row_width *= pixel_depth; + + /* Regardless of pass number the Adam 7 interlace always results in a + * fixed number of pixels to copy then to skip. There may be a + * different number of pixels to skip at the start though. + */ + { + unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; + + row_width -= offset; + dp += offset; + sp += offset; + } + + /* Work out the bytes to copy. */ + if (display != 0) + { + /* When doing the 'block' algorithm the pixel in the pass gets + * replicated to adjacent pixels. This is why the even (0,2,4,6) + * passes are skipped above - the entire expanded row is copied. + */ + bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; + + /* But don't allow this number to exceed the actual row width. */ + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + + else /* normal row; Adam7 only ever gives us one pixel to copy. */ + bytes_to_copy = pixel_depth; + + /* In Adam7 there is a constant offset between where the pixels go. */ + bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; + + /* And simply copy these bytes. Some optimization is possible here, + * depending on the value of 'bytes_to_copy'. Special case the low + * byte counts, which we know to be frequent. + * + * Notice that these cases all 'return' rather than 'break' - this + * avoids an unnecessary test on whether to restore the last byte + * below. + */ + switch (bytes_to_copy) + { + case 1: + for (;;) + { + *dp = *sp; + + if (row_width <= bytes_to_jump) + return; + + dp += bytes_to_jump; + sp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + case 2: + /* There is a possibility of a partial copy at the end here; this + * slows the code down somewhat. + */ + do + { + dp[0] = sp[0], dp[1] = sp[1]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + while (row_width > 1); + + /* And there can only be one byte left at this point: */ + *dp = *sp; + return; + + case 3: + /* This can only be the RGB case, so each copy is exactly one + * pixel and it is not necessary to check for a partial copy. + */ + for (;;) + { + dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + default: +#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE + /* Check for double byte alignment and, if possible, use a + * 16-bit copy. Don't attempt this for narrow images - ones that + * are less than an interlace panel wide. Don't attempt it for + * wide bytes_to_copy either - use the memcpy there. + */ + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) + { + /* Everything is aligned for png_uint_16 copies, but try for + * png_uint_32 first. + */ + if (png_isaligned(dp, png_uint_32) != 0 && + png_isaligned(sp, png_uint_32) != 0 && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) + { + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp32++ = *sp32++; + c -= (sizeof (png_uint_32)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp32 += skip; + sp32 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* Get to here when the row_width truncates the final copy. + * There will be 1-3 bytes left to copy, so don't try the + * 16-bit loop below. + */ + dp = (png_bytep)dp32; + sp = (png_const_bytep)sp32; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + + /* Else do it in 16-bit quantities, but only if the size is + * not too large. + */ + else + { + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp16++ = *sp16++; + c -= (sizeof (png_uint_16)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp16 += skip; + sp16 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* End of row - 1 byte left, bytes_to_copy > row_width: */ + dp = (png_bytep)dp16; + sp = (png_const_bytep)sp16; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + } +#endif /* ALIGN_TYPE code */ + + /* The true default - use a memcpy: */ + for (;;) + { + memcpy(dp, sp, bytes_to_copy); + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + } + + /* NOT REACHED*/ + } /* pixel_depth >= 8 */ + + /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } + else +#endif /* READ_INTERLACING */ + + /* If here then the switch above wasn't used so just memcpy the whole row + * from the temporary row buffer (notice that this overwrites the end of the + * destination row if it is a partial byte.) + */ + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + + /* Restore the overwritten bits from the last byte if necessary. */ + if (end_ptr != NULL) + *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); } #ifdef PNG_READ_INTERLACING_SUPPORTED -/* 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_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations /* Because these may affect the byte layout */) { - 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; /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) @@ -2724,7 +3513,7 @@ png_do_read_interlace(png_structp png_ptr) int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)((row_info->width + 7) & 0x07); dshift = (int)((final_width + 7) & 0x07); @@ -2732,6 +3521,7 @@ png_do_read_interlace(png_structp png_ptr) s_end = 0; s_inc = -1; } + else #endif { @@ -2747,26 +3537,32 @@ png_do_read_interlace(png_structp png_ptr) v = (png_byte)((*sp >> sshift) & 0x01); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + 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); @@ -2777,7 +3573,7 @@ png_do_read_interlace(png_structp png_ptr) png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 3) & 0x03) << 1); dshift = (int)(((final_width + 3) & 0x03) << 1); @@ -2785,6 +3581,7 @@ png_do_read_interlace(png_structp png_ptr) s_end = 0; s_inc = -2; } + else #endif { @@ -2803,26 +3600,32 @@ png_do_read_interlace(png_structp png_ptr) v = (png_byte)((*sp >> sshift) & 0x03); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + 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); @@ -2833,7 +3636,7 @@ png_do_read_interlace(png_structp png_ptr) int jstop = png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 1) & 0x01) << 2); dshift = (int)(((final_width + 1) & 0x01) << 2); @@ -2841,6 +3644,7 @@ png_do_read_interlace(png_structp png_ptr) s_end = 0; s_inc = -4; } + else #endif { @@ -2853,36 +3657,44 @@ png_do_read_interlace(png_structp png_ptr) for (i = 0; i < row_info->width; i++) { - png_byte v = (png_byte)((*sp >> sshift) & 0xf); + png_byte v = (png_byte)((*sp >> sshift) & 0x0f); int j; for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + 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]; @@ -2890,351 +3702,573 @@ png_do_read_interlace(png_structp png_ptr) for (i = 0; i < row_info->width; i++) { - png_byte v[8]; + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ int j; - png_memcpy(v, sp, pixel_bytes); + memcpy(v, sp, pixel_bytes); + for (j = 0; j < jstop; j++) { - png_memcpy(dp, v, pixel_bytes); + memcpy(dp, v, pixel_bytes); dp -= pixel_bytes; } + sp -= pixel_bytes; } break; } } + row_info->width = final_width; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); } #ifndef PNG_READ_PACKSWAP_SUPPORTED - transformations = transformations; /* Silence compiler warning */ + PNG_UNUSED(transformations) /* Silence compiler warning */ +#endif +} +#endif /* READ_INTERLACING */ + +static void +png_read_filter_row_sub(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + + PNG_UNUSED(prev_row) + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_up(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + png_bytep rp = row; + png_const_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_avg(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_bytep rp = row; + png_const_bytep pp = prev_row; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_size_t 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++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +static void +png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp_end = row + row_info->rowbytes; + int a, c; + + /* First pixel/byte */ + c = *prev_row++; + a = *row + c; + *row++ = (png_byte)a; + + /* Remainder */ + while (row < rp_end) + { + int b, pa, pb, pc, p; + + a &= 0xff; /* From previous iteration or start */ + b = *prev_row++; + + 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 + + /* Find the best predictor, the least of pa, pb, pc favoring the earlier + * ones in the case of a tie. + */ + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + /* Calculate the current pixel in a, and move the previous row pixel to c + * for the next time round the loop + */ + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp_end = row + bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + while (row < rp_end) + { + int a = *row + *prev_row++; + *row++ = (png_byte)a; + } + + /* Remainder */ + rp_end += row_info->rowbytes - bpp; + + while (row < rp_end) + { + int a, b, c, pa, pb, pc, p; + + c = *(prev_row - bpp); + a = *(row - bpp); + b = *prev_row++; + + 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 (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image (except for PNG images + * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ +{ + unsigned int bpp = (pp->pixel_depth + 7) >> 3; + + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; + if (bpp == 1) + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_1byte_pixel; + else + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_multibyte_pixel; + +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + PNG_FILTER_OPTIMIZATIONS(pp, bpp); #endif } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ 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_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, + png_const_bytep prev_row, int filter) { - png_debug(1, "in png_read_filter_row"); - png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); - switch (filter) + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ + if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) { - 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; + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); - 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; + pp->read_filter[filter-1](row_info, row, prev_row); } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ -png_read_finish_row(png_structp png_ptr) +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) +{ + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + */ + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - png_memset(png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); + + /* TO DO: don't do this if prev_row isn't needed (requires + * read-ahead of the next row's filter byte. + */ + memset(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]; - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { 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; + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; } + else /* if (png_ptr->transformations & PNG_INTERLACE) */ - break; - } while (png_ptr->iwidth == 0); + break; /* libpng deinterlacing sees every row */ + + } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); if (png_ptr->pass < 7) return; } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { - PNG_IDAT; - 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_31(png_ptr, 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_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_warning(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_warning(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - } - png_ptr->zstream.avail_out = 0; - } - - if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data"); - - inflateReset(&png_ptr->zstream); - - png_ptr->mode |= PNG_AFTER_IDAT; + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ void /* PRIVATE */ -png_read_start_row(png_structp png_ptr) +png_read_start_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; int max_pixel_depth; png_size_t row_bytes; png_debug(1, "in png_read_start_row"); - png_ptr->zstream.avail_in = 0; + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) +#endif + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; + 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]; + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; } + else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; } + max_pixel_depth = png_ptr->pixel_depth; + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of + * calculations to calculate the final pixel depth, then + * png_do_read_transforms actually does the transforms. This means that the + * code which effectively calculates this value is actually repeated in three + * separate places. They must all match. Innocent changes to the order of + * transformations can and will break libpng in a way that causes memory + * overwrites. + * + * TODO: fix this. + */ #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) 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) + + if (png_ptr->num_trans != 0) max_pixel_depth *= 2; } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { max_pixel_depth *= 4; max_pixel_depth /= 3; @@ -3243,22 +4277,42 @@ png_read_start_row(png_structp png_ptr) } #endif -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & (PNG_FILLER)) +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - max_pixel_depth = 32; - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & (PNG_FILLER)) != 0) + { + 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) + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || + png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (max_pixel_depth <= 32) max_pixel_depth = 32; + else max_pixel_depth = 64; } @@ -3266,33 +4320,39 @@ png_read_start_row(png_structp png_ptr) #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || + (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) || #endif #ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) || + (png_ptr->transformations & (PNG_FILLER)) != 0 || #endif - png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + 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) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) max_pixel_depth = 32; - else + + 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; } @@ -3301,15 +4361,22 @@ png_read_start_row(png_structp png_ptr) #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* + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + 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; - } + + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth = user_pixel_depth; + } #endif + /* This value is stored in png_struct and double checked in the row read + * code. + */ + png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; + png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ + /* Align the width on the next larger 8 pixels. Mainly used * for interlacing */ @@ -3318,7 +4385,8 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) * for safety's sake */ row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + - 1 + ((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"); @@ -3327,53 +4395,82 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if (row_bytes + 48 > png_ptr->old_big_row_buf_size) { png_free(png_ptr, png_ptr->big_row_buf); - if (png_ptr->interlaced) + png_free(png_ptr, png_ptr->big_prev_row); + + if (png_ptr->interlaced != 0) png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, row_bytes + 48); + else - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, - row_bytes + 48); - png_ptr->old_big_row_buf_size = row_bytes + 48; + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); #ifdef PNG_ALIGNED_MEMORY_SUPPORTED /* Use 16-byte aligned memory for row_buf with at least 16 bytes - * of padding before and after row_buf. + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. */ - png_ptr->row_buf = png_ptr->big_row_buf + 32 - - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16); - png_ptr->old_big_row_buf_size = row_bytes + 48; + { + png_bytep temp = png_ptr->big_row_buf + 32; + int extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } + #else - /* Use 32 bytes of padding before and 16 bytes after row_buf. */ - png_ptr->row_buf = png_ptr->big_row_buf + 32; + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; #endif png_ptr->old_big_row_buf_size = row_bytes + 48; } #ifdef PNG_MAX_MALLOC_64K - if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) + if (png_ptr->rowbytes > 65535) png_error(png_ptr, "This image requires a row greater than 64KB"); + #endif - if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1)) + if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) png_error(png_ptr, "Row has too many bytes to allocate in memory"); - if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size) + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %u,", png_ptr->width); + png_debug1(3, "height = %u,", png_ptr->height); + png_debug1(3, "iwidth = %u,", png_ptr->iwidth); + png_debug1(3, "num_rows = %u,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer != 0) { - png_free(png_ptr, png_ptr->prev_row); - png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( - png_ptr->rowbytes + 1)); - png_ptr->old_prev_row_size = png_ptr->rowbytes + 1; + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); } - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); - - png_debug1(3, "width = %lu,", png_ptr->width); - png_debug1(3, "height = %lu,", png_ptr->height); - png_debug1(3, "iwidth = %lu,", png_ptr->iwidth); - png_debug1(3, "num_rows = %lu,", png_ptr->num_rows); - png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes); - png_debug1(3, "irowbytes = %lu", - PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); png_ptr->flags |= PNG_FLAG_ROW_INIT; } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c index 1f972c4e..fce30391 100644 --- a/thirdparty/libpng/pngset.c +++ b/thirdparty/libpng/pngset.c @@ -1,8 +1,8 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -16,170 +16,152 @@ * info struct and allows us to change the structure in the future. */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #include "pngpriv.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + #ifdef PNG_bKGD_SUPPORTED void PNGAPI -png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_16p background) { png_debug1(1, "in %s storage function", "bKGD"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || background == NULL) return; - png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->background = *background; info_ptr->valid |= PNG_INFO_bKGD; } #endif #ifdef 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) +void PNGFAPI +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp 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", "cHRM"); + png_xy xy; - 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 /* PNG_FLOATING_POINT_SUPPORTED */ - -#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", "cHRM fixed"); if (png_ptr == NULL || info_ptr == NULL) return; -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) -#endif - { - 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; - } + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; + + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); } -#endif /* PNG_FIXED_POINT_SUPPORTED */ -#endif /* PNG_cHRM_SUPPORTED */ + +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, + &XYZ, 2) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_const_structrp png_ptr, png_inforp 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_set_cHRM_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, white_x, "cHRM White X"), + png_fixed(png_ptr, white_y, "cHRM White Y"), + png_fixed(png_ptr, red_x, "cHRM Red X"), + png_fixed(png_ptr, red_y, "cHRM Red Y"), + png_fixed(png_ptr, green_x, "cHRM Green X"), + png_fixed(png_ptr, green_y, "cHRM Green Y"), + png_fixed(png_ptr, blue_x, "cHRM Blue X"), + png_fixed(png_ptr, blue_y, "cHRM Blue Y")); +} + +void PNGAPI +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Red X"), + png_fixed(png_ptr, green_Y, "cHRM Red Y"), + png_fixed(png_ptr, green_Z, "cHRM Red Z"), + png_fixed(png_ptr, blue_X, "cHRM Red X"), + png_fixed(png_ptr, blue_Y, "cHRM Red Y"), + png_fixed(png_ptr, blue_Z, "cHRM Red Z")); +} +# endif /* FLOATING_POINT */ + +#endif /* cHRM */ #ifdef PNG_gAMA_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +void PNGFAPI +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) { - double png_gamma; - png_debug1(1, "in %s storage function", "gAMA"); if (png_ptr == NULL || info_ptr == NULL) return; - /* Check for overflow */ - if (file_gamma > 21474.83) - { - png_warning(png_ptr, "Limiting gamma to 21474.83"); - png_gamma=21474.83; - } - else - png_gamma = file_gamma; - info_ptr->gamma = (float)png_gamma; -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = (int)(png_gamma*100000.+.5); -#endif - info_ptr->valid |= PNG_INFO_gAMA; - if (png_gamma == 0.0) - png_warning(png_ptr, "Setting gamma=0"); + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); } -#endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point - int_gamma) +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) { - png_fixed_point png_gamma; - - png_debug1(1, "in %s storage function", "gAMA"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (int_gamma > (png_fixed_point)PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Limiting gamma to 21474.83"); - png_gamma=PNG_UINT_31_MAX; - } - else - { - if (int_gamma < 0) - { - png_warning(png_ptr, "Setting negative gamma to zero"); - png_gamma = 0; - } - else - png_gamma = int_gamma; - } -#ifdef PNG_FLOATING_POINT_SUPPORTED - info_ptr->gamma = (float)(png_gamma/100000.); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = png_gamma; -#endif - info_ptr->valid |= PNG_INFO_gAMA; - if (png_gamma == 0) - png_warning(png_ptr, "Setting gamma=0"); + png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, + "png_set_gAMA")); } +# endif #endif #ifdef PNG_hIST_SUPPORTED void PNGAPI -png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) { int i; @@ -192,36 +174,40 @@ png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) > PNG_MAX_PALETTE_LENGTH) { png_warning(png_ptr, - "Invalid palette size, hIST allocation skipped"); + "Invalid palette size, hIST allocation skipped"); + return; } png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in * version 1.2.1 */ - png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)); - if (png_ptr->hist == NULL) + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); + + if (info_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; } - 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; - info_ptr->free_me |= PNG_FREE_HIST; + + for (i = 0; i < info_ptr->num_palette; i++) + info_ptr->hist[i] = hist[i]; + + info_ptr->valid |= PNG_INFO_hIST; } #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) +png_set_IHDR(png_const_structrp png_ptr, png_inforp 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) { png_debug1(1, "in %s storage function", "IHDR"); @@ -242,30 +228,25 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr, if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; + else info_ptr->channels = 1; - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - /* Check for potential overflow */ - if (width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 64 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - info_ptr->rowbytes = 0; - else - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); } #ifdef 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_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) { png_debug1(1, "in %s storage function", "oFFs"); @@ -281,28 +262,51 @@ png_set_oFFs(png_structp png_ptr, png_infop info_ptr, #ifdef 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_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, + int nparams, png_const_charp units, png_charpp params) { png_size_t length; int i; png_debug1(1, "in %s storage function", "pCAL"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) return; - length = png_strlen(purpose) + 1; + length = strlen(purpose) + 1; png_debug1(3, "allocating purpose for info (%lu bytes)", - (unsigned long)length); - info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + (unsigned long)length); + + /* TODO: validate format of calibration name and unit name */ + + /* Check that the type matches the specification. */ + if (type < 0 || type > 3) + png_error(png_ptr, "Invalid pCAL equation type"); + + if (nparams < 0 || nparams > 255) + png_error(png_ptr, "Invalid pCAL parameter count"); + + /* Validate params[nparams] */ + for (i=0; ipcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + if (info_ptr->pcal_purpose == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + return; } - png_memcpy(info_ptr->pcal_purpose, purpose, length); + + memcpy(info_ptr->pcal_purpose, purpose, length); png_debug(3, "storing X0, X1, type, and nparams in info"); info_ptr->pcal_X0 = X0; @@ -310,39 +314,50 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, info_ptr->pcal_type = (png_byte)type; info_ptr->pcal_nparams = (png_byte)nparams; - length = png_strlen(units) + 1; + length = strlen(units) + 1; png_debug1(3, "allocating units for info (%lu bytes)", (unsigned long)length); - info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + if (info_ptr->pcal_units == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; } - png_memcpy(info_ptr->pcal_units, units, length); - info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)((nparams + 1) * png_sizeof(png_charp))); + memcpy(info_ptr->pcal_units, units, length); + + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); + if (info_ptr->pcal_params == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; } - png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); for (i = 0; i < nparams; i++) { - length = png_strlen(params[i]) + 1; + length = strlen(params[i]) + 1; png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, - (unsigned long)length); + (unsigned long)length); + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->pcal_params[i] == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; } - png_memcpy(info_ptr->pcal_params[i], params[i], length); + + memcpy(info_ptr->pcal_params[i], params[i], length); } info_ptr->valid |= PNG_INFO_pCAL; @@ -350,74 +365,136 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, } #endif -#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_sCAL_SUPPORTED void PNGAPI -png_set_sCAL(png_structp png_ptr, png_infop info_ptr, - int unit, double width, double height) +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, + int unit, png_const_charp swidth, png_const_charp sheight) { - png_debug1(1, "in %s storage function", "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_size_t length; + png_size_t lengthw = 0, lengthh = 0; png_debug1(1, "in %s storage function", "sCAL"); if (png_ptr == NULL || info_ptr == NULL) return; + /* Double check the unit (should never get here with an invalid + * unit unless this is an API call.) + */ + if (unit != 1 && unit != 2) + png_error(png_ptr, "Invalid sCAL unit"); + + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || + swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) + png_error(png_ptr, "Invalid sCAL width"); + + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || + sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) + png_error(png_ptr, "Invalid sCAL height"); + info_ptr->scal_unit = (png_byte)unit; - length = png_strlen(swidth) + 1; - png_debug1(3, "allocating unit for info (%u bytes)", - (unsigned int)length); - info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); + ++lengthw; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); + + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); + if (info_ptr->scal_s_width == NULL) { - png_warning(png_ptr, - "Memory allocation failed while processing sCAL"); + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } - png_memcpy(info_ptr->scal_s_width, swidth, length); - length = png_strlen(sheight) + 1; - png_debug1(3, "allocating unit for info (%u bytes)", - (unsigned int)length); - info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); + memcpy(info_ptr->scal_s_width, swidth, lengthw); + + ++lengthh; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); + + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); + if (info_ptr->scal_s_height == NULL) { png_free (png_ptr, info_ptr->scal_s_width); info_ptr->scal_s_width = NULL; - png_warning(png_ptr, - "Memory allocation failed while processing sCAL"); + + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } - png_memcpy(info_ptr->scal_s_height, sheight, length); + + memcpy(info_ptr->scal_s_height, sheight, lengthh); + info_ptr->valid |= PNG_INFO_sCAL; info_ptr->free_me |= PNG_FREE_SCAL; } -#endif -#endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, + PNG_sCAL_PRECISION); + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, + PNG_sCAL_PRECISION); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + png_fixed_point width, png_fixed_point height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif #endif #ifdef 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_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) { png_debug1(1, "in %s storage function", "pHYs"); @@ -432,8 +509,8 @@ png_set_pHYs(png_structp png_ptr, png_infop info_ptr, #endif void PNGAPI -png_set_PLTE(png_structp png_ptr, png_infop info_ptr, - png_colorp palette, int num_palette) +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, + png_const_colorp palette, int num_palette) { png_debug1(1, "in %s storage function", "PLTE"); @@ -445,16 +522,31 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Invalid palette length"); + else { png_warning(png_ptr, "Invalid palette length"); + return; } } + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_error(png_ptr, "Invalid palette"); + } + /* 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. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. */ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); @@ -462,9 +554,11 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, * of num_palette entries, in case of an invalid PNG file that has * too-large sample values. */ - png_ptr->palette = (png_colorp)png_calloc(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); - png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + + if (num_palette > 0) + 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; @@ -475,146 +569,124 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_sBIT_SUPPORTED void PNGAPI -png_set_sBIT(png_structp png_ptr, png_infop info_ptr, - png_color_8p sig_bit) +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_8p sig_bit) { png_debug1(1, "in %s storage function", "sBIT"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) return; - png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); + info_ptr->sig_bit = *sig_bit; info_ptr->valid |= PNG_INFO_sBIT; } #endif #ifdef PNG_sRGB_SUPPORTED void PNGAPI -png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB"); if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->srgb_intent = (png_byte)intent; - info_ptr->valid |= PNG_INFO_sRGB; + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGAPI -png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, - int intent) +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + int srgb_intent) { -#ifdef 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 -#ifdef 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 - 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 png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); if (png_ptr == NULL || info_ptr == NULL) return; - png_set_sRGB(png_ptr, info_ptr, intent); + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, + srgb_intent) != 0) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } -#ifdef 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 - -#ifdef PNG_cHRM_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; - -#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; -#endif - -#ifdef PNG_FIXED_POINT_SUPPORTED - 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 - 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 /* cHRM */ + png_colorspace_sync_info(png_ptr, info_ptr); } #endif /* sRGB */ #ifdef 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_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen) { png_charp new_iccp_name; - png_charp new_iccp_profile; - png_uint_32 length; + png_bytep new_iccp_profile; + png_size_t length; png_debug1(1, "in %s storage function", "iCCP"); if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return; - length = png_strlen(name)+1; - new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (result == 0) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); + if (new_iccp_name == NULL) { - png_warning(png_ptr, "Insufficient memory to process iCCP chunk"); + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + return; } - png_memcpy(new_iccp_name, name, length); - new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); + + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); + if (new_iccp_profile == NULL) { - png_free (png_ptr, new_iccp_name); - png_warning(png_ptr, + png_free(png_ptr, new_iccp_name); + new_iccp_name = NULL; + png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); + return; } - png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + + memcpy(new_iccp_profile, profile, 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; info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; } @@ -622,75 +694,96 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_TEXT_SUPPORTED void PNGAPI -png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, - int num_text) +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) { int ret; ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - if (ret) + + if (ret != 0) png_error(png_ptr, "Insufficient memory to store text"); } int /* PRIVATE */ -png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, - int num_text) +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) { int i; - png_debug1(1, "in %s storage function", ((png_ptr == NULL || - png_ptr->chunk_name[0] == '\0') ? - "text" : (png_const_charp)png_ptr->chunk_name)); + png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : + (unsigned long)png_ptr->chunk_name); - if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) return(0); /* Make sure we have enough space in the "text" array in info_struct - * to hold all of the incoming text_ptr objects. + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) */ - if (info_ptr->num_text + num_text > info_ptr->max_text) + if (num_text > info_ptr->max_text - info_ptr->num_text) { - if (info_ptr->text != NULL) - { - png_textp old_text; - int old_max; + int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; - 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_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - { - png_free(png_ptr, old_text); - return(1); - } - png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * - png_sizeof(png_text))); - png_free(png_ptr, old_text); - } - else + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) { - info_ptr->max_text = num_text + 8; - info_ptr->num_text = 0; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - return(1); - info_ptr->free_me |= PNG_FREE_TEXT; + max_text += num_text; + + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; + + else + max_text = INT_MAX; + + /* Now allocate a new array and copy the old members in; this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); } - png_debug1(3, "allocated %d entries for info_ptr->text", - info_ptr->max_text); + + if (new_text == NULL) + { + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); } + for (i = 0; i < num_text; i++) { - png_size_t text_length, key_len; - png_size_t lang_len, lang_key_len; + size_t text_length, key_len; + 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 < PNG_TEXT_COMPRESSION_NONE || + text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) + { + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); + continue; + } + + key_len = strlen(text_ptr[i].key); if (text_ptr[i].compression <= 0) { @@ -699,125 +792,147 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, } else -#ifdef PNG_iTXt_SUPPORTED +# ifdef PNG_iTXt_SUPPORTED { /* Set iTXt data */ if (text_ptr[i].lang != NULL) - lang_len = png_strlen(text_ptr[i].lang); + lang_len = 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); + lang_key_len = strlen(text_ptr[i].lang_key); + else lang_key_len = 0; } -#else /* PNG_iTXt_SUPPORTED */ +# else /* iTXt */ { - png_warning(png_ptr, "iTXt chunk not supported"); + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); continue; } -#endif +# endif if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') { text_length = 0; -#ifdef PNG_iTXt_SUPPORTED +# ifdef PNG_iTXt_SUPPORTED if (text_ptr[i].compression > 0) textp->compression = PNG_ITXT_COMPRESSION_NONE; + else -#endif +# endif textp->compression = PNG_TEXT_COMPRESSION_NONE; } else { - text_length = png_strlen(text_ptr[i].text); + text_length = strlen(text_ptr[i].text); textp->compression = text_ptr[i].compression; } - textp->key = (png_charp)png_malloc_warn(png_ptr, - (png_size_t) - (key_len + text_length + lang_len + lang_key_len + 4)); - if (textp->key == NULL) - return(1); - png_debug2(2, "Allocated %lu bytes at %x in png_set_text", - (unsigned long)(png_uint_32) - (key_len + lang_len + lang_key_len + text_length + 4), - (int)textp->key); + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); - png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); + if (textp->key == NULL) + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_debug2(2, "Allocated %lu bytes at %p in png_set_text", + (unsigned long)(png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + textp->key); + + memcpy(textp->key, text_ptr[i].key, 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); + 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); + 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=NULL; textp->lang_key=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)); + + if (text_length != 0) + memcpy(textp->text, text_ptr[i].text, text_length); + *(textp->text + text_length) = '\0'; -#ifdef PNG_iTXt_SUPPORTED +# ifdef PNG_iTXt_SUPPORTED if (textp->compression > 0) { textp->text_length = 0; textp->itxt_length = text_length; } - else -#endif + else +# endif { textp->text_length = text_length; -#ifdef PNG_iTXt_SUPPORTED textp->itxt_length = 0; -#endif } + info_ptr->num_text++; png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } + return(0); } #endif #ifdef PNG_tIME_SUPPORTED void PNGAPI -png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) { png_debug1(1, "in %s storage function", "tIME"); - if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_tIME)) + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME) != 0) return; - png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); + if (mod_time->month == 0 || mod_time->month > 12 || + mod_time->day == 0 || mod_time->day > 31 || + mod_time->hour > 23 || mod_time->minute > 59 || + mod_time->second > 60) + { + png_warning(png_ptr, "Ignoring invalid time value"); + + return; + } + + info_ptr->mod_time = *mod_time; info_ptr->valid |= PNG_INFO_tIME; } #endif #ifdef PNG_tRNS_SUPPORTED void PNGAPI -png_set_tRNS(png_structp png_ptr, png_infop info_ptr, - png_bytep trans_alpha, int num_trans, png_color_16p trans_color) +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, + png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) { png_debug1(1, "in %s storage function", "tRNS"); if (png_ptr == NULL || info_ptr == NULL) + return; if (trans_alpha != NULL) @@ -825,35 +940,48 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr, /* It may not actually be necessary to set png_ptr->trans_alpha here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - png_ptr->trans_alpha = info_ptr->trans_alpha = (png_bytep)png_malloc(png_ptr, - (png_size_t)PNG_MAX_PALETTE_LENGTH); + png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - png_memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } if (trans_color != NULL) { - int sample_max = (1 << info_ptr->bit_depth); - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_color->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_color->red > sample_max || - (int)trans_color->green > sample_max || - (int)trans_color->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); - png_memcpy(&(info_ptr->trans_color), trans_color, - png_sizeof(png_color_16)); +#ifdef PNG_WARNINGS_SUPPORTED + if (info_ptr->bit_depth < 16) + { + int sample_max = (1 << info_ptr->bit_depth) - 1; + + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + } +#endif + + info_ptr->trans_color = *trans_color; + if (num_trans == 0) num_trans = 1; } info_ptr->num_trans = (png_uint_16)num_trans; + if (num_trans != 0) { info_ptr->valid |= PNG_INFO_tRNS; @@ -864,207 +992,475 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_sPLT_SUPPORTED void PNGAPI -png_set_sPLT(png_structp png_ptr, - png_infop info_ptr, png_sPLT_tp entries, int nentries) +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) /* * entries - array of png_sPLT_t structures * to be added to the list of palettes * in the info structure. + * * nentries - number of palette structures to be * added. */ { png_sPLT_tp np; - int i; - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) return; - np = (png_sPLT_tp)png_malloc_warn(png_ptr, - (info_ptr->splt_palettes_num + nentries) * - (png_size_t)png_sizeof(png_sPLT_t)); + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); + if (np == NULL) { - png_warning(png_ptr, "No memory for sPLT palettes"); + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + return; } - png_memcpy(np, info_ptr->splt_palettes, - info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes=NULL; + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; - for (i = 0; i < nentries; i++) + np += info_ptr->splt_palettes_num; + + do { - png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; - png_sPLT_tp from = entries + i; - png_uint_32 length; + png_size_t length; - length = png_strlen(from->name) + 1; - to->name = (png_charp)png_malloc_warn(png_ptr, (png_size_t)length); - if (to->name == NULL) + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ continue; } - png_memcpy(to->name, from->name, length); - to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, - (png_size_t)(from->nentries * png_sizeof(png_sPLT_entry))); - if (to->entries == NULL) + + np->depth = entries->depth; + + /* In the event of out-of-memory just return - there's no point keeping + * on trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); + + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong; this code must free it. png_malloc_array produces no + * warnings; use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - png_free(png_ptr, to->name); - to->name = NULL; - continue; + png_free(png_ptr, np->name); + np->name = NULL; + break; } - png_memcpy(to->entries, from->entries, - from->nentries * png_sizeof(png_sPLT_entry)); - to->nentries = from->nentries; - to->depth = from->depth; + + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + } + while (++entries, --nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* sPLT */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); + + /* New in 1.6.0; copy the location and check it. This is an API + * change; previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); } - info_ptr->splt_palettes = np; - info_ptr->splt_palettes_num += nentries; - info_ptr->valid |= PNG_INFO_sPLT; - info_ptr->free_me |= PNG_FREE_SPLT; -} -#endif /* PNG_sPLT_SUPPORTED */ + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; +} -#ifdef 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_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; - int i; - if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) return; - np = (png_unknown_chunkp)png_malloc_warn(png_ptr, - (png_size_t)((info_ptr->unknown_chunks_num + num_unknowns) * - png_sizeof(png_unknown_chunk))); + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); + if (np == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + return; } - png_memcpy(np, info_ptr->unknown_chunks, - info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; - for (i = 0; i < num_unknowns; i++) + np += info_ptr->unknown_chunks_num; + + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) { - png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; - png_unknown_chunkp from = unknowns + i; + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); - png_memcpy((png_charp)to->name, (png_charp)from->name, - png_sizeof(from->name)); - to->name[png_sizeof(to->name)-1] = '\0'; - to->size = from->size; - /* Note our location in the read or write sequence */ - to->location = (png_byte)(png_ptr->mode & 0xff); + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } - if (from->size == 0) - to->data=NULL; else { - to->data = (png_bytep)png_malloc_warn(png_ptr, - (png_size_t)from->size); - if (to->data == NULL) + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); + + if (np->data == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); - to->size = 0; + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; } - else - png_memcpy(to->data, from->data, from->size); + + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; } + + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); } - - info_ptr->unknown_chunks = np; - info_ptr->unknown_chunks_num += num_unknowns; - info_ptr->free_me |= PNG_FREE_UNKN; } + void PNGAPI -png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, - int chunk, int location) +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp 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 + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + location = PNG_AFTER_IDAT; + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } +} +#endif /* STORE_UNKNOWN_CHUNKS */ #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI -png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); 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; + return 0; + + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; + + return png_ptr->mng_features_permitted; } #endif #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -void PNGAPI -png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep - chunk_list, int num_chunks) +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) { - png_bytep new_list, p; - int i, old_num_chunks; + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; iflags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - if (keep == PNG_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, - (png_size_t) - (5*(num_chunks + old_num_chunks))); - if (png_ptr->chunk_list != NULL) + if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST) { - png_memcpy(new_list, png_ptr->chunk_list, - (png_size_t)(5*old_num_chunks)); - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list=NULL; + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + + return; + } + + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; + + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } + + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static PNG_CONST png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + chunk_list = chunks_to_ignore; + num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; + } + + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + + return; + } + + num_chunks = num_chunks_in; + } + + old_num_chunks = png_ptr->num_chunk_list; + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + + return; + } + + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep != 0) + { + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); + + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); + } + + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; ichunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); + + png_ptr->chunk_list = new_list; } - png_memcpy(new_list + 5*old_num_chunks, chunk_list, - (png_size_t)(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; - png_ptr->free_me |= PNG_FREE_LIST; } #endif #ifdef 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_set_read_user_chunk_fn(png_structrp 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"); @@ -1078,47 +1474,94 @@ png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) { png_debug1(1, "in %s storage function", "rows"); if (png_ptr == NULL || info_ptr == NULL) return; - if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + if (info_ptr->row_pointers != NULL && + (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) + + if (row_pointers != NULL) info_ptr->valid |= PNG_INFO_IDAT; } #endif void PNGAPI -png_set_compression_buffer_size(png_structp png_ptr, - png_size_t size) +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { if (png_ptr == NULL) return; - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf_size = 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; + + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); + +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif + +# ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + + return; + } + +#ifndef __COVERITY__ + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } +#endif + + if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif } void PNGAPI -png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) { - if (png_ptr && info_ptr) + if (png_ptr != NULL && info_ptr != NULL) info_ptr->valid &= ~mask; } - #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI -png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { /* Images with dimensions larger than these limits will be @@ -1127,41 +1570,71 @@ png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, */ if (png_ptr == NULL) return; + png_ptr->user_width_max = user_width_max; png_ptr->user_height_max = user_height_max; } /* This function was added to libpng 1.4.0 */ void PNGAPI -png_set_chunk_cache_max (png_structp png_ptr, - png_uint_32 user_chunk_cache_max) +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { - if (png_ptr) - png_ptr->user_chunk_cache_max = user_chunk_cache_max; + if (png_ptr != NULL) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ void PNGAPI -png_set_chunk_malloc_max (png_structp png_ptr, - png_alloc_size_t user_chunk_malloc_max) +png_set_chunk_malloc_max (png_structrp png_ptr, + png_alloc_size_t user_chunk_malloc_max) { - if (png_ptr) - png_ptr->user_chunk_malloc_max = - (png_size_t)user_chunk_malloc_max; + if (png_ptr != NULL) + png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#endif /* ?SET_USER_LIMITS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_set_benign_errors(png_structp png_ptr, int allowed) +png_set_benign_errors(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_benign_errors"); - if (allowed) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed != 0) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; + else - png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); } -#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* BENIGN_ERRORS */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeros + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ +void PNGAPI +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_check_for_invalid_index"); + + if (allowed > 0) + png_ptr->num_palette_max = 0; + + else + png_ptr->num_palette_max = -1; +} +#endif +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pngstruct.h b/thirdparty/libpng/pngstruct.h new file mode 100644 index 00000000..8420d099 --- /dev/null +++ b/thirdparty/libpng/pngstruct.h @@ -0,0 +1,488 @@ + +/* pngstruct.h - header file for PNG reference library + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 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 code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* 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. + */ + +#ifndef PNGSTRUCT_H +#define PNGSTRUCT_H +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information; + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ + png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED + png_error_ptr warning_fn; /* function for printing warnings */ +#endif + 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 */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#ifdef 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 */ +#ifdef 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 */ + + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ + +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ + + 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 */ +#endif +/* Added at libpng 1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif + + 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_size_t rowbytes; /* size of 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_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * This is a pointer into big_prev_row + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * This is a pointer into big_row_buf + */ +#ifdef PNG_WRITE_SUPPORTED + 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 */ +#endif + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + + 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 */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + + png_uint_16 num_trans; /* number of transparency values */ + 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: write only */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif + png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + png_byte background_gamma_type; + png_fixed_point background_gamma; + png_color_16 background; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* bKGD */ + +#ifdef 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 + +#ifdef PNG_READ_GAMMA_SUPPORTED + int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ + png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ + + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + 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_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +#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_alpha; /* alpha values for paletted files */ + png_color_16 trans_color; /* transparent color 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 a 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 */ + +#endif /* PROGRESSIVE_READ */ + +#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 + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup; /* lookup table for quantizing */ + png_bytep quantize_index; /* index translation for palette files */ +#endif + +#ifdef 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 + + /* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ +#ifdef PNG_TIME_RFC1123_SUPPORTED + char time_buffer[29]; /* String to hold RFC 1123 time text */ +#endif +#endif + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; + /* 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; + /* deleted in 1.5.5: 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) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type; +#endif + +/* New members added in libpng-1.2.0 */ + +/* 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 + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ + 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 */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; + + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max; + + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + */ + png_alloc_size_t user_chunk_malloc_max; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ + png_unknown_chunk unknown_chunk; +#endif + +/* New member added in libpng-1.2.26 */ + png_size_t old_big_row_buf_size; + +#ifdef PNG_READ_SUPPORTED +/* New member added in libpng-1.2.30 */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state; +#endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif +}; +#endif /* PNGSTRUCT_H */ diff --git a/thirdparty/libpng/pngtest.c b/thirdparty/libpng/pngtest.c deleted file mode 100644 index 6317751c..00000000 --- a/thirdparty/libpng/pngtest.c +++ /dev/null @@ -1,1632 +0,0 @@ - -/* pngtest.c - a simple test program to test libpng - * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 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 code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * 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 ..." - */ - -#include "png.h" -#include "pngpriv.h" - -# include -# include -# define FCLOSE(file) fclose(file) - -#ifndef PNG_STDIO_SUPPORTED - typedef FILE * png_FILE_p; -#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 -*/ - -#ifndef PNG_FLOATING_POINT_SUPPORTED -#undef PNGTEST_TIMING -#endif - -#ifdef PNGTEST_TIMING -static float t_start, t_stop, t_decode, t_encode, t_misc; -#include -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED -#define PNG_tIME_STRING_LENGTH 29 -static int tIME_chunk_present = 0; -static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; -#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 */ - -/* In case a system header (e.g., on AIX) defined jmpbuf */ -#ifdef jmpbuf -# undef jmpbuf -#endif - -/* 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 - -/* 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_UINT_31_MAX) - 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_UINT_31_MAX || pass > 7) - return; - fprintf(stdout, "w"); -} - - -#ifdef 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 - -#ifdef 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; - -#ifndef PNG_STDIO_SUPPORTED -/* 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 = 0; - png_voidp io_ptr; - - /* 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. - */ - io_ptr = png_get_io_ptr(png_ptr); - if (io_ptr != NULL) - { - check = fread(data, 1, length, (png_FILE_p)io_ptr); - } - - 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) -{ - png_size_t 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_get_io_ptr(png_ptr)); - if ((png_bytep)n_data == data) - { - check = fread(n_data, 1, length, io_ptr); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - err = fread(buf, 1, 1, io_ptr); - 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 */ - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -static void -pngtest_flush(png_structp png_ptr) -{ - /* Do nothing; fflush() is said to be just a waste of energy. */ - png_ptr = png_ptr; /* Stifle compiler warning */ -} -#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_size_t check; - png_FILE_p io_ptr; - io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr)); - - check = fwrite(data, 1, length, io_ptr); - 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_size_t 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) - { - check = fwrite(near_data, 1, length, io_ptr); - } - 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 */ - err = fwrite(buf, 1, written, io_ptr); - 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!)"; - char *test; - test = png_get_error_ptr(png_ptr); - if (test == NULL) - fprintf(STDERR, "%s: libpng warning: %s\n", name, message); - else - fprintf(STDERR, "%s: libpng warning: %s\n", test, 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_STDIO_SUPPORTED */ -/* END of code to validate stdio-free compilation */ - -/* START of code to validate memory allocation and deallocation */ -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - -/* 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_alloc_size_t 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; - -png_voidp png_debug_malloc - PNGARG((png_structp png_ptr, png_alloc_size_t size)); -void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); - -png_voidp -png_debug_malloc(png_structp png_ptr, png_alloc_size_t 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 (NULL); - - /* This calls the library allocator twice, once to get the requested - buffer and once to get a new free list entry. */ - { - /* Disable malloc_fn and free_fn */ - memory_infop pinfo; - png_set_mem_fn(png_ptr, NULL, NULL, NULL); - pinfo = (memory_infop)png_malloc(png_ptr, - png_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_malloc(png_ptr, size); - /* Restore malloc_fn and free_fn */ - png_set_mem_fn(png_ptr, - NULL, png_debug_malloc, png_debug_free); - if (size != 0 && pinfo->pointer == NULL) - { - current_allocation -= size; - total_allocation -= size; - png_error(png_ptr, - "out of memory in pngtest->png_debug_malloc"); - } - pinfo->next = pinformation; - pinformation = pinfo; - /* Make sure the caller isn't assuming zeroed memory. */ - png_memset(pinfo->pointer, 0xdd, pinfo->size); - if (verbose) - printf("png_malloc %lu bytes at %x\n", (unsigned long)size, - pinfo->pointer); - 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", (unsigned int)ptr); - break; - } - ppinfo = &pinfo->next; - } - } - - /* Finally free the data. */ - if (verbose) - printf("Freeing %x\n", ptr); - png_free_default(png_ptr, ptr); - ptr = NULL; -} -#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ -/* END of code to test memory allocation/deallocation */ - - -/* Demonstration of user chunk support of the sTER and vpAg chunks */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - -/* (sTER is a public chunk not yet known by libpng. vpAg is a private -chunk used in ImageMagick to store "virtual page" size). */ - -static png_uint_32 user_chunk_data[4]; - - /* 0: sTER mode + 1 - * 1: vpAg width - * 2: vpAg height - * 3: vpAg units - */ - -static int read_user_chunk_callback(png_struct *png_ptr, - png_unknown_chunkp chunk) -{ - png_uint_32 - *my_user_chunk_data; - - /* Return one of the following: - * return (-n); chunk had an error - * return (0); did not recognize - * return (n); success - * - * The unknown chunk structure contains the chunk data: - * png_byte name[5]; - * png_byte *data; - * png_size_t size; - * - * Note that libpng has already taken care of the CRC handling. - */ - - if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ - chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ - { - /* Found sTER chunk */ - if (chunk->size != 1) - return (-1); /* Error return */ - if (chunk->data[0] != 0 && chunk->data[0] != 1) - return (-1); /* Invalid mode */ - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - my_user_chunk_data[0]=chunk->data[0]+1; - return (1); - } - - if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ - chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ - return (0); /* Did not recognize */ - - /* Found ImageMagick vpAg chunk */ - - if (chunk->size != 9) - return (-1); /* Error return */ - - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - - my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); - my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); - my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; - - return (1); - -} -#endif -/* END of code to demonstrate user chunk support */ - -/* 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 - - char inbuf[256], outbuf[256]; - - row_buf = NULL; - - if ((fpin = fopen(inname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find input file %s\n", inname); - return (1); - } - - if ((fpout = fopen(outname, "wb")) == NULL) - { - fprintf(STDERR, "Could not open output file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - png_debug(0, "Allocating read and write structures"); -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - read_ptr = - png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL, NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - read_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); -#endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - user_chunk_data[0] = 0; - user_chunk_data[1] = 0; - user_chunk_data[2] = 0; - user_chunk_data[3] = 0; - png_set_read_user_chunk_fn(read_ptr, user_chunk_data, - read_user_chunk_callback); - -#endif -#ifdef PNG_WRITE_SUPPORTED -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - write_ptr = - png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL, NULL, png_debug_malloc, png_debug_free); -#else - write_ptr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); -#endif -#ifndef PNG_STDIO_SUPPORTED - 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"); - 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"); -#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_free(read_ptr, row_buf); - row_buf = NULL; - 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, png_sizeof(jmp_buf)); -#endif - -#ifdef PNG_WRITE_SUPPORTED - png_debug(0, "Setting jmpbuf for write struct"); -#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, png_sizeof(jmp_buf)); -#endif -#endif -#endif - - png_debug(0, "Initializing input and output streams"); -#ifdef PNG_STDIO_SUPPORTED - 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, -# ifdef 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); - } - -#ifdef 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 -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - zero_samples = 0; - png_set_write_user_transform_fn(write_ptr, count_zero_samples); -#endif - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_ALWAYS -# define PNG_HANDLE_CHUNK_ALWAYS 3 -# endif - png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, - NULL, 0); -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_IF_SAFE -# define PNG_HANDLE_CHUNK_IF_SAFE 2 -# endif - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, - NULL, 0); -#endif - - png_debug(0, "Reading info struct"); - png_read_info(read_ptr, read_info_ptr); - - png_debug(0, "Transferring info struct"); - { - 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, -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - color_type, interlace_type, compression_type, filter_type); -#else - color_type, PNG_INTERLACE_NONE, compression_type, filter_type); -#endif - } - } -#ifdef PNG_FIXED_POINT_SUPPORTED -#ifdef 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 -#ifdef 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 */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -#ifdef 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 -#ifdef 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 */ -#ifdef 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 -#ifdef 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); - } -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef 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", num_text); - png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); - } - } -#endif -#ifdef 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); -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* We have to use png_memcpy instead of "=" because the string - * pointed to by png_convert_to_rfc1123() gets free'ed before - * we use it. - */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#ifdef PNG_tRNS_SUPPORTED - { - png_bytep trans_alpha; - int num_trans; - png_color_16p trans_color; - - if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans, - &trans_color)) - { - int sample_max = (1 << bit_depth); - /* libpng doesn't reject a tRNS chunk with out-of-range samples */ - if (!((color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_color->gray > sample_max) || - (color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_color->red > sample_max || - (int)trans_color->green > sample_max || - (int)trans_color->blue > sample_max)))) - png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans, - trans_color); - } - } -#endif -#ifdef 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, "Writing info struct"); - -/* 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); - -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - if (user_chunk_data[0] != 0) - { - png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; - - unsigned char - ster_chunk_data[1]; - - if (verbose) - fprintf(STDERR, "\n stereo mode = %lu\n", - (unsigned long)(user_chunk_data[0] - 1)); - ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); - png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); - } - if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) - { - png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; - - unsigned char - vpag_chunk_data[9]; - - if (verbose) - fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", - (unsigned long)user_chunk_data[1], - (unsigned long)user_chunk_data[2], - (unsigned long)user_chunk_data[3]); - png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); - png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); - vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); - png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); - } - -#endif -#endif - -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(0, "Allocating row buffer..."); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); - png_debug1(0, "0x%08lx", (unsigned long)row_buf); -#endif /* SINGLE_ROWBUF_ALLOC */ - png_debug(0, "Writing row data"); - -#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", pass); - for (y = 0; y < height; y++) - { -#ifndef SINGLE_ROWBUF_ALLOC - png_debug2(0, "Allocating 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)", (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, 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)", pass, y); - png_free(read_ptr, row_buf); - row_buf = NULL; -#endif /* !SINGLE_ROWBUF_ALLOC */ - } - } - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); -#endif -#ifdef 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"); - - png_read_end(read_ptr, end_info_ptr); -#ifdef 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", num_text); - png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); - } - } -#endif -#ifdef 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); -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* We have to use png_memcpy instead of "=" because the string - pointed to by png_convert_to_rfc1123() gets free'ed before - we use it */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#ifdef 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, "\n Image width = %lu, height = %lu\n", - (unsigned long)iwidth, (unsigned long)iheight); - } -#endif - - png_debug(0, "Destroying data structs"); -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(1, "destroying row_buf for read_ptr"); - 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"); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_debug(1, "destroying write_end_info_ptr"); - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_debug(1, "destroying write_ptr, write_info_ptr"); - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - png_debug(0, "Destruction complete."); - - FCLOSE(fpin); - FCLOSE(fpout); - - png_debug(0, "Opening files for comparison"); - if ((fpin = fopen(inname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find file %s\n", inname); - return (1); - } - - if ((fpout = fopen(outname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - for (;;) - { - png_size_t num_in, num_out; - - num_in = fread(inbuf, 1, 1, fpin); - num_out = fread(outbuf, 1, 1, fpout); - - 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, "\n 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", - (unsigned long)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)=%ld, sizeof(png_info)=%ld\n", - (long)png_sizeof(png_struct), (long)png_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; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - int allocation_now = current_allocation; -#endif - for (i=2; isize, - (unsigned int) pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - 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; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - 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, "\n Testing %s:", inname); - kerror = test_one_file(inname, outname); - if (kerror == 0) - { - if (verbose == 1 || i == 2) - { -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - int k; -#endif -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - fprintf(STDERR, "\n PASS (%lu zero samples)\n", - (unsigned long)zero_samples); -#else - fprintf(STDERR, " PASS\n"); -#endif -#ifdef 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, (unsigned long)filters_used[k]); -#endif -#ifdef 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, "\n Testing %s:", inname); - fprintf(STDERR, " FAIL\n"); - ierror += kerror; - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - 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, " %lu bytes at %x\n", - (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - 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_4_4 your_png_h_is_not_version_1_4_4; diff --git a/thirdparty/libpng/pngtrans.c b/thirdparty/libpng/pngtrans.c index 741daf45..cd3a79b6 100644 --- a/thirdparty/libpng/pngtrans.c +++ b/thirdparty/libpng/pngtrans.c @@ -1,8 +1,8 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Last changed in libpng 1.4.2 [April 29, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,20 +11,20 @@ * and license in png.h */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #include "pngpriv.h" +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + #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_set_bgr(png_structrp png_ptr) { png_debug(1, "in png_set_bgr"); if (png_ptr == NULL) return; + png_ptr->transformations |= PNG_BGR; } #endif @@ -32,12 +32,13 @@ png_set_bgr(png_structp png_ptr) #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_set_swap(png_structrp png_ptr) { png_debug(1, "in png_set_swap"); if (png_ptr == NULL) return; + if (png_ptr->bit_depth == 16) png_ptr->transformations |= PNG_SWAP_BYTES; } @@ -46,16 +47,19 @@ png_set_swap(png_structp png_ptr) #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_set_packing(png_structrp png_ptr) { png_debug(1, "in png_set_packing"); if (png_ptr == NULL) return; + if (png_ptr->bit_depth < 8) { png_ptr->transformations |= PNG_PACK; - png_ptr->usr_bit_depth = 8; +# ifdef PNG_WRITE_SUPPORTED + png_ptr->usr_bit_depth = 8; +# endif } } #endif @@ -63,12 +67,13 @@ png_set_packing(png_structp png_ptr) #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_set_packswap(png_structrp png_ptr) { png_debug(1, "in png_set_packswap"); if (png_ptr == NULL) return; + if (png_ptr->bit_depth < 8) png_ptr->transformations |= PNG_PACKSWAP; } @@ -76,12 +81,13 @@ png_set_packswap(png_structp png_ptr) #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_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) { png_debug(1, "in png_set_shift"); if (png_ptr == NULL) return; + png_ptr->transformations |= PNG_SHIFT; png_ptr->shift = *true_bits; } @@ -90,11 +96,11 @@ png_set_shift(png_structp png_ptr, png_color_8p true_bits) #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) int PNGAPI -png_set_interlace_handling(png_structp png_ptr) +png_set_interlace_handling(png_structrp png_ptr) { png_debug(1, "in png_set_interlace handling"); - if (png_ptr && png_ptr->interlaced) + if (png_ptr != 0 && png_ptr->interlaced != 0) { png_ptr->transformations |= PNG_INTERLACE; return (7); @@ -111,48 +117,101 @@ png_set_interlace_handling(png_structp png_ptr) * that don't like bytes as parameters. */ void PNGAPI -png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_filler"); if (png_ptr == NULL) return; + + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ png_ptr->transformations |= PNG_FILLER; - png_ptr->filler = (png_uint_16)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_read_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; - } } /* Added to libpng-1.2.7 */ void PNGAPI -png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_add_alpha"); if (png_ptr == NULL) return; + png_set_filler(png_ptr, filler, filler_loc); - png_ptr->transformations |= PNG_ADD_ALPHA; + /* The above may fail to do anything. */ + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_ptr->transformations |= PNG_ADD_ALPHA; } #endif @@ -160,12 +219,13 @@ png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) void PNGAPI -png_set_swap_alpha(png_structp png_ptr) +png_set_swap_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_swap_alpha"); if (png_ptr == NULL) return; + png_ptr->transformations |= PNG_SWAP_ALPHA; } #endif @@ -173,24 +233,26 @@ png_set_swap_alpha(png_structp png_ptr) #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) void PNGAPI -png_set_invert_alpha(png_structp png_ptr) +png_set_invert_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_invert_alpha"); if (png_ptr == NULL) return; + 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_set_invert_mono(png_structrp png_ptr) { png_debug(1, "in png_set_invert_mono"); if (png_ptr == NULL) return; + png_ptr->transformations |= PNG_INVERT_MONO; } @@ -206,8 +268,8 @@ png_do_invert(png_row_infop row_info, png_bytep row) if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i++) { @@ -215,36 +277,41 @@ png_do_invert(png_row_infop row_info, png_bytep row) rp++; } } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && row_info->bit_depth == 8) { png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; - for (i = 0; i < istop; i+=2) + for (i = 0; i < istop; i += 2) { *rp = (png_byte)(~(*rp)); - rp+=2; + rp += 2; } } + +#ifdef PNG_16BIT_SUPPORTED else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && row_info->bit_depth == 16) { png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; - for (i = 0; i < istop; i+=4) + for (i = 0; i < istop; i += 4) { *rp = (png_byte)(~(*rp)); - *(rp+1) = (png_byte)(~(*(rp+1))); - rp+=4; + *(rp + 1) = (png_byte)(~(*(rp + 1))); + rp += 4; } } +#endif } #endif +#ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swaps byte order on 16 bit depth images */ void /* PRIVATE */ @@ -252,8 +319,7 @@ png_do_swap(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_swap"); - if ( - row_info->bit_depth == 16) + if (row_info->bit_depth == 16) { png_bytep rp = row; png_uint_32 i; @@ -261,13 +327,21 @@ png_do_swap(png_row_infop row_info, png_bytep row) for (i = 0; i < istop; i++, rp += 2) { +#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED + /* Feature added to libpng-1.6.11 for testing purposes, not + * enabled by default. + */ + *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); +#else png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; +#endif } } } #endif +#endif #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) static PNG_CONST png_byte onebppswaptable[256] = { @@ -381,19 +455,22 @@ png_do_packswap(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_packswap"); - if ( - row_info->bit_depth < 8) + if (row_info->bit_depth < 8) { - png_bytep rp, end, table; + png_bytep rp; + png_const_bytep end, table; end = row + row_info->rowbytes; if (row_info->bit_depth == 1) - table = (png_bytep)onebppswaptable; + table = onebppswaptable; + else if (row_info->bit_depth == 2) - table = (png_bytep)twobppswaptable; + table = twobppswaptable; + else if (row_info->bit_depth == 4) - table = (png_bytep)fourbppswaptable; + table = fourbppswaptable; + else return; @@ -401,162 +478,123 @@ png_do_packswap(png_row_infop row_info, png_bytep row) *rp = table[*rp]; } } -#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ +#endif /* PACKSWAP || WRITE_PACKSWAP */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -/* Remove filler or alpha byte(s) */ +/* Remove a channel - this used to be 'png_do_strip_filler' but it used a + * somewhat weird combination of flags to determine what to do. All the calls + * to png_do_strip_filler are changed in 1.5.2 to call this instead with the + * correct arguments. + * + * The routine isn't general - the channel must be the channel at the start or + * end (not in the middle) of each pixel. + */ void /* PRIVATE */ -png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) +png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { - png_debug(1, "in png_do_strip_filler"); + png_bytep sp = row; /* source pointer */ + png_bytep dp = row; /* destination pointer */ + png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ + /* At the start sp will point to the first byte to copy and dp to where + * it is copied to. ep always points just beyond the end of the row, so + * the loop simply copies (channels-1) channels until sp reaches ep. + * + * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. + * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. + */ + + /* GA, GX, XG cases */ + if (row_info->channels == 2) { - png_bytep sp=row; - png_bytep dp=row; - png_uint_32 row_width=row_info->width; - png_uint_32 i; - - if ((row_info->color_type == PNG_COLOR_TYPE_RGB || - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - (flags & PNG_FLAG_STRIP_ALPHA))) && - row_info->channels == 4) + if (row_info->bit_depth == 8) { - 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; - */ + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channel and, for sp, the filler */ + sp += 2, ++dp; - *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; - */ + /* For a 1 pixel wide image there is nothing to do */ + while (sp < ep) + *dp++ = *sp, sp += 2; - 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->pixel_depth = 8; } - else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || - (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - (flags & PNG_FLAG_STRIP_ALPHA))) && - row_info->channels == 2) + + else if (row_info->bit_depth == 16) { - 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; + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channel and, for sp, the filler */ + sp += 4, dp += 2; + + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp, sp += 3; + + row_info->pixel_depth = 16; } - if (flags & PNG_FLAG_STRIP_ALPHA) - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + + else + return; /* bad bit depth */ + + row_info->channels = 1; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_GRAY; } + + /* RGBA, RGBX, XRGB cases */ + else if (row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channels and, for sp, the filler */ + sp += 4, dp += 3; + + /* Note that the loop adds 3 to dp and 4 to sp each time. */ + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2; + + row_info->pixel_depth = 24; + } + + else if (row_info->bit_depth == 16) + { + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channels and, for sp, the filler */ + sp += 8, dp += 6; + + while (sp < ep) + { + /* Copy 6 bytes, skip 2 */ + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp, sp += 3; + } + + row_info->pixel_depth = 48; + } + + else + return; /* bad bit depth */ + + row_info->channels = 3; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_RGB; + } + + else + return; /* The filler channel has gone already */ + + /* Fix the rowbytes value. */ + row_info->rowbytes = dp-row; } #endif @@ -567,8 +605,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_bgr"); - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) @@ -585,6 +622,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) *(rp + 2) = save; } } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_bytep rp; @@ -598,6 +636,8 @@ png_do_bgr(png_row_infop row_info, png_bytep row) } } } + +#ifdef PNG_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { if (row_info->color_type == PNG_COLOR_TYPE_RGB) @@ -615,6 +655,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) *(rp + 5) = save; } } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_bytep rp; @@ -631,47 +672,178 @@ png_do_bgr(png_row_infop row_info, png_bytep row) } } } +#endif } } -#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ +#endif /* READ_BGR || WRITE_BGR */ + +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +/* Added at libpng-1.5.10 */ +void /* PRIVATE */ +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) +{ + if (png_ptr->num_palette < (1 << row_info->bit_depth) && + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ + { + /* Calculations moved outside switch in an attempt to stop different + * compiler warnings. 'padding' is in *bits* within the last byte, it is + * an 'int' because pixel_depth becomes an 'int' in the expression below, + * and this calculation is used because it avoids warnings that other + * forms produced on either GCC or MSVC. + */ + int padding = (-row_info->pixel_depth * row_info->width) & 7; + png_bytep rp = png_ptr->row_buf + row_info->rowbytes; + + switch (row_info->bit_depth) + { + case 1: + { + /* in this case, all bytes must be 0 so we don't need + * to unpack the pixels except for the rightmost one. + */ + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp >> padding != 0) + png_ptr->num_palette_max = 1; + padding = 0; + } + + break; + } + + case 2: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 2) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 6) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 4: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 8: + { + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp > png_ptr->num_palette_max) + png_ptr->num_palette_max = (int) *rp; + } + + break; + } + + default: + break; + } + } +} +#endif /* CHECK_FOR_INVALID_INDEX */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED void PNGAPI -png_set_user_transform_info(png_structp png_ptr, png_voidp +png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels) { png_debug(1, "in png_set_user_transform_info"); if (png_ptr == NULL) return; -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + 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. */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED png_voidp PNGAPI -png_get_user_transform_ptr(png_structp png_ptr) +png_get_user_transform_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - return ((png_voidp)png_ptr->user_transform_ptr); -#else - return (NULL); -#endif + + return png_ptr->user_transform_ptr; } -#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || - PNG_WRITE_USER_TRANSFORM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +png_uint_32 PNGAPI +png_get_current_row_number(png_const_structrp png_ptr) +{ + /* See the comments in png.h - this is the sub-image row when reading an + * interlaced image. + */ + if (png_ptr != NULL) + return png_ptr->row_number; + + return PNG_UINT_32_MAX; /* help the app not to fail silently */ +} + +png_byte PNGAPI +png_get_current_pass_number(png_const_structrp png_ptr) +{ + if (png_ptr != NULL) + return png_ptr->pass; + return 8; /* invalid */ +} +#endif /* USER_TRANSFORM_INFO */ +#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ +#endif /* READ || WRITE */ diff --git a/thirdparty/libpng/pngwio.c b/thirdparty/libpng/pngwio.c index 513a71a0..0a40948a 100644 --- a/thirdparty/libpng/pngwio.c +++ b/thirdparty/libpng/pngwio.c @@ -1,8 +1,8 @@ /* pngwio.c - functions for data output * - * Last changed in libpng 1.4.0 [January 3, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 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.) * @@ -18,11 +18,10 @@ * them at run time with png_set_write_fn(...). */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED #include "pngpriv.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 @@ -31,10 +30,13 @@ */ void /* PRIVATE */ -png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { + /* NOTE: write_data_fn must not change the buffer! */ if (png_ptr->write_data_fn != NULL ) - (*(png_ptr->write_data_fn))(png_ptr, data, length); + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); + else png_error(png_ptr, "Call to NULL write function"); } @@ -45,70 +47,19 @@ png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) * write_data function and use it at run time with png_set_write_fn(), rather * than changing the library. */ -#ifndef USE_FAR_KEYWORD -void PNGAPI +void PNGCBAPI png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - png_uint_32 check; + png_size_t check; if (png_ptr == NULL) return; + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); + 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) - -void PNGAPI -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; - - if (png_ptr == NULL) - return; - /* 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) - { - check = fwrite(near_data, 1, length, io_ptr); - } - 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 */ - err = fwrite(buf, 1, written, io_ptr); - 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 @@ -117,23 +68,25 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) */ #ifdef PNG_WRITE_FLUSH_SUPPORTED void /* PRIVATE */ -png_flush(png_structp png_ptr) +png_flush(png_structrp png_ptr) { if (png_ptr->output_flush_fn != NULL) (*(png_ptr->output_flush_fn))(png_ptr); } -#ifdef PNG_STDIO_SUPPORTED -void PNGAPI +# ifdef PNG_STDIO_SUPPORTED +void PNGCBAPI png_default_flush(png_structp png_ptr) { png_FILE_p io_ptr; + if (png_ptr == NULL) return; - io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); fflush(io_ptr); } -#endif +# endif #endif /* This function allows the application to supply new output functions for @@ -166,8 +119,8 @@ png_default_flush(png_structp png_ptr) * *FILE structure. */ 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_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) { if (png_ptr == NULL) return; @@ -185,57 +138,31 @@ png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED + 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 */ +# else + png_ptr->output_flush_fn = output_flush_fn; +# endif +#else + PNG_UNUSED(output_flush_fn) +#endif /* WRITE_FLUSH */ + +#ifdef PNG_READ_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"); + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); } +#endif } - -#ifdef USE_FAR_KEYWORD -#ifdef _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 */ +#endif /* WRITE */ diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c index 02520519..e3c20349 100644 --- a/thirdparty/libpng/pngwrite.c +++ b/thirdparty/libpng/pngwrite.c @@ -1,8 +1,8 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.4.0 [January 3, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,11 +11,65 @@ * and license in png.h */ -/* Get internal access to png.h */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED #include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num != 0) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if ((up->location & where) != 0) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* WRITE_UNKNOWN_CHUNKS */ /* 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, @@ -27,112 +81,114 @@ * them in png_write_end(), and compressing them. */ void PNGAPI -png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) { png_debug(1, "in png_write_info_before_PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) { /* Write PNG signature */ png_write_sig(png_ptr); + #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ - (png_ptr->mng_features_permitted)) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ + png_ptr->mng_features_permitted != 0) { png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); 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, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, #ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type); + info_ptr->interlace_type #else - 0); + 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. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and information + * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c + * for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects and + * error and calls png_error while the color space is being set, yet the + * application continues writing the PNG. So check the 'invalid' flag here + * too. */ -#ifdef 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); +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); # endif #endif - } -#endif -#ifdef PNG_WRITE_sRGB_SUPPORTED - if (info_ptr->valid & PNG_INFO_sRGB) - png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); -#endif -#ifdef 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 + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_iCCP) != 0) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sRGB) != 0) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_sRGB) != 0) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + #ifdef PNG_WRITE_sBIT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sBIT) + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif -#ifdef 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); + +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); # endif #endif - } -#endif + #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - 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 != PNG_HANDLE_CHUNK_NEVER && - up->location && !(up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - if (up->size == 0) - png_warning(png_ptr, "Writing zero-length unknown chunk"); - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); #endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } } void PNGAPI -png_write_info(png_structp png_ptr, png_infop info_ptr) +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) { #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; @@ -145,75 +201,68 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) png_write_info_before_PLTE(png_ptr, info_ptr); - if (info_ptr->valid & PNG_INFO_PLTE) + if ((info_ptr->valid & PNG_INFO_PLTE) != 0) 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_uint_32)info_ptr->num_palette); + + else if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) !=0) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED - if (info_ptr->valid & PNG_INFO_tRNS) + if ((info_ptr->valid & PNG_INFO_tRNS) !=0) { #ifdef 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) + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j; for (j = 0; j<(int)info_ptr->num_trans; j++) - info_ptr->trans_alpha[j] = (png_byte)(255 - info_ptr->trans_alpha[j]); + info_ptr->trans_alpha[j] = + (png_byte)(255 - info_ptr->trans_alpha[j]); } #endif png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), - info_ptr->num_trans, info_ptr->color_type); + info_ptr->num_trans, info_ptr->color_type); } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED - if (info_ptr->valid & PNG_INFO_bKGD) + if ((info_ptr->valid & PNG_INFO_bKGD) != 0) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif + #ifdef PNG_WRITE_hIST_SUPPORTED - if (info_ptr->valid & PNG_INFO_hIST) + if ((info_ptr->valid & PNG_INFO_hIST) != 0) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif + #ifdef PNG_WRITE_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if ((info_ptr->valid & PNG_INFO_oFFs) != 0) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, - info_ptr->offset_unit_type); -#endif -#ifdef 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); + info_ptr->offset_unit_type); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED + if ((info_ptr->valid & PNG_INFO_pCAL) != 0) + 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 -#ifdef PNG_sCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_sCAL) #ifdef PNG_WRITE_sCAL_SUPPORTED -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) - png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, - info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); -#else /* !FLOATING_POINT */ -#ifdef PNG_FIXED_POINT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sCAL) != 0) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); -#endif /* FIXED_POINT */ -#endif /* FLOATING_POINT */ -#else /* !WRITE_sCAL */ - png_warning(png_ptr, - "png_write_sCAL not supported; sCAL chunk not written"); -#endif /* WRITE_sCAL */ #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) + if ((info_ptr->valid & PNG_INFO_pHYs) != 0) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, - info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED - if (info_ptr->valid & PNG_INFO_tIME) + if ((info_ptr->valid & PNG_INFO_tIME) != 0) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; @@ -221,9 +270,9 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #endif /* tIME */ #ifdef 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); + if ((info_ptr->valid & PNG_INFO_sPLT) != 0) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ #ifdef PNG_WRITE_TEXT_SUPPORTED @@ -231,45 +280,49 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing header text chunk %d, type %d", i, - info_ptr->text[i].compression); + info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef 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); + /* 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); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else - png_warning(png_ptr, "Unable to write international text"); + png_warning(png_ptr, "Unable to write international text"); #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) { #ifdef 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); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #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) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, - 0); + info_ptr->text[i].text, + 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else @@ -281,27 +334,7 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #endif /* tEXt */ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - 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 != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); #endif } @@ -311,15 +344,21 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) * comments, I suggest writing them here, and compressing them. */ void PNGAPI -png_write_end(png_structp png_ptr, png_infop info_ptr) +png_write_end(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; - if (!(png_ptr->mode & PNG_HAVE_IDAT)) + + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "No IDATs written into file"); +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + if (png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); +#endif + /* See if user wants us to write information chunks */ if (info_ptr != NULL) { @@ -328,9 +367,10 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) #endif #ifdef 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)) + if ((info_ptr->valid & PNG_INFO_tIME) != 0 && + (png_ptr->mode & PNG_WROTE_tIME) == 0) png_write_tIME(png_ptr, &(info_ptr->mod_time)); + #endif #ifdef PNG_WRITE_TEXT_SUPPORTED /* Loop through comment chunks */ @@ -344,66 +384,50 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) #ifdef 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); + 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); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #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) { #ifdef 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); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #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) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0); + info_ptr->text[i].text, 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif - - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } } #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - 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 != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); #endif } @@ -411,6 +435,7 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) /* Write end of PNG file */ png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application @@ -426,9 +451,8 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) } #ifdef PNG_CONVERT_tIME_SUPPORTED -/* "tm" structure is not supported on WindowsCE */ void PNGAPI -png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) { png_debug(1, "in png_convert_from_struct_tm"); @@ -453,146 +477,79 @@ png_convert_from_time_t(png_timep ptime, time_t ttime) #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) +PNG_FUNCTION(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),PNG_ALLOCATED) { -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL)); +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + 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) +PNG_FUNCTION(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),PNG_ALLOCATED) { -#endif /* PNG_USER_MEM_SUPPORTED */ - volatile int png_cleanup_needed = 0; -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - 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"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif /* PNG_USER_MEM_SUPPORTED */ - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - encounter a png_error() will longjmp here. Since the jmpbuf is - then meaningless we abort instead of returning. */ -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ -#endif -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif - PNG_ABORT(); -#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); - - if (user_png_ver) + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + if (png_ptr != NULL) { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* WRITE_COMPRESSED_TEXT */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* In stable builds only warn if an application error can be completely + * handled. + */ + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; +#endif + + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +#endif + + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); } - 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')) - { -#ifdef PNG_STDIO_SUPPORTED - char msg[80]; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "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_warning(png_ptr, - "Incompatible libpng version in application and library"); - png_cleanup_needed = 1; - } - } - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - if (!png_cleanup_needed) - { - png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, - png_ptr->zbuf_size); - if (png_ptr->zbuf == NULL) - png_cleanup_needed = 1; - } - if (png_cleanup_needed) - { - /* Clean up PNG structure and deallocate any memory. */ - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = 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 - return (NULL); - } - - png_set_write_fn(png_ptr, NULL, NULL, NULL); - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, - 1, NULL, NULL); -#endif - - return (png_ptr); + return png_ptr; } @@ -602,8 +559,8 @@ png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, * "write" the image seven times. */ void PNGAPI -png_write_rows(png_structp png_ptr, png_bytepp row, - png_uint_32 num_rows) +png_write_rows(png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows) { png_uint_32 i; /* row counter */ png_bytepp rp; /* row pointer */ @@ -624,7 +581,7 @@ png_write_rows(png_structp png_ptr, png_bytepp row, * if you are writing an interlaced image. */ void PNGAPI -png_write_image(png_structp png_ptr, png_bytepp image) +png_write_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i; /* row index */ int pass, num_pass; /* pass variables */ @@ -654,53 +611,126 @@ png_write_image(png_structp png_ptr, png_bytepp image) } } +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Performs intrapixel differencing */ +static void +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + 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)); + *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + 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 = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)(red >> 8); + *(rp + 1) = (png_byte)red; + *(rp + 4) = (png_byte)(blue >> 8); + *(rp + 5) = (png_byte)blue; + } + } +#endif /* WRITE_16BIT */ + } +} +#endif /* MNG_FEATURES */ + /* Called by user to write a row of image data */ void PNGAPI -png_write_row(png_structp png_ptr, png_bytep row) +png_write_row(png_structrp png_ptr, png_const_bytep row) { + /* 1.5.6: moved from png_struct to be a local structure: */ + png_row_info row_info; + if (png_ptr == NULL) return; - png_debug2(1, "in png_write_row (row %ld, pass %d)", + png_debug2(1, "in png_write_row (row %u, pass %d)", 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) { /* Make sure we wrote the header info */ - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) png_error(png_ptr, - "png_write_info was never called before png_write_row"); + "png_write_info was never called before png_write_row"); /* 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) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) 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) + if ((png_ptr->transformations & PNG_FILLER) != 0) 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) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) 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) + if ((png_ptr->transformations & PNG_PACK) != 0) 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) + if ((png_ptr->transformations & PNG_SHIFT) != 0) 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) + if ((png_ptr->transformations & PNG_BGR) != 0) 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) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); #endif @@ -709,24 +739,27 @@ png_write_row(png_structp png_ptr, png_bytep row) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { case 0: - if (png_ptr->row_number & 0x07) + if ((png_ptr->row_number & 0x07) != 0) { png_write_finish_row(png_ptr); return; } break; + case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) { png_write_finish_row(png_ptr); return; } break; + case 2: if ((png_ptr->row_number & 0x07) != 4) { @@ -734,13 +767,15 @@ png_write_row(png_structp png_ptr, png_bytep row) return; } break; + case 3: - if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) { png_write_finish_row(png_ptr); return; } break; + case 4: if ((png_ptr->row_number & 0x03) != 2) { @@ -748,54 +783,55 @@ png_write_row(png_structp png_ptr, png_bytep row) return; } break; + case 5: - if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; } break; + case 6: - if (!(png_ptr->row_number & 0x01)) + if ((png_ptr->row_number & 0x01) == 0) { png_write_finish_row(png_ptr); return; } break; + + default: /* error: ignore it */ + 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); + row_info.color_type = png_ptr->color_type; + row_info.width = png_ptr->usr_width; + row_info.channels = png_ptr->usr_channels; + row_info.bit_depth = png_ptr->usr_bit_depth; + row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); - png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); - png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); - png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); - png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); - png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); + png_debug1(3, "row_info->color_type = %d", row_info.color_type); + png_debug1(3, "row_info->width = %u", row_info.width); + png_debug1(3, "row_info->channels = %d", row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); /* Copy user's row into buffer, leaving room for filter byte. */ - png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes); + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Handle interlacing */ if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE)) + (png_ptr->transformations & PNG_INTERLACE) != 0) { - png_do_write_interlace(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->pass); + png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); /* This should always get caught above, but still ... */ - if (!(png_ptr->row_info.width)) + if (row_info.width == 0) { png_write_finish_row(png_ptr); return; @@ -803,9 +839,18 @@ png_write_row(png_structp png_ptr, png_bytep row) } #endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ - if (png_ptr->transformations) - png_do_write_transformations(png_ptr); + if (png_ptr->transformations != 0) + png_do_write_transformations(png_ptr, &row_info); +#endif + + /* At this point the row_info pixel depth must match the 'transformed' depth, + * which is also the output depth. + */ + if (row_info.pixel_depth != png_ptr->pixel_depth || + row_info.pixel_depth != png_ptr->transformed_pixel_depth) + png_error(png_ptr, "internal write transform logic error"); #ifdef PNG_MNG_FEATURES_SUPPORTED /* Write filter_method 64 (intrapixel differencing) only if @@ -817,16 +862,24 @@ png_write_row(png_structp png_ptr, png_bytep row) * 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)) + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ - png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); } #endif +/* Added at libpng-1.5.10 */ +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Check for out-of-range palette index */ + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, &row_info); +#endif + /* Find a filter if necessary, filter the row and write it out. */ - png_write_find_filter(png_ptr, &(png_ptr->row_info)); + png_write_find_filter(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); @@ -835,222 +888,127 @@ png_write_row(png_structp png_ptr, png_bytep row) #ifdef 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_set_flush(png_structrp png_ptr, int nrows) { png_debug(1, "in png_set_flush"); if (png_ptr == NULL) return; + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); } /* Flush the current output buffers now */ void PNGAPI -png_write_flush(png_structp png_ptr) +png_write_flush(png_structrp png_ptr) { - int wrote_IDAT; - png_debug(1, "in png_write_flush"); if (png_ptr == NULL) return; + /* 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_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); png_ptr->flush_rows = 0; png_flush(png_ptr); } -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ +#endif /* WRITE_FLUSH */ -/* Free all memory used by the write */ -void PNGAPI -png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ +#endif + +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_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"); - - if (png_ptr_ptr != NULL) - { - png_ptr = *png_ptr_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr != NULL) - { - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; - } -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - if (png_ptr != NULL) - { - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - 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 = 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 = 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"); /* Free any memory zlib uses */ - deflateEnd(&png_ptr->zstream); + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ - png_free(png_ptr, png_ptr->zbuf); + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; #ifdef PNG_WRITE_FILTER_SUPPORTED 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); -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_free(png_ptr, png_ptr->time_buffer); + png_ptr->prev_row = NULL; + png_ptr->sub_row = NULL; + png_ptr->up_row = NULL; + png_ptr->avg_row = NULL; + png_ptr->paeth_row = NULL; #endif #ifdef 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); + /* Use this to save a little code space, it doesn't free the filter_costs */ + png_reset_filter_heuristics(png_ptr); png_free(png_ptr, png_ptr->filter_costs); png_free(png_ptr, png_ptr->inv_filter_costs); + png_ptr->filter_costs = NULL; + png_ptr->inv_filter_costs = NULL; #endif -#ifdef PNG_SETJMP_SUPPORTED - /* Reset structure */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; #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 + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} - png_memset(png_ptr, 0, png_sizeof(png_struct)); +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_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 + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } } /* 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_set_filter(png_structrp png_ptr, int method, int filters) { png_debug(1, "in png_set_filter"); if (png_ptr == NULL) return; + #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (method == PNG_INTRAPIXEL_DIFFERENCING)) - method = PNG_FILTER_TYPE_BASE; + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; + #endif if (method == PNG_FILTER_TYPE_BASE) { @@ -1059,23 +1017,31 @@ png_set_filter(png_structp png_ptr, int method, int filters) #ifdef PNG_WRITE_FILTER_SUPPORTED case 5: case 6: - case 7: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); + /* FALL THROUGH */ +#endif /* WRITE_FILTER */ case PNG_FILTER_VALUE_NONE: - png_ptr->do_filter = PNG_FILTER_NONE; break; + png_ptr->do_filter = PNG_FILTER_NONE; break; + #ifdef PNG_WRITE_FILTER_SUPPORTED case PNG_FILTER_VALUE_SUB: - png_ptr->do_filter = PNG_FILTER_SUB; break; + png_ptr->do_filter = PNG_FILTER_SUB; break; + case PNG_FILTER_VALUE_UP: - png_ptr->do_filter = PNG_FILTER_UP; break; + png_ptr->do_filter = PNG_FILTER_UP; break; + case PNG_FILTER_VALUE_AVG: - png_ptr->do_filter = PNG_FILTER_AVG; break; + 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; + png_ptr->do_filter = PNG_FILTER_PAETH; break; + + default: + png_ptr->do_filter = (png_byte)filters; break; #else - default: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + default: + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ } /* If we have allocated the row_buf, this means we have already started @@ -1084,50 +1050,57 @@ png_set_filter(png_structp png_ptr, int method, int filters) * 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. + * it should start out with all of the filters, and then remove them + * or add them back after the start of compression. */ if (png_ptr->row_buf != NULL) { #ifdef PNG_WRITE_FILTER_SUPPORTED - if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_SUB) != 0 && + png_ptr->sub_row == NULL) { png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); + (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->do_filter & PNG_FILTER_UP) != 0 && + 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; + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_UP); } + else { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); + (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->do_filter & PNG_FILTER_AVG) != 0 && + 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; + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_AVG); } + else { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); + (png_ptr->rowbytes + 1)); png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } } - if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0 && png_ptr->paeth_row == NULL) { if (png_ptr->prev_row == NULL) @@ -1135,16 +1108,17 @@ png_set_filter(png_structp png_ptr, int method, int filters) 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->rowbytes + 1)); png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } if (png_ptr->do_filter == PNG_NO_FILTERS) -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ png_ptr->do_filter = PNG_FILTER_NONE; } } @@ -1160,209 +1134,423 @@ png_set_filter(png_structp png_ptr, int method, int filters) * better compression. */ #ifdef 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) +/* Convenience reset API. */ +static void +png_reset_filter_heuristics(png_structrp png_ptr) { - int i; + /* Clear out any old values in the 'weights' - this must be done because if + * the app calls set_filter_heuristics multiple times with different + * 'num_weights' values we would otherwise potentially have wrong sized + * arrays. + */ + png_ptr->num_prev_filters = 0; + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + if (png_ptr->prev_filters != NULL) + { + png_bytep old = png_ptr->prev_filters; + png_ptr->prev_filters = NULL; + png_free(png_ptr, old); + } + if (png_ptr->filter_weights != NULL) + { + png_uint_16p old = png_ptr->filter_weights; + png_ptr->filter_weights = NULL; + png_free(png_ptr, old); + } - png_debug(1, "in png_set_filter_heuristics"); + if (png_ptr->inv_filter_weights != NULL) + { + png_uint_16p old = png_ptr->inv_filter_weights; + png_ptr->inv_filter_weights = NULL; + png_free(png_ptr, old); + } + /* Leave the filter_costs - this array is fixed size. */ +} + +static int +png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights) +{ if (png_ptr == NULL) - return; - if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) - { - png_warning(png_ptr, "Unknown filter heuristic method"); - return; - } + return 0; - if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) - { - heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; - } + /* Clear out the arrays */ + png_reset_filter_heuristics(png_ptr); - if (num_weights < 0 || filter_weights == NULL || - heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + /* Check arguments; the 'reset' function makes the correct settings for the + * unweighted case, but we must handle the weight case by initializing the + * arrays for the caller. + */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { - num_weights = 0; - } + int i; - 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) + if (num_weights > 0) { png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_byte) * num_weights)); + (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)(png_sizeof(png_uint_16) * num_weights)); + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + (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; } + + /* Safe to set this now */ + png_ptr->num_prev_filters = (png_byte)num_weights; } - for (i = 0; i < num_weights; i++) + /* 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) { - 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); - } + 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)); } - } - - /* 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)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); - - png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_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++) + /* All the arrays are inited, safe to set this: */ + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED; + + /* Return the 'ok' code. */ + return 1; + } + else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) { - if (filter_costs == NULL || filter_costs[i] < 0.0) + return 1; + } + else + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return 0; + } +} + +/* Provide floating and fixed point APIs */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs) +{ + png_debug(1, "in png_set_filter_heuristics"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) { - png_ptr->inv_filter_costs[i] = - png_ptr->filter_costs[i] = PNG_COST_FACTOR; + 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)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5); + + png_ptr->filter_weights[i] = + (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5); + } } - else if (filter_costs[i] >= 1.0) + + /* 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[i] >= 1.0) { png_ptr->inv_filter_costs[i] = - (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); + (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5); + png_ptr->filter_costs[i] = - (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); + (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5); } } } -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ +#endif /* FLOATING_POINT */ +#ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI -png_set_compression_level(png_structp png_ptr, int level) +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs) +{ + png_debug(1, "in png_set_filter_heuristics_fixed"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] <= 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) + ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1); + + png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR* + PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]); + } + } + + /* 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[i] >= PNG_FP_1) + { + png_uint_32 tmp; + + /* Use a 32 bit unsigned temporary here because otherwise the + * intermediate value will be a 32 bit *signed* integer (ANSI rules) + * and this will get the wrong answer on division. + */ + tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2); + tmp /= filter_costs[i]; + + png_ptr->inv_filter_costs[i] = (png_uint_16)tmp; + + tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF; + tmp /= PNG_FP_1; + + png_ptr->filter_costs[i] = (png_uint_16)tmp; + } + } +} +#endif /* FIXED_POINT */ +#endif /* WRITE_WEIGHTED_FILTER */ + +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +void PNGAPI +png_set_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_compression_level"); if (png_ptr == NULL) return; - 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_set_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_compression_mem_level"); if (png_ptr == NULL) return; - 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_set_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_compression_strategy"); if (png_ptr == NULL) return; + + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; } +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ void PNGAPI -png_set_compression_window_bits(png_structp png_ptr, int window_bits) +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; + + /* Prior to 1.6.0 this would warn but then set the window_bits value. This + * meant that negative window bits values could be selected that would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ if (window_bits > 15) + { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + 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; + window_bits = 8; + } + png_ptr->zlib_window_bits = window_bits; } void PNGAPI -png_set_compression_method(png_structp png_ptr, int method) +png_set_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_compression_method"); if (png_ptr == NULL) return; + + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ 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; } +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +/* The following were added to libpng-1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +void PNGAPI +png_set_text_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_text_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_level = level; +} void PNGAPI -png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_text_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_mem_level = mem_level; +} + +void PNGAPI +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_text_compression_strategy"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; + + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_text_window_bits = window_bits; +} + +void PNGAPI +png_set_text_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_text_compression_method"); + + if (png_ptr == NULL) + return; + + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_text_method = method; +} +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +/* end of API added to libpng-1.5.4 */ + +void PNGAPI +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) +{ + if (png_ptr == NULL) + return; + png_ptr->write_row_fn = write_row_fn; } #ifdef 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_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + write_user_transform_fn) { png_debug(1, "in png_set_write_user_transform_fn"); if (png_ptr == NULL) return; + png_ptr->transformations |= PNG_USER_TRANSFORM; png_ptr->write_user_transform_fn = write_user_transform_fn; } @@ -1371,87 +1559,901 @@ png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_write_png(png_structp png_ptr, png_infop info_ptr, - int transforms, voidp params) +png_write_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, voidp params) { if (png_ptr == NULL || info_ptr == NULL) return; + if ((info_ptr->valid & PNG_INFO_IDAT) == 0) + { + png_app_error(png_ptr, "no rows for png_write_image to write"); + return; + } + /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ -#ifdef PNG_WRITE_INVERT_SUPPORTED /* Invert monochrome pixels */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_WRITE_INVERT_SUPPORTED png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif -#ifdef 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); + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif -#ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_WRITE_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED /* Swap location of alpha bytes from ARGB to RGBA */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif + /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into + * RGB, note that the code expects the input color type to be G or RGB; no + * alpha channel. + */ + if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) + { #ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ - if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -#endif + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) + { + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_app_error(png_ptr, + "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); + + /* Continue if ignored - this is the pre-1.6.10 behavior */ + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } + + else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); +#endif + } -#ifdef PNG_WRITE_BGR_SUPPORTED /* Flip BGR pixels to RGB */ - if (transforms & PNG_TRANSFORM_BGR) + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_WRITE_BGR_SUPPORTED png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif -#ifdef PNG_WRITE_SWAP_SUPPORTED /* Swap bytes of 16-bit files to most significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_WRITE_SWAP_SUPPORTED png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED /* Swap bits of 1, 2, 4 bit packed pixel formats */ - if (transforms & PNG_TRANSFORM_PACKSWAP) + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ - if (info_ptr->valid & PNG_INFO_IDAT) - png_write_image(png_ptr, info_ptr->row_pointers); + 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); - transforms = transforms; /* Quiet compiler warnings */ - params = params; + PNG_UNUSED(params) } #endif -#endif /* PNG_WRITE_SUPPORTED */ + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + const png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_bytep row_end; + int aindex; + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + const png_imagep image = display->image; + const void *cmap = display->colormap; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ + defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + /* The following four ints are actually booleans */ + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); + int write_16bit = linear && !colormap && (display->convert_to_8bit == 0); + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required. */ + if (display->row_stride == 0) + display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + /* Set the required transforms then write the rows in the correct order. */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit != 0) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16 bit files. + */ + if (write_16bit != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap != 0 && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED + png_set_compression_level(png_ptr, 3); +#endif + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear != 0 && alpha != 0 ) || + (colormap == 0 && display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit != 0) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (result == 0) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + while (y-- > 0) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given (FILE*). */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap) != 0) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* WRITE */ diff --git a/thirdparty/libpng/pngwtran.c b/thirdparty/libpng/pngwtran.c index 070caa54..db82e27b 100644 --- a/thirdparty/libpng/pngwtran.c +++ b/thirdparty/libpng/pngwtran.c @@ -1,8 +1,8 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,84 +11,17 @@ * and license in png.h */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED #include "pngpriv.h" -/* 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"); - - if (png_ptr == NULL) - return; - -#ifdef 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 -#ifdef 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 -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef 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 -#ifdef PNG_WRITE_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef 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 -#ifdef 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 -#ifdef 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 -#ifdef PNG_WRITE_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#ifdef PNG_WRITE_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -} +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED #ifdef 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 */ +static void png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { png_debug(1, "in png_do_pack"); @@ -114,9 +47,12 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { if (*sp != 0) v |= mask; + sp++; + if (mask > 1) mask >>= 1; + else { mask = 0x80; @@ -125,10 +61,13 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) v = 0; } } + if (mask != 0x80) *dp = (png_byte)v; + break; } + case 2: { png_bytep sp, dp; @@ -140,12 +79,14 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) 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; @@ -153,14 +94,19 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) dp++; v = 0; } + else shift -= 2; + sp++; } + if (shift != 6) *dp = (png_byte)v; + break; } + case 4: { png_bytep sp, dp; @@ -172,6 +118,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) dp = row; shift = 4; v = 0; + for (i = 0; i < row_width; i++) { png_byte value; @@ -186,20 +133,27 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) dp++; v = 0; } + else shift -= 4; sp++; } + if (shift != 4) *dp = (png_byte)v; + break; } + + default: + break; } + row_info->bit_depth = (png_byte)bit_depth; row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); + row_info->width); } } #endif @@ -212,36 +166,40 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) * 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) +static void +png_do_shift(png_row_infop row_info, png_bytep row, + png_const_color_8p bit_depth) { png_debug(1, "in png_do_shift"); - if ( - row_info->color_type != PNG_COLOR_TYPE_PALETTE) + if (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) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { 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) + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_dec[channels] = bit_depth->alpha; @@ -252,33 +210,40 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) 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; + png_size_t i; + unsigned int mask; + png_size_t 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; + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; + else - *bp |= (png_byte)((v >> (-j)) & mask); + out |= (v >> (-j)) & mask; } + + *bp = (png_byte)(out & 0xff); } } + else if (row_info->bit_depth == 8) { png_bytep bp = row; @@ -288,21 +253,26 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) for (i = 0; i < istop; i++, bp++) { - png_uint_16 v; + const unsigned int c = i%channels; int j; - int c = (int)(i%channels); + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; + else - *bp |= (png_byte)((v >> (-j)) & 0xff); + out |= v >> (-j); } + + *bp = (png_byte)(out & 0xff); } } + else { png_bytep bp; @@ -311,20 +281,22 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) for (bp = row, i = 0; i < istop; i++) { - int c = (int)(i%channels); - png_uint_16 value, v; + const unsigned int c = i%channels; int j; + unsigned int value, v; - v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + v = png_get_uint_16(bp); 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); + value |= v << j; + else - value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + value |= v >> (-j); } - *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)((value >> 8) & 0xff); *bp++ = (png_byte)(value & 0xff); } } @@ -333,7 +305,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_swap_alpha"); @@ -341,12 +313,13 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - /* This converts from ARGB to RGBA */ if (row_info->bit_depth == 8) { + /* This converts from ARGB to RGBA */ 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++); @@ -356,9 +329,11 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save; } } - /* This converts from AARRGGBB to RRGGBBAA */ + +#ifdef PNG_WRITE_16BIT_SUPPORTED else { + /* This converts from AARRGGBB to RRGGBBAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -378,12 +353,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } +#endif /* WRITE_16BIT */ } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - /* This converts from AG to GA */ if (row_info->bit_depth == 8) { + /* This converts from AG to GA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -395,9 +372,11 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save; } } - /* This converts from AAGG to GGAA */ + +#ifdef PNG_WRITE_16BIT_SUPPORTED else { + /* This converts from AAGG to GGAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -413,13 +392,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } +#endif /* WRITE_16BIT */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_invert_alpha"); @@ -427,12 +407,13 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - /* This inverts the alpha channel in RGBA */ if (row_info->bit_depth == 8) { + /* This inverts the alpha channel in RGBA */ 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++) { /* Does nothing @@ -444,9 +425,11 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } - /* This inverts the alpha channel in RRGGBBAA */ + +#ifdef PNG_WRITE_16BIT_SUPPORTED else { + /* This inverts the alpha channel in RRGGBBAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -466,12 +449,14 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } +#endif /* WRITE_16BIT */ } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - /* This inverts the alpha channel in GA */ if (row_info->bit_depth == 8) { + /* This inverts the alpha channel in GA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -482,9 +467,11 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } - /* This inverts the alpha channel in GGAA */ + +#ifdef PNG_WRITE_16BIT_SUPPORTED else { + /* This inverts the alpha channel in GGAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -500,67 +487,88 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } +#endif /* WRITE_16BIT */ } } } #endif -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ void /* PRIVATE */ -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_write_intrapixel"); + png_debug(1, "in png_do_write_transformations"); - if ( - (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 (png_ptr == NULL) + return; - 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; +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t 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 - 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; +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif - 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; +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif - 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 = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(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); - } - } - } +#ifdef PNG_WRITE_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED +# ifdef PNG_16BIT_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +# endif +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE_TRANSFORMS */ +#endif /* WRITE */ diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c index 19feb1d9..b289671d 100644 --- a/thirdparty/libpng/pngwutil.c +++ b/thirdparty/libpng/pngwutil.c @@ -1,8 +1,8 @@ /* pngwutil.c - utilities to write a PNG file * - * Last changed in libpng 1.4.1 [February 25, 2010] - * Copyright (c) 1998-2010 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 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.) * @@ -11,11 +11,11 @@ * and license in png.h */ -#define PNG_NO_PEDANTIC_WARNINGS -#include "png.h" -#ifdef PNG_WRITE_SUPPORTED #include "pngpriv.h" +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_INT_FUNCTIONS_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. @@ -23,27 +23,12 @@ void PNGAPI 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); + buf[0] = (png_byte)(i >> 24); + buf[1] = (png_byte)(i >> 16); + buf[2] = (png_byte)(i >> 8); + buf[3] = (png_byte)(i ); } -#ifdef PNG_SAVE_INT_32_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 PNGAPI -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. @@ -51,9 +36,10 @@ png_save_int_32(png_bytep buf, png_int_32 i) void PNGAPI png_save_uint_16(png_bytep buf, unsigned int i) { - buf[0] = (png_byte)((i >> 8) & 0xff); - buf[1] = (png_byte)(i & 0xff); + buf[0] = (png_byte)(i >> 8); + buf[1] = (png_byte)(i ); } +#endif /* Simple function to write the signature. If we have already written * the magic bytes of the signature, or more likely, the PNG stream is @@ -62,7 +48,7 @@ png_save_uint_16(png_bytep buf, unsigned int i) * bytes have already been written. */ void PNGAPI -png_write_sig(png_structp png_ptr) +png_write_sig(png_structrp png_ptr) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; @@ -74,42 +60,25 @@ png_write_sig(png_structp png_ptr) /* 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; } -/* 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) -{ - if (png_ptr == NULL) - return; - png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); - png_write_chunk_data(png_ptr, data, (png_size_t)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) +static void +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, + png_uint_32 length) { png_byte buf[8]; - png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, - (unsigned long)length); +#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) + PNG_CSTRING_FROM_CHUNK(buf, chunk_name); + png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); +#endif if (png_ptr == NULL) return; @@ -123,13 +92,16 @@ png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, /* Write the length and the chunk name */ png_save_uint_32(buf, length); - png_memcpy(buf + 4, chunk_name, 4); - png_write_data(png_ptr, buf, (png_size_t)8); + png_save_uint_32(buf + 4, chunk_name); + png_write_data(png_ptr, buf, 8); + /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, chunk_name, 4); + png_ptr->chunk_name = chunk_name; + /* Reset the crc and run it over the chunk name */ png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, chunk_name, 4); + + png_calculate_crc(png_ptr, buf + 4, 4); #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that chunk data will (possibly) be written. @@ -139,30 +111,40 @@ png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, #endif } -/* Write the data of a PNG chunk started with png_write_chunk_start(). +void PNGAPI +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, + png_uint_32 length) +{ + png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); +} + +/* Write the data of a PNG chunk started with png_write_chunk_header(). * 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(). + * given to png_write_chunk_header(). */ void PNGAPI -png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, + png_size_t length) { /* Write the data, and run the CRC over it */ if (png_ptr == NULL) return; + if (data != NULL && length > 0) { png_write_data(png_ptr, data, length); + /* Update the CRC after writing the data, - * in case that the user I/O routine alters it. + * in case the user I/O routine alters it. */ png_calculate_crc(png_ptr, data, length); } } -/* Finish a chunk started with png_write_chunk_start(). */ +/* Finish a chunk started with png_write_chunk_header(). */ void PNGAPI -png_write_chunk_end(png_structp png_ptr) +png_write_chunk_end(png_structrp png_ptr) { png_byte buf[4]; @@ -181,246 +163,601 @@ png_write_chunk_end(png_structp png_ptr) png_write_data(png_ptr, buf, (png_size_t)4); } -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* 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. + */ +static void +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, + png_const_bytep data, png_size_t length) +{ + if (png_ptr == NULL) + return; + + /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maximum"); + + png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* This is the API that calls the internal function above. */ +void PNGAPI +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, + png_const_bytep data, png_size_t length) +{ + png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, + length); +} + +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) +{ + /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) + { + if (png_ptr->interlaced != 0) + { + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; + + for (cb_base=0, pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); + } + + return cb_base; + } + + else + return (png_ptr->rowbytes+1) * h; + } + + else + return 0xffffffffU; +} + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ +static void +optimize_cmf(png_bytep data, png_alloc_size_t data_size) +{ + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ + { + unsigned int tmp; + + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; + } + } + } +} +#endif /* WRITE_OPTIMIZE_CMF */ + +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +#endif +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_warning(png_ptr, msg); + + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } + + png_ptr->zowner = 0; +#else + png_error(png_ptr, msg); +#endif + } + + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ + + if (owner == png_IDAT) + { + if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + strategy = png_ptr->zlib_strategy; + + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; + + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +#else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +#endif + } + + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; + } + } + + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); + + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + /* Now initialize if required, setting the new parameters, otherwise just + * to a simple reset to the previous parameters. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + ret = deflateReset(&png_ptr->zstream); + + else + { + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } +} + +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; + + if (list != NULL) + { + *listp = NULL; + + do + { + png_compression_bufferp next = list->next; + + png_free(png_ptr, list); + list = next; + } + while (list != NULL); + } +} + +#ifdef PNG_WRITE_COMPRESSED_TEXT_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. + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) */ - 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 */ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of 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) +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) +{ + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} + +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) { int ret; - comp->num_output_ptr = 0; - comp->max_output_ptr = 0; - comp->output_ptr = NULL; - comp->input = NULL; - comp->input_len = 0; - - /* 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) - { -#ifdef PNG_STDIO_SUPPORTED - char msg[50]; - png_snprintf(msg, 50, "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. + /* To find the length of the output it is necessary to first compress the + * input. The result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. * - * 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). + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. */ + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); - /* 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; + if (ret != Z_OK) + return ret; - /* This is the same compression loop as in png_write_row() */ - do + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. + */ { - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - if (ret != Z_OK) + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; + + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); + + output_len = png_ptr->zstream.avail_out; + + do { - /* 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)) - { - /* Make sure the output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) + uInt avail_in = ZLIB_IO_MAX; + + if (avail_in > input_len) + avail_in = (uInt)input_len; + + input_len -= avail_in; + + png_ptr->zstream.avail_in = avail_in; + + if (png_ptr->zstream.avail_out == 0) { - int old_max; + png_compression_buffer *next; - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) { - png_charpp old_ptr; - - old_ptr = comp->output_ptr; - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charpp))); - png_memcpy(comp->output_ptr, old_ptr, old_max - * png_sizeof(png_charp)); - png_free(png_ptr, old_ptr); + ret = Z_MEM_ERROR; + break; } - else - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charp))); - } - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_charp)png_malloc(png_ptr, - (png_alloc_size_t)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) + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) { - int old_max; + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) + if (next == 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_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); - png_memcpy(comp->output_ptr, old_ptr, - old_max * png_sizeof(png_charp)); - png_free(png_ptr, old_ptr); + ret = Z_MEM_ERROR; + break; } - else - comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); + + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; } - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_charp)png_malloc(png_ptr, - (png_alloc_size_t)png_ptr->zbuf_size); - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - comp->num_output_ptr++; + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; - /* and reset the buffer pointers */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; + /* Move 'end' to the next buffer pointer. */ + end = &next->next; } + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ } - else if (ret != Z_STREAM_END) + while (ret == Z_OK); + + /* There may be some space left in the last output buffer. This needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) { - /* 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"); + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_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; + else + png_zstream_error(png_ptr, ret); - return((int)text_len); + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; + + /* The only success case is Z_STREAM_END, input_len must be 0; if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) + { +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); +#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; + } + + else + return ret; + } } /* Ship the compressed text out via chunk writes */ -static void /* PRIVATE */ -png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { - int i; + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; - /* Handle the no-compression case */ - if (comp->input) + for (;;) { - png_write_chunk_data(png_ptr, (png_bytep)comp->input, - (png_size_t)comp->input_len); - return; + if (avail > output_len) + avail = output_len; + + png_write_chunk_data(png_ptr, output, avail); + + output_len -= avail; + + if (output_len == 0 || next == NULL) + break; + + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; } - /* 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_size_t)png_ptr->zbuf_size); - png_free(png_ptr, comp->output_ptr[i]); - } - if (comp->max_output_ptr != 0) - png_free(png_ptr, comp->output_ptr); - /* 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_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - - /* Reset zlib for another zTXt/iTXt or image data */ - deflateReset(&png_ptr->zstream); - png_ptr->zstream.data_type = Z_BINARY; + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); } -#endif +#endif /* WRITE_COMPRESSED_TEXT */ + +#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' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +static png_uint_32 +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) + { + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)*key++; + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; + + else if (space == 0) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; + } + + else if (bad_character == 0) + bad_character = ch; /* just skip it, record the first error */ + } + + if (key_len > 0 && space != 0) /* trailing space */ + { + --key_len, --new_key; + if (bad_character == 0) + bad_character = 32; + } + + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + +#ifdef PNG_WARNINGS_SUPPORTED + /* Try to only output one warning per keyword: */ + if (*key != 0) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character != 0) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } +#endif /* WARNINGS */ + + return key_len; +} +#endif /* WRITE_TEXT || WRITE_pCAL || WRITE_iCCP || WRITE_sPLT */ /* 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) +png_write_IHDR(png_structrp 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) { - PNG_IHDR; - int ret; - png_byte buf[13]; /* Buffer to store the IHDR info */ png_debug(1, "in png_write_IHDR"); @@ -435,36 +772,61 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, case 2: case 4: case 8: - case 16: png_ptr->channels = 1; break; - default: png_error(png_ptr, - "Invalid bit depth for grayscale image"); +#ifdef PNG_WRITE_16BIT_SUPPORTED + case 16: +#endif + png_ptr->channels = 1; break; + + default: + png_error(png_ptr, + "Invalid bit depth for grayscale image"); } break; + case PNG_COLOR_TYPE_RGB: +#ifdef PNG_WRITE_16BIT_SUPPORTED if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif 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"); + 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: +#ifdef PNG_WRITE_16BIT_SUPPORTED if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif 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"); } @@ -486,13 +848,13 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, */ if ( #ifdef 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)) && + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + ((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) + filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Invalid filter type specified"); filter_type = PNG_FILTER_TYPE_BASE; @@ -500,7 +862,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, #ifdef PNG_WRITE_INTERLACING_SUPPORTED if (interlace_type != PNG_INTERLACE_NONE && - interlace_type != PNG_INTERLACE_ADAM7) + interlace_type != PNG_INTERLACE_ADAM7) { png_warning(png_ptr, "Invalid interlace type specified"); interlace_type = PNG_INTERLACE_ADAM7; @@ -509,7 +871,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, interlace_type=PNG_INTERLACE_NONE; #endif - /* Save the relevent information */ + /* Save the relevant information */ png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->color_type = (png_byte)color_type; png_ptr->interlaced = (png_byte)interlace_type; @@ -537,55 +899,19 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, buf[12] = (png_byte)interlace_type; /* Write the chunk */ - png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); + png_write_complete_chunk(png_ptr, 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->do_filter) == PNG_NO_FILTERS) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || - png_ptr->bit_depth < 8) + 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; - ret = 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); - if (ret != Z_OK) - { - if (ret == Z_VERSION_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- version error"); - if (ret == Z_STREAM_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- stream error"); - if (ret == Z_MEM_ERROR) png_error(png_ptr, - "zlib failed to initialize compressor -- mem error"); - png_error(png_ptr, "zlib failed to initialize compressor"); - } - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - /* libpng is not interested in zstream.data_type */ - /* Set it to a predefined value, to avoid its evaluation inside zlib */ - png_ptr->zstream.data_type = Z_BINARY; - png_ptr->mode = PNG_HAVE_IHDR; + png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ } /* Write the palette. We are careful not to trust png_color to be in the @@ -593,45 +919,47 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, * structure. */ void /* PRIVATE */ -png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, + png_uint_32 num_pal) { - PNG_PLTE; png_uint_32 i; - png_colorp pal_ptr; + png_const_colorp pal_ptr; png_byte buf[3]; png_debug(1, "in png_write_PLTE"); if (( #ifdef PNG_MNG_FEATURES_SUPPORTED - !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && #endif - num_pal == 0) || num_pal > 256) + 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_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)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { png_warning(png_ptr, - "Ignoring request to write a PLTE chunk in grayscale PNG"); + "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", png_ptr->num_palette); - png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, - (png_uint_32)(num_pal * 3)); + png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); #ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) { buf[0] = pal_ptr->red; @@ -639,11 +967,13 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) 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; @@ -651,216 +981,280 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) 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 */ +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ void /* PRIVATE */ -png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) { - PNG_IDAT; - - png_debug(1, "in png_write_IDAT"); - - /* Optimize the CMF field in the zlib stream. */ - /* This hack of the zlib stream is compliant to the stream specification. */ - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + if (png_ptr->zowner != png_IDAT) { - unsigned int z_cmf = data[0]; /* zlib compression method and flags */ - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) { - /* Avoid memory underflows and multiplication overflows. - * - * The conditions below are practically always satisfied; - * however, they still must be checked. - */ - if (length >= 2 && - png_ptr->height < 16384 && png_ptr->width < 16384) - { - png_uint_32 uncompressed_idat_size = png_ptr->height * - ((png_ptr->width * - png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - unsigned int z_cinfo = z_cmf >> 4; - unsigned int half_z_window_size = 1 << (z_cinfo + 7); - while (uncompressed_idat_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); - if (data[0] != (png_byte)z_cmf) - { - data[0] = (png_byte)z_cmf; - data[1] &= 0xe0; - data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); - } - } + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; } + else - png_error(png_ptr, - "Invalid zlib compression method or flags in IDAT"); + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; } - png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); - png_ptr->mode |= PNG_HAVE_IDAT; + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } + } } /* Write an IEND chunk */ void /* PRIVATE */ -png_write_IEND(png_structp png_ptr) +png_write_IEND(png_structrp png_ptr) { - PNG_IEND; - png_debug(1, "in png_write_IEND"); - png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, - (png_size_t)0); + png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); png_ptr->mode |= PNG_HAVE_IEND; } #ifdef 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) +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) { - PNG_gAMA; - png_uint_32 igamma; - png_byte buf[4]; - - png_debug(1, "in png_write_gAMA"); - - /* 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) -{ - PNG_gAMA; png_byte buf[4]; png_debug(1, "in png_write_gAMA"); /* file_gamma is saved in 1/100,000ths */ png_save_uint_32(buf, (png_uint_32)file_gamma); - png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); + png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); } #endif -#endif #ifdef PNG_WRITE_sRGB_SUPPORTED /* Write a sRGB chunk */ void /* PRIVATE */ -png_write_sRGB(png_structp png_ptr, int srgb_intent) +png_write_sRGB(png_structrp png_ptr, int srgb_intent) { - PNG_sRGB; png_byte buf[1]; png_debug(1, "in png_write_sRGB"); if (srgb_intent >= PNG_sRGB_INTENT_LAST) - png_warning(png_ptr, - "Invalid sRGB rendering intent specified"); + 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); + png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); } #endif #ifdef 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) +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile) { - PNG_iCCP; - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_uint_32 profile_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ compression_state comp; - int embedded_profile_len = 0; + png_uint_32 temp; png_debug(1, "in png_write_iCCP"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((name_len = png_check_keyword(png_ptr, name, - &new_name)) == 0) - return; - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - png_warning(png_ptr, "Unknown compression type in iCCP chunk"); - + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ if (profile == NULL) - profile_len = 0; + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ - if (profile_len > 3) - embedded_profile_len = - ((*( (png_bytep)profile ))<<24) | - ((*( (png_bytep)profile + 1))<<16) | - ((*( (png_bytep)profile + 2))<< 8) | - ((*( (png_bytep)profile + 3)) ); + profile_len = png_get_uint_32(profile); + + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_len & 0x03)) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); - if (embedded_profile_len < 0) { - png_warning(png_ptr, - "Embedded profile length in iCCP chunk is negative"); - png_free(png_ptr, new_name); - return; + png_uint_32 embedded_profile_len = png_get_uint_32(profile); + + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); } - if (profile_len < embedded_profile_len) - { - png_warning(png_ptr, - "Embedded profile length too large in iCCP chunk"); - png_free(png_ptr, new_name); - return; - } + name_len = png_check_keyword(png_ptr, name, new_name); - if (profile_len > embedded_profile_len) - { - png_warning(png_ptr, - "Truncating profile to actual length in iCCP chunk"); - profile_len = embedded_profile_len; - } + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); - if (profile_len) - profile_len = png_text_compress(png_ptr, profile, - (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; /* 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, - (png_size_t)(name_len + 2)); + ++name_len; - if (profile_len) - png_write_compressed_data_out(png_ptr, &comp); + png_text_compress_init(&comp, profile, profile_len); + + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sPLT_SUPPORTED /* Write a sPLT chunk */ void /* PRIVATE */ -png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) { - PNG_sPLT; - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_byte new_name[80]; png_byte entrybuf[10]; png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); png_size_t palette_size = entry_size * spalette->nentries; @@ -871,15 +1265,19 @@ png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) png_debug(1, "in png_write_sPLT"); - if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) - return; + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); /* 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_header(png_ptr, png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 1)); - png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); + (png_size_t)(name_len + 1)); + + png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); /* Loop through each palette entry, writing appropriately */ #ifdef PNG_POINTER_INDEXING_SUPPORTED @@ -887,69 +1285,72 @@ png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) { 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); + 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_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, (png_size_t)entry_size); + + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #else ep=spalette->entries; - for (i=0; i>spalette->nentries; i++) + 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); + 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_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, (png_size_t)entry_size); + + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #endif png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sBIT_SUPPORTED /* Write the sBIT chunk */ void /* PRIVATE */ -png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) { - PNG_sBIT; png_byte buf[4]; png_size_t size; png_debug(1, "in png_write_sBIT"); /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if (color_type & PNG_COLOR_MASK_COLOR) + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_byte maxbits; maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : - png_ptr->usr_bit_depth); + png_ptr->usr_bit_depth); + if (sbit->red == 0 || sbit->red > maxbits || sbit->green == 0 || sbit->green > maxbits || sbit->blue == 0 || sbit->blue > maxbits) @@ -957,11 +1358,13 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) 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) @@ -969,115 +1372,58 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) png_warning(png_ptr, "Invalid sBIT depth specified"); return; } + buf[0] = sbit->gray; size = 1; } - if (color_type & PNG_COLOR_MASK_ALPHA) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { 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); + png_write_complete_chunk(png_ptr, png_sBIT, buf, size); } #endif #ifdef 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) +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) { - PNG_cHRM; - png_byte buf[32]; - - 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; - - png_debug(1, "in png_write_cHRM"); - - int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5); - int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5); - int_red_x = (png_uint_32)(red_x * 100000.0 + 0.5); - int_red_y = (png_uint_32)(red_y * 100000.0 + 0.5); - int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5); - int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5); - int_blue_x = (png_uint_32)(blue_x * 100000.0 + 0.5); - int_blue_y = (png_uint_32)(blue_y * 100000.0 + 0.5); - -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_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 - { - /* Each value is saved in 1/100,000ths */ - - png_save_uint_32(buf, int_white_x); - png_save_uint_32(buf + 4, int_white_y); - - png_save_uint_32(buf + 8, int_red_x); - png_save_uint_32(buf + 12, int_red_y); - - png_save_uint_32(buf + 16, int_green_x); - png_save_uint_32(buf + 20, int_green_y); - - png_save_uint_32(buf + 24, int_blue_x); - png_save_uint_32(buf + 28, int_blue_y); - - 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) -{ - PNG_cHRM; png_byte buf[32]; png_debug(1, "in png_write_cHRM"); /* Each value is saved in 1/100,000ths */ -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, - green_x, green_y, blue_x, blue_y)) -#endif - { - png_save_uint_32(buf, (png_uint_32)white_x); - png_save_uint_32(buf + 4, (png_uint_32)white_y); + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); - png_save_uint_32(buf + 8, (png_uint_32)red_x); - png_save_uint_32(buf + 12, (png_uint_32)red_y); + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); - png_save_uint_32(buf + 16, (png_uint_32)green_x); - png_save_uint_32(buf + 20, (png_uint_32)green_y); + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); - png_save_uint_32(buf + 24, (png_uint_32)blue_x); - png_save_uint_32(buf + 28, (png_uint_32)blue_y); + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); - png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); - } + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); } #endif -#endif #ifdef PNG_WRITE_tRNS_SUPPORTED /* Write the tRNS chunk */ void /* PRIVATE */ -png_write_tRNS(png_structp png_ptr, png_bytep trans_alpha, png_color_16p tran, - int num_trans, int color_type) +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, + png_const_color_16p tran, int num_trans, int color_type) { - PNG_tRNS; png_byte buf[6]; png_debug(1, "in png_write_tRNS"); @@ -1086,42 +1432,54 @@ png_write_tRNS(png_structp png_ptr, png_bytep trans_alpha, png_color_16p tran, { if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) { - png_warning(png_ptr, "Invalid number of transparent colors specified"); + png_app_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_alpha, - (png_size_t)num_trans); + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (png_size_t)num_trans); } + else if (color_type == PNG_COLOR_TYPE_GRAY) { /* One 16 bit value */ if (tran->gray >= (1 << png_ptr->bit_depth)) { - png_warning(png_ptr, - "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + png_app_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + return; } + png_save_uint_16(buf, tran->gray); - png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); + png_write_complete_chunk(png_ptr, 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); - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif { - png_warning(png_ptr, + png_app_warning(png_ptr, "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } - png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); + + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); } + else { - png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); } } #endif @@ -1129,9 +1487,8 @@ png_write_tRNS(png_structp png_ptr, png_bytep trans_alpha, png_color_16p tran, #ifdef PNG_WRITE_bKGD_SUPPORTED /* Write the background chunk */ void /* PRIVATE */ -png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) { - PNG_bKGD; png_byte buf[6]; png_debug(1, "in png_write_bKGD"); @@ -1140,40 +1497,51 @@ png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) { if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette || - (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && + (png_ptr->num_palette != 0 || + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && #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); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); } - else if (color_type & PNG_COLOR_MASK_COLOR) + + else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_save_uint_16(buf, back->red); png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 4, back->blue); - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif { png_warning(png_ptr, - "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + return; } - png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); + + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); } + else { if (back->gray >= (1 << png_ptr->bit_depth)) { png_warning(png_ptr, - "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + return; } + png_save_uint_16(buf, back->gray); - png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); } } #endif @@ -1181,9 +1549,8 @@ png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ -png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) { - PNG_hIST; int i; png_byte buf[3]; @@ -1192,242 +1559,110 @@ png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) if (num_hist > (int)png_ptr->num_palette) { png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, - png_ptr->num_palette); + 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)); + png_write_chunk_header(png_ptr, 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"); - - *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'", key); - - *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); - if (*new_key == NULL) - { - png_warning(png_ptr, "Out of memory while procesing keyword"); - return ((png_size_t)0); - } - - /* Replace non-printing characters with a blank and print a warning */ - for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) - { - if ((png_byte)*kp < 0x20 || - ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) - { -#ifdef PNG_STDIO_SUPPORTED - char msg[40]; - - png_snprintf(msg, 40, - "invalid keyword character 0x%02X", (png_byte)*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'", 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); - 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 - #ifdef 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) +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + png_size_t text_len) { - PNG_tEXt; - png_size_t key_len; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[80]; png_debug(1, "in png_write_tEXt"); - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); if (text == NULL || *text == '\0') text_len = 0; + else - text_len = png_strlen(text); + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); /* 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)); + png_write_chunk_header(png_ptr, png_tEXt, + (png_uint_32)/*checked above*/(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, - (png_size_t)(key_len + 1)); - if (text_len) - png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); + png_write_chunk_data(png_ptr, new_key, key_len + 1); + + if (text_len != 0) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); } #endif #ifdef 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) +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + int compression) { - PNG_zTXt; - png_size_t key_len; - char buf[1]; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) + if (compression == PNG_TEXT_COMPRESSION_NONE) { - png_free(png_ptr, new_key); + png_write_tEXt(png_ptr, key, text, 0); 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; - } + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); - text_len = png_strlen(text); + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); + + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression, - &comp); + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); + + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); /* 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)new_key, - (png_size_t)(key_len + 1)); - png_free(png_ptr, new_key); + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); + + /* Write key */ + png_write_chunk_data(png_ptr, new_key, key_len); - 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); @@ -1439,97 +1674,109 @@ png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, #ifdef 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) +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, + png_const_charp lang, png_const_charp lang_key, png_const_charp text) { - PNG_iTXt; - png_size_t lang_len, key_len, lang_key_len, text_len; - png_charp new_lang; - png_charp new_key = NULL; - png_byte cbuf[2]; + png_uint_32 key_len, prefix_len; + png_size_t lang_len, lang_key_len; + png_byte new_key[82]; compression_state comp; png_debug(1, "in png_write_iTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; + key_len = png_check_keyword(png_ptr, key, new_key); - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); - if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) + /* Set the compression flag */ + switch (compression) { - png_warning(png_ptr, "Empty language field in iTXt chunk"); - new_lang = NULL; - lang_len = 0; + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; + + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; + + default: + png_error(png_ptr, "iTXt: invalid compression"); } - if (lang_key == NULL) - lang_key_len = 0; - else - lang_key_len = png_strlen(lang_key); - - if (text == NULL) - text_len = 0; - else - text_len = png_strlen(text); - - /* 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)); + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ /* 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. + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ - /* 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, (png_size_t)2); + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_len); - cbuf[0] = 0; - png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), - (png_size_t)(lang_len + 1)); - png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), - (png_size_t)(lang_key_len + 1)); - png_write_compressed_data_out(png_ptr, &comp); + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); + + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); + + if (compression != 0) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } + + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); + + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } + + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); + + png_write_chunk_data(png_ptr, new_key, key_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); + + if (compression != 0) + png_write_compressed_data_out(png_ptr, &comp); + + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); - png_free(png_ptr, new_lang); } #endif #ifdef PNG_WRITE_oFFs_SUPPORTED /* Write the oFFs chunk */ void /* PRIVATE */ -png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, - int unit_type) +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) { - PNG_oFFs; png_byte buf[9]; png_debug(1, "in png_write_oFFs"); @@ -1541,63 +1788,67 @@ png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, png_save_int_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); + png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); } #endif #ifdef 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) +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_const_charp units, + png_charpp params) { - PNG_pCAL; - png_size_t purpose_len, units_len, total_len; - png_uint_32p params_len; + png_uint_32 purpose_len; + png_size_t units_len, total_len; + png_size_tp params_len; png_byte buf[10]; - png_charp new_purpose; + png_byte new_purpose[80]; int i; png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); if (type >= PNG_EQUATION_LAST) - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ - purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); - units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; - params_len = (png_uint_32p)png_malloc(png_ptr, - (png_alloc_size_t)(nparams * png_sizeof(png_uint_32))); + params_len = (png_size_tp)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); /* Find the length of each parameter, making sure we don't count the - null terminator for the last parameter. */ + * null terminator for the last parameter. + */ for (i = 0; i < nparams; i++) { - params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); png_debug2(3, "pCAL parameter %d length = %lu", i, - (unsigned long) params_len[i]); - total_len += (png_size_t)params_len[i]; + (unsigned long)params_len[i]); + total_len += params_len[i]; } png_debug1(3, "pCAL total length = %d", (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, - (png_size_t)purpose_len); + png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, 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); + png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); for (i = 0; i < nparams; i++) { - png_write_chunk_data(png_ptr, (png_bytep)params[i], - (png_size_t)params_len[i]); + png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); } png_free(png_ptr, params_len); @@ -1607,40 +1858,19 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, #ifdef PNG_WRITE_sCAL_SUPPORTED /* Write the sCAL chunk */ -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) void /* PRIVATE */ -png_write_sCAL(png_structp png_ptr, int unit, double width, double height) +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, + png_const_charp height) { - PNG_sCAL; - char buf[64]; - png_size_t total_len; - - png_debug(1, "in png_write_sCAL"); - - buf[0] = (char)unit; - png_snprintf(buf + 1, 63, "%12.12e", width); - total_len = 1 + png_strlen(buf + 1) + 1; - png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); - total_len += png_strlen(buf + total_len); - - png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); -} -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -void /* PRIVATE */ -png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, - png_charp height) -{ - PNG_sCAL; png_byte buf[64]; png_size_t wlen, hlen, total_len; png_debug(1, "in png_write_sCAL_s"); - wlen = png_strlen(width); - hlen = png_strlen(height); + wlen = strlen(width); + hlen = strlen(height); total_len = wlen + hlen + 2; + if (total_len > 64) { png_warning(png_ptr, "Can't write sCAL (buffer too small)"); @@ -1648,24 +1878,21 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, } buf[0] = (png_byte)unit; - png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ - png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); + png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); } #endif -#endif -#endif #ifdef 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) +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) { - PNG_pHYs; png_byte buf[9]; png_debug(1, "in png_write_pHYs"); @@ -1677,7 +1904,7 @@ png_write_pHYs(png_structp png_ptr, png_uint_32 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); + png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); } #endif @@ -1686,9 +1913,8 @@ png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, * 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) +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) { - PNG_tIME; png_byte buf[7]; png_debug(1, "in png_write_tIME"); @@ -1708,130 +1934,137 @@ png_write_tIME(png_structp png_ptr, png_timep mod_time) buf[5] = mod_time->minute; buf[6] = mod_time->second; - png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); + png_write_complete_chunk(png_ptr, 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) +png_write_start_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - png_size_t buf_size; + png_alloc_size_t buf_size; + int usr_pixel_depth; png_debug(1, "in png_write_start_row"); - buf_size = (png_size_t)(PNG_ROWBYTES( - png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); + usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; + buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; + + /* 1.5.6: added to allow checking in the row write code. */ + png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; + png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; /* Set up row buffer */ - png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)buf_size); + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; #ifdef PNG_WRITE_FILTER_SUPPORTED /* 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_alloc_size_t)(png_ptr->rowbytes + 1)); + 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)) + if ((png_ptr->do_filter & + (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) { /* Set up previous row buffer */ - png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, - (png_alloc_size_t)buf_size); + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); - if (png_ptr->do_filter & PNG_FILTER_UP) + if ((png_ptr->do_filter & PNG_FILTER_UP) != 0) { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_size_t)(png_ptr->rowbytes + 1)); + png_ptr->rowbytes + 1); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } - if (png_ptr->do_filter & PNG_FILTER_AVG) + if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0) { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)(png_ptr->rowbytes + 1)); + png_ptr->rowbytes + 1); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } - if (png_ptr->do_filter & PNG_FILTER_PAETH) + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0) { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - (png_size_t)(png_ptr->rowbytes + 1)); + png_ptr->rowbytes + 1); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; + 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]; + 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) +png_write_finish_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - int ret; - png_debug(1, "in png_write_finish_row"); /* Next row */ @@ -1843,31 +2076,37 @@ png_write_finish_row(png_structp png_ptr) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) { 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_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) + 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) != 0) break; + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); } @@ -1876,9 +2115,10 @@ png_write_finish_row(png_structp png_ptr) if (png_ptr->pass < 7) { if (png_ptr->prev_row != NULL) - png_memset(png_ptr->prev_row, 0, - (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* - png_ptr->usr_bit_depth, png_ptr->width)) + 1); + memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); + return; } } @@ -1886,39 +2126,7 @@ png_write_finish_row(png_structp png_ptr) /* 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); - png_ptr->zstream.data_type = Z_BINARY; + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); } #ifdef PNG_WRITE_INTERLACING_SUPPORTED @@ -1935,10 +2143,10 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) /* 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}; + static PNG_CONST png_byte 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}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_write_interlace"); @@ -1961,6 +2169,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) dp = row; d = 0; shift = 7; + for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { @@ -1974,14 +2183,17 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) *dp++ = (png_byte)d; d = 0; } + else shift--; } if (shift != 7) *dp = (png_byte)d; + break; } + case 2: { png_bytep sp; @@ -1995,6 +2207,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) dp = row; shift = 6; d = 0; + for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { @@ -2008,13 +2221,16 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) *dp++ = (png_byte)d; d = 0; } + else shift -= 2; } if (shift != 6) - *dp = (png_byte)d; + *dp = (png_byte)d; + break; } + case 4: { png_bytep sp; @@ -2029,7 +2245,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) shift = 4; d = 0; for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) + i += png_pass_inc[pass]) { sp = row + (png_size_t)(i >> 1); value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; @@ -2041,13 +2257,16 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) *dp++ = (png_byte)d; d = 0; } + else shift -= 4; } if (shift != 4) *dp = (png_byte)d; + break; } + default: { png_bytep sp; @@ -2058,18 +2277,21 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) /* 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 */ + + /* 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); + memcpy(dp, sp, pixel_bytes); + /* Next pixel */ dp += pixel_bytes; } @@ -2078,11 +2300,12 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) } /* 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 = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); } } #endif @@ -2091,21 +2314,25 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) * been specified by the application, and then writes the row out with the * chosen filter. */ +static void /* PRIVATE */ +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t row_bytes); + #define PNG_MAXSUM (((png_uint_32)(-1)) >> 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_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { png_bytep best_row; #ifdef PNG_WRITE_FILTER_SUPPORTED png_bytep prev_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; + png_size_t row_bytes = row_info->rowbytes; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - int num_p_filters = (int)png_ptr->num_prev_filters; + int num_p_filters = png_ptr->num_prev_filters; #endif png_debug(1, "in png_write_find_filter"); @@ -2113,8 +2340,8 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) #ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) { - /* These will never be selected so we need not test them. */ - filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); } #endif @@ -2140,11 +2367,14 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) * 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) */ @@ -2153,12 +2383,11 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) /* 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) + if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE) { png_bytep rp; png_uint_32 sum = 0; - png_uint_32 i; + png_size_t i; int v; for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) @@ -2181,9 +2410,10 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } @@ -2192,12 +2422,14 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) * it has the minimum possible computational cost - none). */ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; + else sum = (sumhi << PNG_HISHIFT) + sumlo; } @@ -2210,25 +2442,28 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) /* It's the only filter so no testing is needed */ { png_bytep rp, lp, dp; - png_uint_32 i; + png_size_t 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); + *dp = (png_byte)((int)*rp - (int)*lp); } + best_row = png_ptr->sub_row; } - else if (filter_to_do & PNG_FILTER_SUB) + else if ((filter_to_do & PNG_FILTER_SUB) != 0) { png_bytep rp, dp, lp; png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; + png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -2248,19 +2483,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; + else lmins = (lmhi << PNG_HISHIFT) + lmlo; } @@ -2273,10 +2511,11 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) sum += (v < 128) ? v : 256 - v; } + for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + v = *dp = (png_byte)((int)*rp - (int)*lp); sum += (v < 128) ? v : 256 - v; @@ -2297,19 +2536,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) { sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; + else sum = (sumhi << PNG_HISHIFT) + sumlo; } @@ -2326,22 +2568,23 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (filter_to_do == PNG_FILTER_UP) { png_bytep rp, dp, pp; - png_uint_32 i; + png_size_t 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++) + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + *dp = (png_byte)((int)*rp - (int)*pp); } + best_row = png_ptr->up_row; } - else if (filter_to_do & PNG_FILTER_UP) + else if ((filter_to_do & PNG_FILTER_UP) != 0) { png_bytep rp, dp, pp; png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; + png_size_t i; int v; @@ -2358,28 +2601,31 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; + 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++) + pp = prev_row + 1; i < row_bytes; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; @@ -2400,19 +2646,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; + else sum = (sumhi << PNG_HISHIFT) + sumlo; } @@ -2430,24 +2679,26 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) { 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); + *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); } + for (lp = row_buf + 1; i < row_bytes; i++) { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); + *dp++ = + (png_byte)((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)); } best_row = png_ptr->avg_row; } - else if (filter_to_do & PNG_FILTER_AVG) + else if ((filter_to_do & PNG_FILTER_AVG) != 0) { png_bytep rp, dp, pp, lp; png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; + png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -2463,19 +2714,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; + else lmins = (lmhi << PNG_HISHIFT) + lmlo; } @@ -2484,14 +2738,15 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) 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); + v = *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); 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); + (png_byte)(((int)*rp++ - ((int)*pp++ + (int)*lp++) / 2)); sum += (v < 128) ? v : 256 - v; @@ -2512,19 +2767,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; + else sum = (sumhi << PNG_HISHIFT) + sumlo; } @@ -2538,14 +2796,15 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) } /* Paeth filter */ - if (filter_to_do == PNG_FILTER_PAETH) + if ((filter_to_do == PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; - png_uint_32 i; + png_size_t i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, - pp = prev_row + 1; i < bpp; i++) + pp = prev_row + 1; i < bpp; i++) { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + *dp++ = (png_byte)((int)*rp++ - (int)*pp++); } for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) @@ -2571,16 +2830,16 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + *dp++ = (png_byte)((int)*rp++ - p); } best_row = png_ptr->paeth_row; } - else if (filter_to_do & PNG_FILTER_PAETH) + else if ((filter_to_do & PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; png_uint_32 sum = 0, lmins = mins; - png_uint_32 i; + png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -2596,28 +2855,31 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; + 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++) + pp = prev_row + 1; i < bpp; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; } @@ -2643,20 +2905,23 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; -#else /* PNG_SLOW_PAETH */ +#else /* 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 */ +#endif /* SLOW_PAETH */ - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - p); sum += (v < 128) ? v : 256 - v; @@ -2677,19 +2942,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; + PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; + PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; + else sum = (sumhi << PNG_HISHIFT) + sumlo; } @@ -2700,10 +2968,10 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) best_row = png_ptr->paeth_row; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - /* Do the actual writing of the filtered row data from the chosen filter. */ +#endif /* WRITE_FILTER */ - png_write_filtered_row(png_ptr, best_row); + /* Do the actual writing of the filtered row data from the chosen filter. */ + png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); #ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -2711,55 +2979,31 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) 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 -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ } /* Do the actual writing of a previously filtered row. */ -void /* PRIVATE */ -png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +static void +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t full_row_length/*includes filter byte*/) { png_debug(1, "in png_write_filtered_row"); png_debug1(2, "filter = %d", 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); + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); +#ifdef PNG_WRITE_FILTER_SUPPORTED /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) { @@ -2769,6 +3013,7 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) png_ptr->prev_row = png_ptr->row_buf; png_ptr->row_buf = tptr; } +#endif /* WRITE_FILTER */ /* Finish row - updates counters and flushes zlib if last row */ png_write_finish_row(png_ptr); @@ -2781,6 +3026,6 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) { png_write_flush(png_ptr); } -#endif +#endif /* WRITE_FLUSH */ } -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE */ diff --git a/thirdparty/libtiff/libtiff.def b/thirdparty/libtiff/libtiff.def index ce36cfde..98228f1b 100644 --- a/thirdparty/libtiff/libtiff.def +++ b/thirdparty/libtiff/libtiff.def @@ -1,151 +1,164 @@ -EXPORTS TIFFOpen - TIFFOpenW - TIFFGetVersion - TIFFCleanup - TIFFClose - TIFFFlush - TIFFFlushData - TIFFGetField - TIFFVGetField - TIFFGetFieldDefaulted - TIFFVGetFieldDefaulted - TIFFGetTagListEntry - TIFFGetTagListCount - TIFFReadDirectory - TIFFScanlineSize64 - TIFFScanlineSize - TIFFStripSize64 - TIFFStripSize - TIFFVStripSize64 - TIFFVStripSize - TIFFRawStripSize64 - TIFFRawStripSize - TIFFTileRowSize64 - TIFFTileRowSize - TIFFTileSize64 - TIFFTileSize - TIFFVTileSize64 - TIFFVTileSize - TIFFFileno - TIFFSetFileno - TIFFGetMode - TIFFIsTiled - TIFFIsByteSwapped - TIFFIsBigEndian - TIFFIsMSB2LSB - TIFFIsUpSampled +EXPORTS TIFFAccessTagMethods TIFFCIELabToRGBInit TIFFCIELabToXYZ - TIFFXYZToRGB - TIFFYCbCrToRGBInit - TIFFYCbCrtoRGB - TIFFCurrentRow + TIFFCheckTile + TIFFCheckpointDirectory + TIFFCleanup + TIFFClientOpen + TIFFClientdata + TIFFClose + TIFFComputeStrip + TIFFComputeTile + TIFFCreateCustomDirectory + TIFFCreateDirectory + TIFFCreateEXIFDirectory + TIFFCurrentDirOffset TIFFCurrentDirectory + TIFFCurrentRow TIFFCurrentStrip TIFFCurrentTile TIFFDataWidth - TIFFReadBufferSetup - TIFFWriteBufferSetup - TIFFSetupStrips - TIFFLastDirectory - TIFFSetDirectory - TIFFSetSubDirectory - TIFFUnlinkDirectory - TIFFSetField - TIFFVSetField - TIFFCheckpointDirectory - TIFFWriteDirectory - TIFFRewriteDirectory - TIFFPrintDirectory - TIFFReadScanline - TIFFWriteScanline - TIFFReadRGBAImage - TIFFReadRGBAImageOriented - TIFFFdOpen - TIFFClientOpen - TIFFFileName - TIFFError - TIFFErrorExt - TIFFWarning - TIFFWarningExt - TIFFSetErrorHandler - TIFFSetErrorHandlerExt - TIFFSetWarningHandler - TIFFSetWarningHandlerExt - TIFFComputeTile - TIFFCheckTile - TIFFNumberOfTiles - TIFFReadTile - TIFFWriteTile - TIFFComputeStrip - TIFFNumberOfStrips - TIFFRGBAImageBegin - TIFFRGBAImageGet - TIFFRGBAImageEnd - TIFFReadEncodedStrip - TIFFReadRawStrip - TIFFReadEncodedTile - TIFFReadRawTile - TIFFReadRGBATile - TIFFReadRGBAStrip - TIFFWriteEncodedStrip - TIFFWriteRawStrip - TIFFWriteEncodedTile - TIFFWriteRawTile - TIFFSetWriteOffset - TIFFSwabFloat - TIFFSwabDouble - TIFFSwabShort - TIFFSwabLong - TIFFSwabArrayOfShort - TIFFSwabArrayOfLong - TIFFSwabArrayOfFloat - TIFFSwabArrayOfDouble - TIFFSwabArrayOfTriples - TIFFReverseBits - TIFFGetBitRevTable TIFFDefaultStripSize TIFFDefaultTileSize - TIFFRasterScanlineSize64 - TIFFRasterScanlineSize - _TIFFmalloc - _TIFFrealloc - _TIFFfree - _TIFFmemset - _TIFFmemcpy - _TIFFmemcmp - TIFFCreateDirectory - TIFFSetTagExtender + TIFFError + TIFFErrorExt + TIFFFdOpen + TIFFFieldDataType + TIFFFieldName + TIFFFieldPassCount + TIFFFieldReadCount + TIFFFieldTag TIFFFieldWithName TIFFFieldWithTag - TIFFCurrentDirOffset - TIFFWriteCheck - TIFFRGBAImageOK - TIFFNumberOfDirectories - TIFFSetFileName - TIFFSetClientdata - TIFFSetMode - TIFFClientdata - TIFFGetReadProc - TIFFGetWriteProc - TIFFGetSeekProc - TIFFGetCloseProc - TIFFGetSizeProc - TIFFGetMapFileProc - TIFFGetUnmapFileProc - TIFFIsCODECConfigured - TIFFGetConfiguredCODECs - TIFFFindCODEC - TIFFRegisterCODEC - TIFFUnRegisterCODEC - TIFFFreeDirectory - TIFFReadCustomDirectory - TIFFReadEXIFDirectory - TIFFAccessTagMethods - TIFFGetClientInfo - TIFFSetClientInfo - TIFFSwabLong8 - TIFFSwabArrayOfLong8 + TIFFFieldWriteCount + TIFFFileName + TIFFFileno + TIFFFindCODEC TIFFFindField - TIFFUnsetField + TIFFFlush + TIFFFlushData + TIFFFreeDirectory + TIFFGetBitRevTable + TIFFGetClientInfo + TIFFGetCloseProc + TIFFGetConfiguredCODECs + TIFFGetField + TIFFGetFieldDefaulted + TIFFGetMapFileProc + TIFFGetMode + TIFFGetReadProc + TIFFGetSeekProc + TIFFGetSizeProc + TIFFGetTagListCount + TIFFGetTagListEntry + TIFFGetUnmapFileProc + TIFFGetVersion + TIFFGetWriteProc + TIFFIsBigEndian + TIFFIsByteSwapped + TIFFIsCODECConfigured + TIFFIsMSB2LSB + TIFFIsTiled + TIFFIsUpSampled + TIFFLastDirectory TIFFMergeFieldInfo + TIFFNumberOfDirectories + TIFFNumberOfStrips + TIFFNumberOfTiles + TIFFOpen + TIFFOpenW + TIFFPrintDirectory + TIFFRGBAImageBegin + TIFFRGBAImageEnd + TIFFRGBAImageGet + TIFFRGBAImageOK + TIFFRasterScanlineSize + TIFFRasterScanlineSize64 + TIFFRawStripSize + TIFFRawStripSize64 + TIFFReadBufferSetup + TIFFReadCustomDirectory + TIFFReadDirectory + TIFFReadEXIFDirectory + TIFFReadEncodedStrip + TIFFReadEncodedTile + TIFFReadRGBAImage + TIFFReadRGBAImageOriented + TIFFReadRGBAStrip + TIFFReadRGBATile + TIFFReadRawStrip + TIFFReadRawTile + TIFFReadScanline + TIFFReadTile + TIFFRegisterCODEC + TIFFReverseBits + TIFFRewriteDirectory + TIFFScanlineSize + TIFFScanlineSize64 + TIFFSetClientInfo + TIFFSetClientdata + TIFFSetCompressionScheme + TIFFSetDirectory + TIFFSetErrorHandler + TIFFSetErrorHandlerExt + TIFFSetField + TIFFSetFileName + TIFFSetFileno + TIFFSetMode + TIFFSetSubDirectory + TIFFSetTagExtender + TIFFSetWarningHandler + TIFFSetWarningHandlerExt + TIFFSetWriteOffset + TIFFSetupStrips + TIFFStripSize + TIFFStripSize64 + TIFFSwabArrayOfDouble + TIFFSwabArrayOfFloat + TIFFSwabArrayOfLong + TIFFSwabArrayOfLong8 + TIFFSwabArrayOfShort + TIFFSwabArrayOfTriples + TIFFSwabDouble + TIFFSwabFloat + TIFFSwabLong + TIFFSwabLong8 + TIFFSwabShort + TIFFTileRowSize + TIFFTileRowSize64 + TIFFTileSize + TIFFTileSize64 + TIFFUnRegisterCODEC + TIFFUnlinkDirectory + TIFFUnsetField + TIFFVGetField + TIFFVGetFieldDefaulted + TIFFVSetField + TIFFVStripSize + TIFFVStripSize64 + TIFFVTileSize + TIFFVTileSize64 + TIFFWarning + TIFFWarningExt + TIFFWriteBufferSetup + TIFFWriteCheck + TIFFWriteCustomDirectory + TIFFWriteDirectory + TIFFWriteEncodedStrip + TIFFWriteEncodedTile + TIFFWriteRawStrip + TIFFWriteRawTile + TIFFWriteScanline + TIFFWriteTile + TIFFXYZToRGB + TIFFYCbCrToRGBInit + TIFFYCbCrtoRGB + _TIFFCheckMalloc + _TIFFCheckRealloc + _TIFFRewriteField + _TIFFfree + _TIFFmalloc + _TIFFmemcmp + _TIFFmemcpy + _TIFFmemset + _TIFFrealloc diff --git a/thirdparty/libtiff/tif_codec.c b/thirdparty/libtiff/tif_codec.c index e2016673..703e87d5 100644 --- a/thirdparty/libtiff/tif_codec.c +++ b/thirdparty/libtiff/tif_codec.c @@ -1,4 +1,4 @@ -/* $Id: tif_codec.c,v 1.15 2010-12-14 12:53:00 dron Exp $ */ +/* $Id: tif_codec.c,v 1.16 2013-05-02 14:44:29 tgl Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -108,7 +108,8 @@ _notConfigured(TIFF* tif) const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); char compression_code[20]; - sprintf( compression_code, "%d", tif->tif_dir.td_compression ); + snprintf(compression_code, sizeof(compression_code), "%d", + tif->tif_dir.td_compression ); TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%s compression support is not configured", c ? c->name : compression_code ); diff --git a/thirdparty/libtiff/tif_config.h.cmake.in b/thirdparty/libtiff/tif_config.h.cmake.in index 455e7b32..a556f3c4 100644 --- a/thirdparty/libtiff/tif_config.h.cmake.in +++ b/thirdparty/libtiff/tif_config.h.cmake.in @@ -380,6 +380,11 @@ /* Define to empty if `const' does not conform to ANSI C. */ #cmakedefine const +/* Visual Studio 2015 / VC 14 / MSVC 19.00 finally has snprintf() */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus diff --git a/thirdparty/libtiff/tif_config.h.in b/thirdparty/libtiff/tif_config.h.in index dfd6e38a..468ddbd3 100644 --- a/thirdparty/libtiff/tif_config.h.in +++ b/thirdparty/libtiff/tif_config.h.in @@ -27,6 +27,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_ASSERT_H +/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. + */ +#undef HAVE_DECL_OPTARG + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -79,12 +83,6 @@ /* Define to 1 if you have the `lfind' function. */ #undef HAVE_LFIND -/* Define to 1 if you have the `c' library (-lc). */ -#undef HAVE_LIBC - -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H @@ -197,8 +195,7 @@ /* Support LogLuv high dynamic range encoding */ #undef LOGLUV_SUPPORT -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ +/* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Support LZMA2 compression */ @@ -213,9 +210,6 @@ /* Support NeXT 2-bit RLE algorithm */ #undef NEXT_SUPPORT -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -#undef NO_MINUS_C_MINUS_O - /* Support Old JPEG compresson (read-only) */ #undef OJPEG_SUPPORT @@ -262,6 +256,9 @@ /* The size of `signed short', as computed by sizeof. */ #undef SIZEOF_SIGNED_SHORT +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + /* The size of `unsigned char *', as computed by sizeof. */ #undef SIZEOF_UNSIGNED_CHAR_P @@ -317,6 +314,12 @@ /* Pointer difference type */ #undef TIFF_PTRDIFF_T +/* Size type formatter */ +#undef TIFF_SIZE_FORMAT + +/* Unsigned size type */ +#undef TIFF_SIZE_T + /* Signed size type formatter */ #undef TIFF_SSIZE_FORMAT @@ -371,6 +374,11 @@ /* Support Deflate compression */ #undef ZIP_SUPPORT +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS diff --git a/thirdparty/libtiff/tif_dir.c b/thirdparty/libtiff/tif_dir.c index 401a080e..73212c02 100644 --- a/thirdparty/libtiff/tif_dir.c +++ b/thirdparty/libtiff/tif_dir.c @@ -1,4 +1,4 @@ -/* $Id: tif_dir.c,v 1.108 2012-02-01 01:51:00 fwarmerdam Exp $ */ +/* $Id: tif_dir.c,v 1.121 2015-05-31 23:11:43 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -122,6 +122,10 @@ setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v) #undef EXTRASAMPLE_COREL_UNASSALPHA } +/* + * Confirm we have "samplesperpixel" ink names separated by \0. Returns + * zero if the ink names are not as expected. + */ static uint32 checkInkNamesString(TIFF* tif, uint32 slen, const char* s) { @@ -132,9 +136,9 @@ checkInkNamesString(TIFF* tif, uint32 slen, const char* s) const char* ep = s+slen; const char* cp = s; for (; i > 0; i--) { - for (; *cp != '\0'; cp++) - if (cp >= ep) - goto bad; + for (; cp < ep && *cp != '\0'; cp++) {} + if (cp >= ep) + goto bad; cp++; /* skip \0 */ } return ((uint32)(cp-s)); @@ -156,9 +160,23 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) TIFFDirectory* td = &tif->tif_dir; int status = 1; uint32 v32, i, v; + double dblval; char* s; + const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); + uint32 standard_tag = tag; + if( fip == NULL ) /* cannot happen since OkToChangeTag() already checks it */ + return 0; + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (ie. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } - switch (tag) { + switch (standard_tag) { case TIFFTAG_SUBFILETYPE: td->td_subfiletype = (uint32) va_arg(ap, uint32); break; @@ -267,10 +285,16 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(ap, double), td->td_samplesperpixel); break; case TIFFTAG_XRESOLUTION: - td->td_xresolution = (float) va_arg(ap, double); + dblval = va_arg(ap, double); + if( dblval < 0 ) + goto badvaluedouble; + td->td_xresolution = (float) dblval; break; case TIFFTAG_YRESOLUTION: - td->td_yresolution = (float) va_arg(ap, double); + dblval = va_arg(ap, double); + if( dblval < 0 ) + goto badvaluedouble; + td->td_yresolution = (float) dblval; break; case TIFFTAG_PLANARCONFIG: v = (uint16) va_arg(ap, uint16_vap); @@ -423,7 +447,6 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) default: { TIFFTagValue *tv; int tv_size, iCustom; - const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); /* * This can happen if multiple images are open with different @@ -434,11 +457,11 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) * happens, for example, when tiffcp is used to convert between * compression schemes and codec-specific tags are blindly copied. */ - if(fip == NULL || fip->field_bit != FIELD_CUSTOM) { + if(fip->field_bit != FIELD_CUSTOM) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Invalid %stag \"%s\" (not supported by codec)", tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", - fip ? fip->field_name : "Unknown"); + fip->field_name); status = 0; break; } @@ -550,102 +573,99 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) goto end; } - if ((fip->field_passcount - || fip->field_writecount == TIFF_VARIABLE - || fip->field_writecount == TIFF_VARIABLE2 - || fip->field_writecount == TIFF_SPP - || tv->count > 1) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { + if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + uint16 v[2]; + v[0] = (uint16)va_arg(ap, int); + v[1] = (uint16)va_arg(ap, int); + _TIFFmemcpy(tv->value, &v, 4); + } + + else if (fip->field_passcount + || fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2 + || fip->field_writecount == TIFF_SPP + || tv->count > 1) { _TIFFmemcpy(tv->value, va_arg(ap, void *), tv->count * tv_size); } else { - /* - * XXX: The following loop required to handle - * TIFFTAG_PAGENUMBER, TIFFTAG_HALFTONEHINTS, - * TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE tags. - * These tags are actually arrays and should be passed as - * array pointers to TIFFSetField() function, but actually - * passed as a list of separate values. This behaviour - * must be changed in the future! - */ - int i; char *val = (char *)tv->value; + assert( tv->count == 1 ); - for (i = 0; i < tv->count; i++, val += tv_size) { - switch (fip->field_type) { - case TIFF_BYTE: - case TIFF_UNDEFINED: - { - uint8 v = (uint8)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SBYTE: - { - int8 v = (int8)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SHORT: - { - uint16 v = (uint16)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SSHORT: - { - int16 v = (int16)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_LONG: - case TIFF_IFD: - { - uint32 v = va_arg(ap, uint32); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SLONG: - { - int32 v = va_arg(ap, int32); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_LONG8: - case TIFF_IFD8: - { - uint64 v = va_arg(ap, uint64); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SLONG8: - { - int64 v = va_arg(ap, int64); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - case TIFF_FLOAT: - { - float v = (float)va_arg(ap, double); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_DOUBLE: - { - double v = va_arg(ap, double); - _TIFFmemcpy(val, &v, tv_size); - } - break; - default: - _TIFFmemset(val, 0, tv_size); - status = 0; - break; + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + { + uint8 v = (uint8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); } + break; + case TIFF_SBYTE: + { + int8 v = (int8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SHORT: + { + uint16 v = (uint16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SSHORT: + { + int16 v = (int16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_LONG: + case TIFF_IFD: + { + uint32 v = va_arg(ap, uint32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SLONG: + { + int32 v = va_arg(ap, int32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_LONG8: + case TIFF_IFD8: + { + uint64 v = va_arg(ap, uint64); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SLONG8: + { + int64 v = va_arg(ap, int64); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + { + float v = (float)va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_DOUBLE: + { + double v = va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + default: + _TIFFmemset(val, 0, tv_size); + status = 0; + break; } } } @@ -681,6 +701,16 @@ badvalue32: va_end(ap); } return (0); +badvaluedouble: + { + const TIFFField* fip=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %f for \"%s\" tag", + tif->tif_name, dblval, + fip ? fip->field_name : "Unknown"); + va_end(ap); + } + return (0); } /* @@ -795,8 +825,22 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) { TIFFDirectory* td = &tif->tif_dir; int ret_val = 1; + uint32 standard_tag = tag; + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if( fip == NULL ) /* cannot happen since TIFFGetField() already checks it */ + return 0; + + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (ie. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } - switch (tag) { + switch (standard_tag) { case TIFFTAG_SUBFILETYPE: *va_arg(ap, uint32*) = td->td_subfiletype; break; @@ -971,8 +1015,6 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) break; default: { - const TIFFField* fip = - TIFFFindField(tif, tag, TIFF_ANY); int i; /* @@ -984,14 +1026,14 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) * get a tag that is not valid for the image's * codec then we'll arrive here. */ - if( fip == NULL || fip->field_bit != FIELD_CUSTOM ) + if( fip->field_bit != FIELD_CUSTOM ) { TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField", "%s: Invalid %stag \"%s\" " "(not supported by codec)", tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", - fip ? fip->field_name : "Unknown"); + fip->field_name); ret_val = 0; break; } @@ -1013,84 +1055,85 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) *va_arg(ap, uint16*) = (uint16)tv->count; *va_arg(ap, void **) = tv->value; ret_val = 1; + } else if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + *va_arg(ap, uint16*) = ((uint16 *)tv->value)[0]; + *va_arg(ap, uint16*) = ((uint16 *)tv->value)[1]; + ret_val = 1; } else { - if ((fip->field_type == TIFF_ASCII + if (fip->field_type == TIFF_ASCII || fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2 || fip->field_readcount == TIFF_SPP - || tv->count > 1) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { + || tv->count > 1) { *va_arg(ap, void **) = tv->value; ret_val = 1; } else { - int j; char *val = (char *)tv->value; - - for (j = 0; j < tv->count; - j++, val += _TIFFDataSize(tv->info->field_type)) { - switch (fip->field_type) { - case TIFF_BYTE: - case TIFF_UNDEFINED: - *va_arg(ap, uint8*) = - *(uint8 *)val; - ret_val = 1; - break; - case TIFF_SBYTE: - *va_arg(ap, int8*) = - *(int8 *)val; - ret_val = 1; - break; - case TIFF_SHORT: - *va_arg(ap, uint16*) = - *(uint16 *)val; - ret_val = 1; - break; - case TIFF_SSHORT: - *va_arg(ap, int16*) = - *(int16 *)val; - ret_val = 1; - break; - case TIFF_LONG: - case TIFF_IFD: - *va_arg(ap, uint32*) = - *(uint32 *)val; - ret_val = 1; - break; - case TIFF_SLONG: - *va_arg(ap, int32*) = - *(int32 *)val; - ret_val = 1; - break; - case TIFF_LONG8: - case TIFF_IFD8: - *va_arg(ap, uint64*) = - *(uint64 *)val; - ret_val = 1; - break; - case TIFF_SLONG8: - *va_arg(ap, int64*) = - *(int64 *)val; - ret_val = 1; - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - case TIFF_FLOAT: - *va_arg(ap, float*) = - *(float *)val; - ret_val = 1; - break; - case TIFF_DOUBLE: - *va_arg(ap, double*) = - *(double *)val; - ret_val = 1; - break; - default: - ret_val = 0; - break; - } + assert( tv->count == 1 ); + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + *va_arg(ap, uint8*) = + *(uint8 *)val; + ret_val = 1; + break; + case TIFF_SBYTE: + *va_arg(ap, int8*) = + *(int8 *)val; + ret_val = 1; + break; + case TIFF_SHORT: + *va_arg(ap, uint16*) = + *(uint16 *)val; + ret_val = 1; + break; + case TIFF_SSHORT: + *va_arg(ap, int16*) = + *(int16 *)val; + ret_val = 1; + break; + case TIFF_LONG: + case TIFF_IFD: + *va_arg(ap, uint32*) = + *(uint32 *)val; + ret_val = 1; + break; + case TIFF_SLONG: + *va_arg(ap, int32*) = + *(int32 *)val; + ret_val = 1; + break; + case TIFF_LONG8: + case TIFF_IFD8: + *va_arg(ap, uint64*) = + *(uint64 *)val; + ret_val = 1; + break; + case TIFF_SLONG8: + *va_arg(ap, int64*) = + *(int64 *)val; + ret_val = 1; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + *va_arg(ap, float*) = + *(float *)val; + ret_val = 1; + break; + case TIFF_DOUBLE: + *va_arg(ap, double*) = + *(double *)val; + ret_val = 1; + break; + default: + ret_val = 0; + break; } } } @@ -1214,6 +1257,35 @@ TIFFCreateDirectory(TIFF* tif) return 0; } +int +TIFFCreateCustomDirectory(TIFF* tif, const TIFFFieldArray* infoarray) +{ + TIFFDefaultDirectory(tif); + + /* + * Reset the field definitions to match the application provided list. + * Hopefully TIFFDefaultDirectory() won't have done anything irreversable + * based on it's assumption this is an image directory. + */ + _TIFFSetupFields(tif, infoarray); + + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (uint32) -1; + + return 0; +} + +int +TIFFCreateEXIFDirectory(TIFF* tif) +{ + const TIFFFieldArray* exifFieldArray; + exifFieldArray = _TIFFGetExifFields(); + return TIFFCreateCustomDirectory(tif, exifFieldArray); +} + /* * Setup a default directory structure. */ @@ -1250,8 +1322,20 @@ TIFFDefaultDirectory(TIFF* tif) tif->tif_tagmethods.printdir = NULL; /* * Give client code a chance to install their own - * tag extensions & methods, prior to compression overloads. + * tag extensions & methods, prior to compression overloads, + * but do some prior cleanup first. (http://trac.osgeo.org/gdal/ticket/5054) */ + if (tif->tif_nfieldscompat > 0) { + uint32 i; + + for (i = 0; i < tif->tif_nfieldscompat; i++) { + if (tif->tif_fieldscompat[i].allocated_size) + _TIFFfree(tif->tif_fieldscompat[i].fields); + } + _TIFFfree(tif->tif_fieldscompat); + tif->tif_nfieldscompat = 0; + tif->tif_fieldscompat = NULL; + } if (_TIFFextender) (*_TIFFextender)(tif); (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); @@ -1292,6 +1376,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off) if (((uint64)poffa!=poff)||(poffbtif->tif_size)) { TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count"); + *nextdir=0; return(0); } _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16)); @@ -1401,7 +1486,8 @@ TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off) (void) TIFFSeekFile(tif, dircount16*20, SEEK_CUR); if (!ReadOK(tif, nextdir, sizeof (uint64))) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Error fetching directory link", tif->tif_name); return (0); } @@ -1418,6 +1504,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off) uint16 TIFFNumberOfDirectories(TIFF* tif) { + static const char module[] = "TIFFNumberOfDirectories"; uint64 nextdir; uint16 n; if (!(tif->tif_flags&TIFF_BIGTIFF)) @@ -1426,7 +1513,18 @@ TIFFNumberOfDirectories(TIFF* tif) nextdir = tif->tif_header.big.tiff_diroff; n = 0; while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) - n++; + { + if (n != 65535) { + ++n; + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Directory count exceeded 65535 limit," + " giving up on counting."); + return (65535); + } + } return (n); } diff --git a/thirdparty/libtiff/tif_dirinfo.c b/thirdparty/libtiff/tif_dirinfo.c index 06b5a5a0..7db4bdb9 100644 --- a/thirdparty/libtiff/tif_dirinfo.c +++ b/thirdparty/libtiff/tif_dirinfo.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirinfo.c,v 1.114 2011-05-17 00:21:17 fwarmerdam Exp $ */ +/* $Id: tif_dirinfo.c,v 1.121 2014-05-07 01:58:46 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -37,7 +37,7 @@ * * NOTE: The second field (field_readcount) and third field (field_writecount) * sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3) - * and TIFFTAG_SPP (-2). The macros should be used but would throw off + * and TIFF_SPP (-2). The macros should be used but would throw off * the formatting of the code, so please interprete the -1, -2 and -3 * values accordingly. */ @@ -128,6 +128,8 @@ tiffFields[] = { { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL }, { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL }, { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL }, + { TIFFTAG_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFARepeatPatternDim", NULL }, + { TIFFTAG_CFAPATTERN, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFAPattern" , NULL}, { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL }, /* end Pixar tags */ { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, 0, TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "RichTIFFIPTC", NULL }, @@ -190,9 +192,23 @@ tiffFields[] = { { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotPreProfileMatrix", NULL }, { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentICCProfile", NULL }, { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentPreProfileMatrix", NULL }, - /* end DNG tags */ - /* begin pseudo tags */ { TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, + /* end DNG tags */ + /* begin TIFF/FX tags */ + { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "Indexed", NULL }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GlobalParametersIFD", NULL }, + { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ProfileType", NULL }, + { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "FaxProfile", NULL }, + { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CodingMethods", NULL }, + { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "VersionYear", NULL }, + { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ModeNumber", NULL }, + { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Decode", NULL }, + { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ImageBaseColor", NULL }, + { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "T82Options", NULL }, + { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "StripRowCounts", NULL }, + { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ImageLayer", NULL }, + /* end TIFF/FX tags */ + /* begin pseudo tags */ }; static TIFFField @@ -348,7 +364,7 @@ _TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32 n) { static const char module[] = "_TIFFMergeFields"; static const char reason[] = "for fields array"; - TIFFField** tp; + /* TIFFField** tp; */ uint32 i; tif->tif_foundfield = NULL; @@ -369,7 +385,7 @@ _TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32 n) return 0; } - tp = tif->tif_fields + tif->tif_nfields; + /* tp = tif->tif_fields + tif->tif_nfields; */ for (i = 0; i < n; i++) { const TIFFField *fip = TIFFFindField(tif, info[i].field_tag, TIFF_ANY); @@ -556,6 +572,42 @@ TIFFFieldWithName(TIFF* tif, const char *field_name) return (fip); } +uint32 +TIFFFieldTag(const TIFFField* fip) +{ + return fip->field_tag; +} + +const char * +TIFFFieldName(const TIFFField* fip) +{ + return fip->field_name; +} + +TIFFDataType +TIFFFieldDataType(const TIFFField* fip) +{ + return fip->field_type; +} + +int +TIFFFieldPassCount(const TIFFField* fip) +{ + return fip->field_passcount; +} + +int +TIFFFieldReadCount(const TIFFField* fip) +{ + return fip->field_readcount; +} + +int +TIFFFieldWriteCount(const TIFFField* fip) +{ + return fip->field_writecount; +} + const TIFFField* _TIFFFindOrRegisterField(TIFF *tif, uint32 tag, TIFFDataType dt) @@ -661,7 +713,7 @@ _TIFFCreateAnonField(TIFF *tif, uint32 tag, TIFFDataType field_type) * note that this name is a special sign to TIFFClose() and * _TIFFSetupFields() to free the field */ - sprintf(fld->field_name, "Tag %d", (int) tag); + snprintf(fld->field_name, 32, "Tag %d", (int) tag); return fld; } diff --git a/thirdparty/libtiff/tif_dirread.c b/thirdparty/libtiff/tif_dirread.c index c242d8fa..606366c8 100644 --- a/thirdparty/libtiff/tif_dirread.c +++ b/thirdparty/libtiff/tif_dirread.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirread.c,v 1.174 2012-02-01 02:24:47 fwarmerdam Exp $ */ +/* $Id: tif_dirread.c,v 1.187 2015-05-31 21:09:33 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -2172,11 +2172,6 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEn break; } _TIFFfree(origdata); - if (err!=TIFFReadDirEntryErrOk) - { - _TIFFfree(data); - return(err); - } *value=data; return(TIFFReadDirEntryErrOk); } @@ -2414,11 +2409,6 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEnt break; } _TIFFfree(origdata); - if (err!=TIFFReadDirEntryErrOk) - { - _TIFFfree(data); - return(err); - } *value=data; return(TIFFReadDirEntryErrOk); } @@ -2657,11 +2647,6 @@ TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value) break; } _TIFFfree(origdata); - if (err!=TIFFReadDirEntryErrOk) - { - _TIFFfree(data); - return(err); - } *value=data; return(TIFFReadDirEntryErrOk); } @@ -2723,11 +2708,6 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntr break; } _TIFFfree(origdata); - if (err!=TIFFReadDirEntryErrOk) - { - _TIFFfree(data); - return(err); - } *value=data; return(TIFFReadDirEntryErrOk); } @@ -3313,10 +3293,15 @@ TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest) if (!ReadOK(tif,dest,size)) return(TIFFReadDirEntryErrIo); } else { - tmsize_t ma,mb; - ma=(tmsize_t)offset; + size_t ma,mb; + ma=(size_t)offset; mb=ma+size; - if (((uint64)ma!=offset)||(mbtif->tif_size)) + if (((uint64)ma!=offset) + || (mb < ma) + || (mb - ma != (size_t) size) + || (mb < (size_t)size) + || (mb > (size_t)tif->tif_size) + ) return(TIFFReadDirEntryErrIo); _TIFFmemcpy(dest,tif->tif_base+ma,size); } @@ -3369,7 +3354,7 @@ static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, c } else { switch (err) { case TIFFReadDirEntryErrCount: - TIFFErrorExt(tif->tif_clientdata, module, + TIFFWarningExt(tif->tif_clientdata, module, "Incorrect count for \"%s\"; tag ignored", tagname); break; @@ -3425,6 +3410,8 @@ TIFFReadDirectory(TIFF* tif) const TIFFField* fip; uint32 fii=FAILED_FII; toff_t nextdiroff; + int bitspersample_read = FALSE; + tif->tif_diroff=tif->tif_nextdiroff; if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff)) return 0; /* last offset or bad offset (IFD looping) */ @@ -3701,6 +3688,8 @@ TIFFReadDirectory(TIFF* tif) } if (!TIFFSetField(tif,dp->tdir_tag,value)) goto bad; + if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE ) + bitspersample_read = TRUE; } break; case TIFFTAG_SMINSAMPLEVALUE: @@ -3758,6 +3747,19 @@ TIFFReadDirectory(TIFF* tif) uint32 countrequired; uint32 incrementpersample; uint16* value=NULL; + /* It would be dangerous to instanciate those tag values */ + /* since if td_bitspersample has not yet been read (due to */ + /* unordered tags), it could be read afterwards with a */ + /* values greater than the default one (1), which may cause */ + /* crashes in user code */ + if( !bitspersample_read ) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFWarningExt(tif->tif_clientdata,module, + "Ignoring %s since BitsPerSample tag not found", + fip ? fip->field_name : "unknown tagname"); + continue; + } countpersample=(1L<tif_dir.td_bitspersample); if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample)) { @@ -4273,7 +4275,8 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) TIFFDirectory *td = &tif->tif_dir; uint32 strip; - _TIFFFillStriles( tif ); + if( !_TIFFFillStriles( tif ) ) + return -1; if (td->td_stripbytecount) _TIFFfree(td->td_stripbytecount); @@ -4372,6 +4375,11 @@ TIFFCheckDirOffset(TIFF* tif, uint64 diroff) if (diroff == 0) /* no more directories */ return 0; + if (tif->tif_dirnumber == 65535) { + TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset", + "Cannot handle more than 65535 TIFF directories"); + return 0; + } for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { if (tif->tif_dirlist[n] == diroff) @@ -4391,7 +4399,10 @@ TIFFCheckDirOffset(TIFF* tif, uint64 diroff) tif->tif_dirnumber, 2 * sizeof(uint64), "for IFD list"); if (!new_dirlist) return 0; - tif->tif_dirlistsize = 2 * tif->tif_dirnumber; + if( tif->tif_dirnumber >= 32768 ) + tif->tif_dirlistsize = 65535; + else + tif->tif_dirlistsize = 2 * tif->tif_dirnumber; tif->tif_dirlist = new_dirlist; } @@ -4703,6 +4714,7 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) return 0; } fip=tif->tif_fields[fii]; + assert(fip != NULL); /* should not happen */ assert(fip->set_field_type!=TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */ assert(fip->set_field_type!=TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */ err=TIFFReadDirEntryErrOk; @@ -4761,7 +4773,7 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) break; case TIFF_SETGET_UINT8: { - uint8 data; + uint8 data=0; assert(fip->field_readcount==1); assert(fip->field_passcount==0); err=TIFFReadDirEntryByte(tif,dp,&data); @@ -4855,8 +4867,12 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) uint16* data; assert(fip->field_readcount==2); assert(fip->field_passcount==0); - if (dp->tdir_count!=2) + if (dp->tdir_count!=2) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected 2, got %d", + fip->field_name,(int)dp->tdir_count); return(0); + } err=TIFFReadDirEntryShortArray(tif,dp,&data); if (err==TIFFReadDirEntryErrOk) { @@ -4873,8 +4889,12 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) uint8* data; assert(fip->field_readcount>=1); assert(fip->field_passcount==0); - if (dp->tdir_count!=(uint64)fip->field_readcount) - /* corrupt file */; + if (dp->tdir_count!=(uint64)fip->field_readcount) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected %d, got %d", + fip->field_name,(int) fip->field_readcount, (int)dp->tdir_count); + return 0; + } else { err=TIFFReadDirEntryByteArray(tif,dp,&data); @@ -5342,7 +5362,7 @@ TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) } if (err!=TIFFReadDirEntryErrOk) { - TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",recover); + TIFFReadDirEntryOutputErr(tif,err,module,fip->field_name,recover); return(0); } return(1); diff --git a/thirdparty/libtiff/tif_dirwrite.c b/thirdparty/libtiff/tif_dirwrite.c index 11738cfe..a0fd8dc2 100644 --- a/thirdparty/libtiff/tif_dirwrite.c +++ b/thirdparty/libtiff/tif_dirwrite.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirwrite.c,v 1.76 2011-02-18 20:53:04 fwarmerdam Exp $ */ +/* $Id: tif_dirwrite.c,v 1.78 2015-05-31 00:38:46 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -2570,7 +2570,7 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, tmsize_t count, void* data) { static const char module[] = "TIFFResetField"; - const TIFFField* fip = NULL; + /* const TIFFField* fip = NULL; */ uint16 dircount; tmsize_t dirsize; uint8 direntry_raw[20]; @@ -2586,7 +2586,7 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, /* -------------------------------------------------------------------- */ /* Find field definition. */ /* -------------------------------------------------------------------- */ - fip = TIFFFindField(tif, tag, TIFF_ANY); + /*fip =*/ TIFFFindField(tif, tag, TIFF_ANY); /* -------------------------------------------------------------------- */ /* Do some checking this is a straight forward case. */ @@ -2839,14 +2839,15 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, "Error writing directory link"); return (0); } - - _TIFFfree( buf_to_write ); } else { memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype)); } + _TIFFfree( buf_to_write ); + buf_to_write = 0; + /* -------------------------------------------------------------------- */ /* Adjust the directory entry. */ /* -------------------------------------------------------------------- */ diff --git a/thirdparty/libtiff/tif_fax3.c b/thirdparty/libtiff/tif_fax3.c index 52c16b40..2b2dccd0 100644 --- a/thirdparty/libtiff/tif_fax3.c +++ b/thirdparty/libtiff/tif_fax3.c @@ -1,4 +1,4 @@ -/* $Id: tif_fax3.c,v 1.72 2010-06-09 17:17:13 bfriesen Exp $ */ +/* $Id: tif_fax3.c,v 1.74 2012-06-21 02:01:31 fwarmerdam Exp $ */ /* * Copyright (c) 1990-1997 Sam Leffler @@ -526,6 +526,7 @@ Fax3SetupState(TIFF* tif) "for Group 3/4 run arrays"); if (dsp->runs == NULL) return (0); + memset( dsp->runs, 0, TIFFSafeMultiply(uint32,nruns,2)*sizeof(uint32)); dsp->curruns = dsp->runs; if (needsRefLine) dsp->refruns = dsp->runs + nruns; diff --git a/thirdparty/libtiff/tif_getimage.c b/thirdparty/libtiff/tif_getimage.c index 6a09b4d2..f49b73fd 100644 --- a/thirdparty/libtiff/tif_getimage.c +++ b/thirdparty/libtiff/tif_getimage.c @@ -1,4 +1,4 @@ -/* $Id: tif_getimage.c,v 1.78 2011-02-23 21:46:09 fwarmerdam Exp $ */ +/* $Id: tif_getimage.c,v 1.90 2015-06-17 01:34:08 bfriesen Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler @@ -182,8 +182,23 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) "Planarconfiguration", td->td_planarconfig); return (0); } + if( td->td_samplesperpixel != 3 ) + { + sprintf(emsg, + "Sorry, can not handle image with %s=%d", + "Samples/pixel", td->td_samplesperpixel); + return 0; + } break; case PHOTOMETRIC_CIELAB: + if( td->td_samplesperpixel != 3 || td->td_bitspersample != 8 ) + { + sprintf(emsg, + "Sorry, can not handle image with %s=%d and %s=%d", + "Samples/pixel", td->td_samplesperpixel, + "Bits/sample", td->td_bitspersample); + return 0; + } break; default: sprintf(emsg, "Sorry, can not handle image with %s=%d", @@ -597,6 +612,10 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) int32 fromskew, toskew; uint32 nrow; int ret = 1, flip; + uint32 this_tw, tocol; + int32 this_toskew, leftmost_toskew; + int32 leftmost_fromskew; + uint32 leftmost_tw; buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif)); if (buf == 0) { @@ -617,37 +636,50 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) toskew = -(int32)(tw - w); } + /* + * Leftmost tile is clipped on left side if col_offset > 0. + */ + leftmost_fromskew = img->col_offset % tw; + leftmost_tw = tw - leftmost_fromskew; + leftmost_toskew = toskew + leftmost_fromskew; for (row = 0; row < h; row += nrow) { rowstoread = th - (row + img->row_offset) % th; nrow = (row + rowstoread > h ? h - row : rowstoread); - for (col = 0; col < w; col += tw) + fromskew = leftmost_fromskew; + this_tw = leftmost_tw; + this_toskew = leftmost_toskew; + tocol = 0; + col = img->col_offset; + while (tocol < w) { - if (TIFFReadTile(tif, buf, col+img->col_offset, + if (TIFFReadTile(tif, buf, col, row+img->row_offset, 0, 0)==(tmsize_t)(-1) && img->stoponerr) { ret = 0; break; } - - pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); - - 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 + pos); - } - else - { - (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); - } - } + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif) + \ + ((tmsize_t) fromskew * img->samplesperpixel); + if (tocol + this_tw > w) + { + /* + * Rightmost tile is clipped on right side. + */ + fromskew = tw - (w - tocol); + this_tw = tw - fromskew; + this_toskew = toskew + fromskew; + } + (*put)(img, raster+y*w+tocol, tocol, y, this_tw, nrow, fromskew, this_toskew, buf + pos); + tocol += this_tw; + col += this_tw; + /* + * After the leftmost tile, tiles are no longer clipped on left side. + */ + fromskew = 0; + this_tw = tw; + this_toskew = toskew; + } y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); } @@ -692,19 +724,29 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) unsigned char* p2; unsigned char* pa; tmsize_t tilesize; + tmsize_t bufsize; int32 fromskew, toskew; int alpha = img->alpha; uint32 nrow; int ret = 1, flip; int colorchannels; + uint32 this_tw, tocol; + int32 this_toskew, leftmost_toskew; + int32 leftmost_fromskew; + uint32 leftmost_tw; tilesize = TIFFTileSize(tif); - buf = (unsigned char*) _TIFFmalloc((alpha?4:3)*tilesize); + bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,tilesize); + if (bufsize == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtTileSeparate"); + return (0); + } + buf = (unsigned char*) _TIFFmalloc(bufsize); if (buf == 0) { TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer"); return (0); } - _TIFFmemset(buf, 0, (alpha?4:3)*tilesize); + _TIFFmemset(buf, 0, bufsize); p0 = buf; p1 = p0 + tilesize; p2 = p1 + tilesize; @@ -736,20 +778,31 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) break; } + /* + * Leftmost tile is clipped on left side if col_offset > 0. + */ + leftmost_fromskew = img->col_offset % tw; + leftmost_tw = tw - leftmost_fromskew; + leftmost_toskew = toskew + leftmost_fromskew; for (row = 0; row < h; row += nrow) { rowstoread = th - (row + img->row_offset) % th; nrow = (row + rowstoread > h ? h - row : rowstoread); - for (col = 0; col < w; col += tw) + fromskew = leftmost_fromskew; + this_tw = leftmost_tw; + this_toskew = leftmost_toskew; + tocol = 0; + col = img->col_offset; + while (tocol < w) { - if (TIFFReadTile(tif, p0, col+img->col_offset, + if (TIFFReadTile(tif, p0, col, row+img->row_offset,0,0)==(tmsize_t)(-1) && img->stoponerr) { ret = 0; break; } if (colorchannels > 1 - && TIFFReadTile(tif, p1, col+img->col_offset, + && TIFFReadTile(tif, p1, col, row+img->row_offset,0,1) == (tmsize_t)(-1) && img->stoponerr) { @@ -757,7 +810,7 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) break; } if (colorchannels > 1 - && TIFFReadTile(tif, p2, col+img->col_offset, + && TIFFReadTile(tif, p2, col, row+img->row_offset,0,2) == (tmsize_t)(-1) && img->stoponerr) { @@ -765,7 +818,7 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) break; } if (alpha - && TIFFReadTile(tif,pa,col+img->col_offset, + && TIFFReadTile(tif,pa,col, row+img->row_offset,0,colorchannels) == (tmsize_t)(-1) && img->stoponerr) { @@ -773,23 +826,27 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) break; } - pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); - - if (col + tw > w) + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif) + \ + ((tmsize_t) fromskew * img->samplesperpixel); + if (tocol + this_tw > w) { /* - * Tile is clipped horizontally. Calculate - * visible portion and skewing factors. + * Rightmost tile is clipped on right side. */ - uint32 npix = w - col; - fromskew = tw - npix; - (*put)(img, raster+y*w+col, col, y, - npix, nrow, fromskew, toskew + fromskew, - p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); - } else { - (*put)(img, raster+y*w+col, col, y, - tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + fromskew = tw - (w - tocol); + this_tw = tw - fromskew; + this_toskew = toskew + fromskew; } + (*put)(img, raster+y*w+tocol, tocol, y, this_tw, nrow, fromskew, this_toskew, \ + p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + tocol += this_tw; + col += this_tw; + /* + * After the leftmost tile, tiles are no longer clipped on left side. + */ + fromskew = 0; + this_tw = tw; + this_toskew = toskew; } y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); @@ -836,6 +893,12 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) int32 fromskew, toskew; int ret = 1, flip; + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); + if( subsamplingver == 0 ) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Invalid vertical YCbCr subsampling"); + return (0); + } + buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); @@ -853,7 +916,7 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) } TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); - TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); + scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += nrow) @@ -873,7 +936,8 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) break; } - pos = ((row + img->row_offset) % rowsperstrip) * scanline; + pos = ((row + img->row_offset) % rowsperstrip) * scanline + \ + ((tmsize_t) img->col_offset * img->samplesperpixel); (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); } @@ -917,17 +981,23 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) uint32 rowsperstrip, offset_row; uint32 imagewidth = img->width; tmsize_t stripsize; + tmsize_t bufsize; int32 fromskew, toskew; int alpha = img->alpha; int ret = 1, flip, colorchannels; stripsize = TIFFStripSize(tif); - p0 = buf = (unsigned char *)_TIFFmalloc((alpha?4:3)*stripsize); + bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,stripsize); + if (bufsize == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate"); + return (0); + } + p0 = buf = (unsigned char *)_TIFFmalloc(bufsize); if (buf == 0) { TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); return (0); } - _TIFFmemset(buf, 0, (alpha?4:3)*stripsize); + _TIFFmemset(buf, 0, bufsize); p1 = p0 + stripsize; p2 = p1 + stripsize; pa = (alpha?(p2+stripsize):NULL); @@ -998,7 +1068,8 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) } } - pos = ((row + img->row_offset) % rowsperstrip) * scanline; + pos = ((row + img->row_offset) % rowsperstrip) * scanline + \ + ((tmsize_t) img->col_offset * img->samplesperpixel); (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); @@ -1196,6 +1267,26 @@ DECLAREContigPutFunc(putgreytile) } } +/* + * 8-bit greyscale with associated alpha => colormap/RGBA + */ +DECLAREContigPutFunc(putagreytile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = BWmap[*pp][0] & (*(pp+1) << 24 | ~A1); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + /* * 16-bit greyscale => colormap/RGB */ @@ -1494,6 +1585,26 @@ DECLARESepPutFunc(putRGBAAseparate8bittile) } } +/* + * 8-bit unpacked CMYK samples => RGBA + */ +DECLARESepPutFunc(putCMYKseparate8bittile) +{ + (void) img; (void) y; + while (h-- > 0) { + uint32 rv, gv, bv, kv; + for (x = w; x-- > 0;) { + kv = 255 - *a++; + rv = (kv*(255-*r++))/255; + gv = (kv*(255-*g++))/255; + bv = (kv*(255-*b++))/255; + *cp++ = PACK4(rv,gv,bv,255); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + /* * 8-bit unpacked samples => RGBA w/ unassociated alpha */ @@ -1800,7 +1911,7 @@ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) (void) y; fromskew = (fromskew * 10) / 4; - if ((h & 3) == 0 && (w & 1) == 0) { + if ((w & 3) == 0 && (h & 1) == 0) { for (; h >= 2; h -= 2) { x = w>>2; do { @@ -1877,7 +1988,7 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) /* XXX adjust fromskew */ do { x = w>>2; - do { + while(x>0) { int32 Cb = pp[4]; int32 Cr = pp[5]; @@ -1888,7 +1999,8 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) cp += 4; pp += 6; - } while (--x); + x--; + } if( (w&3) != 0 ) { @@ -1979,7 +2091,7 @@ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) fromskew = (fromskew * 4) / 2; do { x = w>>1; - do { + while(x>0) { int32 Cb = pp[2]; int32 Cr = pp[3]; @@ -1988,7 +2100,8 @@ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) cp += 2; pp += 4; - } while (--x); + x --; + } if( (w&1) != 0 ) { @@ -2461,7 +2574,10 @@ PickContigCase(TIFFRGBAImage* img) img->put.contig = put16bitbwtile; break; case 8: - img->put.contig = putgreytile; + if (img->alpha && img->samplesperpixel == 2) + img->put.contig = putagreytile; + else + img->put.contig = putgreytile; break; case 4: img->put.contig = put4bitbwtile; @@ -2486,7 +2602,7 @@ PickContigCase(TIFFRGBAImage* img) * must always be <= horizontal subsampling; so * there are only a few possibilities and we just * enumerate the cases. - * Joris: added support for the [1,2] case, nonetheless, to accomodate + * Joris: added support for the [1,2] case, nonetheless, to accommodate * some OJPEG files */ uint16 SubsamplingHor; @@ -2540,58 +2656,65 @@ PickSeparateCase(TIFFRGBAImage* img) img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; img->put.separate = NULL; switch (img->photometric) { - case PHOTOMETRIC_MINISWHITE: - case PHOTOMETRIC_MINISBLACK: - /* greyscale images processed pretty much as RGB by gtTileSeparate */ - case PHOTOMETRIC_RGB: - switch (img->bitspersample) { - case 8: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - img->put.separate = putRGBAAseparate8bittile; - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - if (BuildMapUaToAa(img)) - img->put.separate = putRGBUAseparate8bittile; - } - else - img->put.separate = putRGBseparate8bittile; - break; - case 16: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - { - if (BuildMapBitdepth16To8(img)) - img->put.separate = putRGBAAseparate16bittile; - } - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - if (BuildMapBitdepth16To8(img) && - BuildMapUaToAa(img)) - img->put.separate = putRGBUAseparate16bittile; - } - else - { - if (BuildMapBitdepth16To8(img)) - img->put.separate = putRGBseparate16bittile; - } - break; + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + /* greyscale images processed pretty much as RGB by gtTileSeparate */ + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.separate = putRGBAAseparate8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate8bittile; + } + else + img->put.separate = putRGBseparate8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBAAseparate16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapBitdepth16To8(img) && + BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate16bittile; + } + else + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBseparate16bittile; } break; - case PHOTOMETRIC_YCBCR: - if ((img->bitspersample==8) && (img->samplesperpixel==3)) + } + break; + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8 && img->samplesperpixel == 4) + { + img->alpha = 1; // Not alpha, but seems like the only way to get 4th band + img->put.separate = putCMYKseparate8bittile; + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample==8) && (img->samplesperpixel==3)) + { + if (initYCbCrConversion(img)!=0) { - if (initYCbCrConversion(img)!=0) - { - uint16 hs, vs; - TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); - switch ((hs<<4)|vs) { - case 0x11: - img->put.separate = putseparate8bitYCbCr11tile; - break; - /* TODO: add other cases here */ - } + uint16 hs, vs; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); + switch ((hs<<4)|vs) { + case 0x11: + img->put.separate = putseparate8bitYCbCr11tile; + break; + /* TODO: add other cases here */ } } - break; + } + break; } return ((img->get!=NULL) && (img->put.separate!=NULL)); } diff --git a/thirdparty/libtiff/tif_jpeg.c b/thirdparty/libtiff/tif_jpeg.c index f0e0aab8..d9276caf 100644 --- a/thirdparty/libtiff/tif_jpeg.c +++ b/thirdparty/libtiff/tif_jpeg.c @@ -1,4 +1,4 @@ -/* $Id: tif_jpeg.c,v 1.105 2012-02-01 01:51:00 fwarmerdam Exp $ */ +/* $Id: tif_jpeg.c,v 1.118 2015-06-10 13:17:41 bfriesen Exp $ */ /* * Copyright (c) 1994-1997 Sam Leffler @@ -658,7 +658,9 @@ alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, #define JPEG_MARKER_SOF0 0xC0 #define JPEG_MARKER_SOF1 0xC1 -#define JPEG_MARKER_SOF3 0xC3 +#define JPEG_MARKER_SOF2 0xC2 +#define JPEG_MARKER_SOF9 0xC9 +#define JPEG_MARKER_SOF10 0xCA #define JPEG_MARKER_DHT 0xC4 #define JPEG_MARKER_SOI 0xD8 #define JPEG_MARKER_SOS 0xDA @@ -729,6 +731,7 @@ JPEGFixupTagsSubsampling(TIFF* tif) _TIFFFillStriles( tif ); if( tif->tif_dir.td_stripbytecount == NULL + || tif->tif_dir.td_stripoffset == NULL || tif->tif_dir.td_stripbytecount[0] == 0 ) { /* Do not even try to check if the first strip/tile does not @@ -816,8 +819,11 @@ JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data) JPEGFixupTagsSubsamplingSkip(data,n); } break; - case JPEG_MARKER_SOF0: - case JPEG_MARKER_SOF1: + case JPEG_MARKER_SOF0: /* Baseline sequential Huffman */ + case JPEG_MARKER_SOF1: /* Extended sequential Huffman */ + case JPEG_MARKER_SOF2: /* Progressive Huffman: normally not allowed by TechNote, but that doesn't hurt supporting it */ + case JPEG_MARKER_SOF9: /* Extended sequential arithmetic */ + case JPEG_MARKER_SOF10: /* Progressive arithmetic: normally not allowed by TechNote, but that doesn't hurt supporting it */ /* this marker contains the subsampling factors we're scanning for */ { uint16 n; @@ -992,7 +998,7 @@ JPEGSetupDecode(TIFF* tif) /* * Set up for decoding a strip or tile. */ -static int +/*ARGSUSED*/ static int JPEGPreDecode(TIFF* tif, uint16 s) { JPEGState *sp = JState(tif); @@ -1095,50 +1101,13 @@ JPEGPreDecode(TIFF* tif, uint16 s) /* 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) { - TIFFWarningExt(tif->tif_clientdata, module, - "Improper JPEG sampling factors %d,%d\n" - "Apparently should be %d,%d.", - sp->cinfo.d.comp_info[0].h_samp_factor, - sp->cinfo.d.comp_info[0].v_samp_factor, - sp->h_sampling, sp->v_sampling); - - /* - * There are potential security issues here - * for decoders that have already allocated - * buffers based on the expected sampling - * factors. Lets check the sampling factors - * dont exceed what we were expecting. - */ - 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) { - TIFFErrorExt(tif->tif_clientdata, - module, - "Cannot honour JPEG sampling factors" - " that exceed those specified."); - return (0); - } - - /* - * XXX: Files written by the Intergraph software - * has different sampling factors stored in the - * TIFF tags and in the JPEG structures. We will - * try to deduce Intergraph files by the presense - * of the tag 33918. - */ - if (!TIFFFindField(tif, 33918, TIFF_ANY)) { - TIFFWarningExt(tif->tif_clientdata, module, - "Decompressor will try reading with " - "sampling %d,%d.", - sp->cinfo.d.comp_info[0].h_samp_factor, - sp->cinfo.d.comp_info[0].v_samp_factor); - - sp->h_sampling = (uint16) - sp->cinfo.d.comp_info[0].h_samp_factor; - sp->v_sampling = (uint16) - sp->cinfo.d.comp_info[0].v_samp_factor; - } + TIFFErrorExt(tif->tif_clientdata, module, + "Improper JPEG sampling factors %d,%d\n" + "Apparently should be %d,%d.", + sp->cinfo.d.comp_info[0].h_samp_factor, + sp->cinfo.d.comp_info[0].v_samp_factor, + sp->h_sampling, sp->v_sampling); + return (0); } /* Rest should have sampling factors 1,1 */ for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { @@ -1160,11 +1129,11 @@ JPEGPreDecode(TIFF* tif, uint16 s) if (td->td_planarconfig == PLANARCONFIG_CONTIG && sp->photometric == PHOTOMETRIC_YCBCR && sp->jpegcolormode == JPEGCOLORMODE_RGB) { - /* Convert YCbCr to 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 */ + /* 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 && @@ -1175,6 +1144,9 @@ JPEGPreDecode(TIFF* tif, uint16 s) if (downsampled_output) { /* Need to use raw-data interface to libjpeg */ sp->cinfo.d.raw_data_out = TRUE; +#if JPEG_LIB_VERSION >= 70 + sp->cinfo.d.do_fancy_upsampling = FALSE; +#endif /* JPEG_LIB_VERSION >= 70 */ tif->tif_decoderow = DecodeRowError; tif->tif_decodestrip = JPEGDecodeRaw; tif->tif_decodetile = JPEGDecodeRaw; @@ -1202,6 +1174,63 @@ JPEGPreDecode(TIFF* tif, uint16 s) * Decode a chunk of pixels. * "Standard" case: returned data is not downsampled. */ +#if !JPEG_LIB_MK1_OR_12BIT +static int +JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + (void) s; + + /* + ** Update available information, buffer may have been refilled + ** between decode requests + */ + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; + + if( sp->bytesperline == 0 ) + return 0; + + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline not read"); + + if( nrows > (tmsize_t) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) + { + do + { + /* + * In the libjpeg6b-9a 8bit case. We read directly into + * the TIFF buffer. + */ + JSAMPROW bufptr = (JSAMPROW)buf; + + if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) + return (0); + + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); + } + + /* Update information on consumed data */ + tif->tif_rawcp = (uint8*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* Close down the decompressor if we've finished the strip or tile. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} +#endif /* !JPEG_LIB_MK1_OR_12BIT */ + +#if JPEG_LIB_MK1_OR_12BIT /*ARGSUSED*/ static int JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) { @@ -1221,91 +1250,81 @@ JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) nrows = cc / sp->bytesperline; if (cc % sp->bytesperline) - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read"); + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline not read"); if( nrows > (tmsize_t) sp->cinfo.d.image_height ) nrows = sp->cinfo.d.image_height; /* data is expected to be read in multiples of a scanline */ if (nrows) - { - JSAMPROW line_work_buf = NULL; + { + JSAMPROW line_work_buf = NULL; - /* - * For 6B, only use temporary buffer for 12 bit imagery. - * For Mk1 always use it. - */ -#if !defined(JPEG_LIB_MK1) - if( sp->cinfo.d.data_precision == 12 ) -#endif - { - line_work_buf = (JSAMPROW) - _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width - * sp->cinfo.d.num_components ); - } + /* + * For 6B, only use temporary buffer for 12 bit imagery. + * For Mk1 always use it. + */ + if( sp->cinfo.d.data_precision == 12 ) + { + line_work_buf = (JSAMPROW) + _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width + * sp->cinfo.d.num_components ); + } - do { - if( line_work_buf != NULL ) - { - /* - * In the MK1 case, we aways read into a 16bit buffer, and then - * pack down to 12bit or 8bit. In 6B case we only read into 16 - * bit buffer for 12bit data, which we need to repack. - */ - if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) - return (0); + do + { + if( line_work_buf != NULL ) + { + /* + * In the MK1 case, we aways read into a 16bit + * buffer, and then pack down to 12bit or 8bit. + * In 6B case we only read into 16 bit buffer + * for 12bit data, which we need to repack. + */ + if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) + return (0); - if( sp->cinfo.d.data_precision == 12 ) - { - int value_pairs = (sp->cinfo.d.output_width - * sp->cinfo.d.num_components) / 2; - int iPair; + if( sp->cinfo.d.data_precision == 12 ) + { + int value_pairs = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; - for( iPair = 0; iPair < value_pairs; iPair++ ) - { - unsigned char *out_ptr = - ((unsigned char *) buf) + iPair * 3; - JSAMPLE *in_ptr = line_work_buf + iPair * 2; + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = line_work_buf + iPair * 2; - out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; - out_ptr[1] = ((in_ptr[0] & 0xf) << 4) - | ((in_ptr[1] & 0xf00) >> 8); - out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); - } - } - else if( sp->cinfo.d.data_precision == 8 ) - { - int value_count = (sp->cinfo.d.output_width - * sp->cinfo.d.num_components); - int iValue; + out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; + out_ptr[1] = ((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8); + out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); + } + } + else if( sp->cinfo.d.data_precision == 8 ) + { + int value_count = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components); + int iValue; - for( iValue = 0; iValue < value_count; iValue++ ) - { - ((unsigned char *) buf)[iValue] = - line_work_buf[iValue] & 0xff; - } - } - } - else - { - /* - * In the libjpeg6b 8bit case. We read directly into the - * TIFF buffer. - */ - JSAMPROW bufptr = (JSAMPROW)buf; + for( iValue = 0; iValue < value_count; iValue++ ) + { + ((unsigned char *) buf)[iValue] = + line_work_buf[iValue] & 0xff; + } + } + } - if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) - return (0); - } + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); - ++tif->tif_row; - buf += sp->bytesperline; - cc -= sp->bytesperline; - } while (--nrows > 0); - - if( line_work_buf != NULL ) - _TIFFfree( line_work_buf ); - } + if( line_work_buf != NULL ) + _TIFFfree( line_work_buf ); + } /* Update information on consumed data */ tif->tif_rawcp = (uint8*) sp->src.next_input_byte; @@ -1313,8 +1332,9 @@ JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) /* Close down the decompressor if we've finished the strip or tile. */ return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height - || TIFFjpeg_finish_decompress(sp); + || TIFFjpeg_finish_decompress(sp); } +#endif /* JPEG_LIB_MK1_OR_12BIT */ /*ARGSUSED*/ static int DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) @@ -1349,8 +1369,8 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) #if defined(JPEG_LIB_MK1_OR_12BIT) unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) * - sp->cinfo.d.output_width * - sp->cinfo.d.num_components); + sp->cinfo.d.output_width * + sp->cinfo.d.num_components); if(tmpbuf==NULL) { TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", "Out of memory"); @@ -1362,10 +1382,10 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) jpeg_component_info *compptr; int ci, clumpoffset; - if( cc < sp->bytesperline * sp->v_sampling ) { - TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", - "application buffer not large enough for all data."); - return 0; + if( cc < sp->bytesperline ) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data."); + return 0; } /* Reload downsampled-data buffer if needed */ @@ -1381,20 +1401,25 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) */ clumpoffset = 0; /* first sample in clump */ for (ci = 0, compptr = sp->cinfo.d.comp_info; - ci < sp->cinfo.d.num_components; - ci++, compptr++) { + ci < sp->cinfo.d.num_components; + ci++, compptr++) { int hsamp = compptr->h_samp_factor; int vsamp = compptr->v_samp_factor; int ypos; for (ypos = 0; ypos < vsamp; ypos++) { JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + JDIMENSION nclump; #if defined(JPEG_LIB_MK1_OR_12BIT) JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset; #else JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset; + if (cc < (tmsize_t) (clumpoffset + samples_per_clump*(clumps_per_line-1) + hsamp)) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data, possible subsampling issue"); + return 0; + } #endif - JDIMENSION nclump; if (hsamp == 1) { /* fast path for at least Cb and Cr */ @@ -1405,7 +1430,7 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) } else { int xpos; - /* general case */ + /* general case */ for (nclump = clumps_per_line; nclump-- > 0; ) { for (xpos = 0; xpos < hsamp; xpos++) outptr[xpos] = *inptr++; @@ -1428,9 +1453,9 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) } } else - { /* 12-bit */ + { /* 12-bit */ int value_pairs = (sp->cinfo.d.output_width - * sp->cinfo.d.num_components) / 2; + * sp->cinfo.d.num_components) / 2; int iPair; for( iPair = 0; iPair < value_pairs; iPair++ ) { @@ -1438,7 +1463,7 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) JSAMPLE *in_ptr = (JSAMPLE *) (tmpbuf + iPair * 2); out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; out_ptr[1] = ((in_ptr[0] & 0xf) << 4) - | ((in_ptr[1] & 0xf00) >> 8); + | ((in_ptr[1] & 0xf00) >> 8); out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); } } @@ -1447,12 +1472,9 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) sp->scancount ++; tif->tif_row += sp->v_sampling; -/* - buf += clumps_per_line*samples_per_clump; - cc -= clumps_per_line*samples_per_clump; -*/ - buf += sp->bytesperline * sp->v_sampling; - cc -= sp->bytesperline * sp->v_sampling; + + buf += sp->bytesperline; + cc -= sp->bytesperline; nrows -= sp->v_sampling; } while (nrows > 0); @@ -1465,7 +1487,7 @@ JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) /* Close down the decompressor if done. */ return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height - || TIFFjpeg_finish_decompress(sp); + || TIFFjpeg_finish_decompress(sp); } @@ -1482,6 +1504,15 @@ unsuppress_quant_table (JPEGState* sp, int tblno) qtbl->sent_table = FALSE; } +static void +suppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = TRUE; +} + static void unsuppress_huff_table (JPEGState* sp, int tblno) { @@ -1493,6 +1524,17 @@ unsuppress_huff_table (JPEGState* sp, int tblno) htbl->sent_table = FALSE; } +static void +suppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = TRUE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = TRUE; +} + static int prepare_JPEGTables(TIFF* tif) { @@ -1542,17 +1584,38 @@ JPEGSetupEncode(TIFF* tif) assert(sp != NULL); assert(!sp->cinfo.comm.is_decompressor); + sp->photometric = td->td_photometric; + /* * 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 (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; + } + } else { + if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1) + sp->cinfo.c.in_color_space = JCS_GRAYSCALE; + else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3) + sp->cinfo.c.in_color_space = JCS_RGB; + else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4) + sp->cinfo.c.in_color_space = JCS_CMYK; + else + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + } 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]; @@ -1712,10 +1775,7 @@ JPEGPreEncode(TIFF* tif, uint16 s) 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->jpegcolormode != JPEGCOLORMODE_RGB) { if (sp->h_sampling != 1 || sp->v_sampling != 1) downsampled_input = TRUE; } @@ -1728,21 +1788,11 @@ JPEGPreEncode(TIFF* tif, uint16 s) 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 { - if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1) - sp->cinfo.c.in_color_space = JCS_GRAYSCALE; - else if (td->td_photometric == PHOTOMETRIC_RGB) - sp->cinfo.c.in_color_space = JCS_RGB; - else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4) - sp->cinfo.c.in_color_space = JCS_CMYK; - else - sp->cinfo.c.in_color_space = JCS_UNKNOWN; if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space)) 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; @@ -1757,14 +1807,30 @@ JPEGPreEncode(TIFF* tif, uint16 s) sp->cinfo.c.write_JFIF_header = FALSE; sp->cinfo.c.write_Adobe_marker = FALSE; /* set up table handling correctly */ - if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + /* calling TIFFjpeg_set_quality() causes quantization tables to be flagged */ + /* as being to be emitted, which we don't want in the JPEGTABLESMODE_QUANT */ + /* mode, so we must manually suppress them. However TIFFjpeg_set_quality() */ + /* should really be called when dealing with files with directories with */ + /* mixed qualities. see http://trac.osgeo.org/gdal/ticket/3539 */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) return (0); - if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + suppress_quant_table(sp, 0); + suppress_quant_table(sp, 1); + } + else { unsuppress_quant_table(sp, 0); unsuppress_quant_table(sp, 1); } if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + { + /* Explicit suppression is only needed if we did not go through the */ + /* prepare_JPEGTables() code path, which may be the case if updating */ + /* an existing file */ + suppress_huff_table(sp, 0); + suppress_huff_table(sp, 1); sp->cinfo.c.optimize_coding = FALSE; + } else sp->cinfo.c.optimize_coding = TRUE; if (downsampled_input) { @@ -1998,13 +2064,10 @@ JPEGCleanup(TIFF* tif) tif->tif_tagmethods.vgetfield = sp->vgetparent; tif->tif_tagmethods.vsetfield = sp->vsetparent; tif->tif_tagmethods.printdir = sp->printdir; - - if( sp != NULL ) { - if( sp->cinfo_initialized ) - TIFFjpeg_destroy(sp); /* release libjpeg resources */ - if (sp->jpegtables) /* tag value */ - _TIFFfree(sp->jpegtables); - } + if( sp->cinfo_initialized ) + 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; diff --git a/thirdparty/libtiff/tif_luv.c b/thirdparty/libtiff/tif_luv.c index eba6c08e..4e328bad 100644 --- a/thirdparty/libtiff/tif_luv.c +++ b/thirdparty/libtiff/tif_luv.c @@ -1,4 +1,4 @@ -/* $Id: tif_luv.c,v 1.35 2011-04-02 20:54:09 bfriesen Exp $ */ +/* $Id: tif_luv.c,v 1.40 2015-06-21 01:09:09 bfriesen Exp $ */ /* * Copyright (c) 1997 Greg Ward Larson @@ -379,6 +379,9 @@ LogLuvDecodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) { tmsize_t rowlen = TIFFScanlineSize(tif); + if (rowlen == 0) + return 0; + assert(cc%rowlen == 0); while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) bp += rowlen, cc -= rowlen; @@ -395,6 +398,9 @@ LogLuvDecodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) { tmsize_t rowlen = TIFFTileRowSize(tif); + if (rowlen == 0) + return 0; + assert(cc%rowlen == 0); while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) bp += rowlen, cc -= rowlen; @@ -644,6 +650,9 @@ LogLuvEncodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) { tmsize_t rowlen = TIFFScanlineSize(tif); + if (rowlen == 0) + return 0; + assert(cc%rowlen == 0); while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) bp += rowlen, cc -= rowlen; @@ -659,6 +668,9 @@ LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) { tmsize_t rowlen = TIFFTileRowSize(tif); + if (rowlen == 0) + return 0; + assert(cc%rowlen == 0); while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) bp += rowlen, cc -= rowlen; @@ -683,7 +695,9 @@ LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) #ifndef M_PI #define M_PI 3.14159265358979323846 #endif +#undef log2 /* Conflict with C'99 function */ #define log2(x) ((1./M_LN2)*log(x)) +#undef exp2 /* Conflict with C'99 function */ #define exp2(x) exp(M_LN2*(x)) #define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \ diff --git a/thirdparty/libtiff/tif_lzw.c b/thirdparty/libtiff/tif_lzw.c index fd9c7a0a..58345f0a 100644 --- a/thirdparty/libtiff/tif_lzw.c +++ b/thirdparty/libtiff/tif_lzw.c @@ -1,4 +1,4 @@ -/* $Id: tif_lzw.c,v 1.45 2011-04-02 20:54:09 bfriesen Exp $ */ +/* $Id: tif_lzw.c,v 1.47 2015-06-13 05:03:50 faxguy Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -268,6 +268,8 @@ LZWPreDecode(TIFF* tif, uint16 s) if( sp->dec_codetab == NULL ) { tif->tif_setupdecode( tif ); + if( sp->dec_codetab == NULL ) + return (0); } /* @@ -434,16 +436,18 @@ LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) if (code == CODE_EOI) break; if (code == CODE_CLEAR) { - free_entp = sp->dec_codetab + CODE_FIRST; - _TIFFmemset(free_entp, 0, - (CSIZE - CODE_FIRST) * sizeof (code_t)); - nbits = BITS_MIN; - nbitsmask = MAXCODE(BITS_MIN); - maxcodep = sp->dec_codetab + nbitsmask-1; - NextCode(tif, sp, bp, code, GetNextCode); + do { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + NextCode(tif, sp, bp, code, GetNextCode); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ if (code == CODE_EOI) break; - if (code >= CODE_CLEAR) { + if (code > CODE_CLEAR) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "LZWDecode: Corrupted LZW table at scanline %d", tif->tif_row); @@ -653,16 +657,18 @@ LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) if (code == CODE_EOI) break; if (code == CODE_CLEAR) { - free_entp = sp->dec_codetab + CODE_FIRST; - _TIFFmemset(free_entp, 0, - (CSIZE - CODE_FIRST) * sizeof (code_t)); - nbits = BITS_MIN; - nbitsmask = MAXCODE(BITS_MIN); - maxcodep = sp->dec_codetab + nbitsmask; - NextCode(tif, sp, bp, code, GetNextCodeCompat); + do { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ if (code == CODE_EOI) break; - if (code >= CODE_CLEAR) { + if (code > CODE_CLEAR) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "LZWDecode: Corrupted LZW table at scanline %d", tif->tif_row); diff --git a/thirdparty/libtiff/tif_next.c b/thirdparty/libtiff/tif_next.c index 524e127c..17e03111 100644 --- a/thirdparty/libtiff/tif_next.c +++ b/thirdparty/libtiff/tif_next.c @@ -1,4 +1,4 @@ -/* $Id: tif_next.c,v 1.13 2010-03-10 18:56:48 bfriesen Exp $ */ +/* $Id: tif_next.c,v 1.16 2014-12-29 12:09:11 erouault Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -71,7 +71,7 @@ NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); return (0); } - for (row = buf; occ > 0; occ -= scanline, row += scanline) { + for (row = buf; cc > 0 && occ > 0; occ -= scanline, row += scanline) { n = *bp++, cc--; switch (n) { case LITERALROW: @@ -90,6 +90,8 @@ NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) * The scanline has a literal span that begins at some * offset. */ + if( cc < 4 ) + goto bad; off = (bp[0] * 256) + bp[1]; n = (bp[2] * 256) + bp[3]; if (cc < 4+n || off+n > scanline) @@ -102,6 +104,8 @@ NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) default: { uint32 npixels = 0, grey; uint32 imagewidth = tif->tif_dir.td_imagewidth; + if( isTiled(tif) ) + imagewidth = tif->tif_dir.td_tilewidth; /* * The scanline is composed of a sequence of constant @@ -139,10 +143,27 @@ bad: return (0); } +static int +NeXTPreDecode(TIFF* tif, uint16 s) +{ + static const char module[] = "NeXTPreDecode"; + TIFFDirectory *td = &tif->tif_dir; + (void)s; + + if( td->td_bitspersample != 2 ) + { + TIFFErrorExt(tif->tif_clientdata, module, "Unsupported BitsPerSample = %d", + td->td_bitspersample); + return (0); + } + return (1); +} + int TIFFInitNeXT(TIFF* tif, int scheme) { (void) scheme; + tif->tif_predecode = NeXTPreDecode; tif->tif_decoderow = NeXTDecode; tif->tif_decodestrip = NeXTDecode; tif->tif_decodetile = NeXTDecode; diff --git a/thirdparty/libtiff/tif_ojpeg.c b/thirdparty/libtiff/tif_ojpeg.c index 0c9301d9..23d40622 100644 --- a/thirdparty/libtiff/tif_ojpeg.c +++ b/thirdparty/libtiff/tif_ojpeg.c @@ -1,4 +1,4 @@ -/* $Id: tif_ojpeg.c,v 1.54 2011-05-31 17:05:07 bfriesen Exp $ */ +/* $Id: tif_ojpeg.c,v 1.60 2015-05-31 00:38:46 bfriesen Exp $ */ /* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 specification is now totally obsolete and deprecated for new applications and @@ -39,7 +39,7 @@ OF THIS SOFTWARE. Joris Van Damme and/or AWare Systems may be available for custom - developement. If you like what you see, and need anything similar or related, + development. If you like what you see, and need anything similar or related, contact . */ @@ -141,7 +141,7 @@ * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee * instant processing, optimal streaming and optimal use of processor cache, but also big * enough so as to not result in significant call overhead. It should be at least a few - * bytes to accomodate some structures (this is verified in asserts), but it would not be + * bytes to accommodate some structures (this is verified in asserts), but it would not be * sensible to make it this small anyway, and it should be at most 64K since it is indexed * with uint16. We recommend 2K. * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has @@ -528,6 +528,8 @@ OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap) uint32 ma; uint64* mb; uint32 n; + const TIFFField* fip; + switch(tag) { case TIFFTAG_JPEGIFOFFSET: @@ -597,7 +599,10 @@ OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap) default: return (*sp->vsetparent)(tif,tag,ap); } - TIFFSetFieldBit(tif,TIFFFieldWithTag(tif,tag)->field_bit); + fip = TIFFFieldWithTag(tif,tag); + if( fip == NULL ) /* shouldn't happen */ + return(0); + TIFFSetFieldBit(tif,fip->field_bit); tif->tif_flags|=TIFF_DIRTYDIRECT; return(1); } @@ -1146,7 +1151,9 @@ OJPEGWriteHeaderInfo(TIFF* tif) OJPEGState* sp=(OJPEGState*)tif->tif_data; uint8** m; uint32 n; - assert(sp->libjpeg_session_active==0); + /* if a previous attempt failed, don't try again */ + if (sp->libjpeg_session_active != 0) + return 0; sp->out_state=ososSoi; sp->restart_index=0; jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); @@ -1490,14 +1497,17 @@ OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) nb[sizeof(uint32)+1]=JPEG_MARKER_DHT; nb[sizeof(uint32)+2]=(m>>8); nb[sizeof(uint32)+3]=(m&255); - if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) + if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) { + _TIFFfree(nb); return(0); + } o=nb[sizeof(uint32)+4]; if ((o&240)==0) { if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + _TIFFfree(nb); return(0); } if (sp->dctable[o]!=0) @@ -1509,12 +1519,14 @@ OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) if ((o&240)!=16) { TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + _TIFFfree(nb); return(0); } o&=15; if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + _TIFFfree(nb); return(0); } if (sp->actable[o]!=0) @@ -1953,7 +1965,13 @@ OJPEGReadBufferFill(OJPEGState* sp) break; case osibsJpegInterchangeFormat: sp->in_buffer_source=osibsStrile; + break; case osibsStrile: + if (!_TIFFFillStriles( sp->tif ) + || sp->tif->tif_dir.td_stripoffset == NULL + || sp->tif->tif_dir.td_stripbytecount == NULL) + return 0; + if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) sp->in_buffer_source=osibsEof; else diff --git a/thirdparty/libtiff/tif_packbits.c b/thirdparty/libtiff/tif_packbits.c index a79abe86..9e771901 100644 --- a/thirdparty/libtiff/tif_packbits.c +++ b/thirdparty/libtiff/tif_packbits.c @@ -1,4 +1,4 @@ -/* $Id: tif_packbits.c,v 1.20 2010-03-10 18:56:49 bfriesen Exp $ */ +/* $Id: tif_packbits.c,v 1.22 2012-06-20 05:25:33 fwarmerdam Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -241,7 +241,7 @@ PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) n = (long)occ; } occ -= n; - b = *bp++, cc--; /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */ + b = *bp++, cc--; while (n-- > 0) *op++ = (uint8) b; } else { /* copy next n+1 bytes literally */ @@ -252,7 +252,13 @@ PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) (unsigned long) ((tmsize_t)n - occ + 1)); n = (long)occ - 1; } - _TIFFmemcpy(op, bp, ++n); /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */ + if (cc < (tmsize_t) (n+1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Terminating PackBitsDecode due to lack of data."); + break; + } + _TIFFmemcpy(op, bp, ++n); op += n; occ -= n; bp += n; cc -= n; } diff --git a/thirdparty/libtiff/tif_pixarlog.c b/thirdparty/libtiff/tif_pixarlog.c index d8123e8d..044c4115 100644 --- a/thirdparty/libtiff/tif_pixarlog.c +++ b/thirdparty/libtiff/tif_pixarlog.c @@ -1,4 +1,4 @@ -/* $Id: tif_pixarlog.c,v 1.35 2011-01-06 16:00:23 fwarmerdam Exp $ */ +/* $Id: tif_pixarlog.c,v 1.39 2012-12-10 17:27:13 tgl Exp $ */ /* * Copyright (c) 1996-1997 Sam Leffler @@ -120,9 +120,9 @@ horizontalAccumulateF(uint16 *wp, int n, int stride, float *op, if (n >= stride) { mask = CODE_MASK; if (stride == 3) { - t0 = ToLinearF[cr = wp[0]]; - t1 = ToLinearF[cg = wp[1]]; - t2 = ToLinearF[cb = wp[2]]; + 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; @@ -139,10 +139,10 @@ horizontalAccumulateF(uint16 *wp, int n, int stride, float *op, 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]]; + 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; @@ -186,9 +186,9 @@ horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op, 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; + 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); @@ -205,10 +205,10 @@ horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op, 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; + 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); @@ -250,9 +250,9 @@ horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op, 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]]; + op[0] = ToLinear16[cr = (wp[0] & mask)]; + op[1] = ToLinear16[cg = (wp[1] & mask)]; + op[2] = ToLinear16[cb = (wp[2] & mask)]; n -= 3; while (n > 0) { wp += 3; @@ -263,10 +263,10 @@ horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op, 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]]; + 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)]; n -= 4; while (n > 0) { wp += 4; @@ -345,9 +345,9 @@ horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op, 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]]; + op[0] = ToLinear8[cr = (wp[0] & mask)]; + op[1] = ToLinear8[cg = (wp[1] & mask)]; + op[2] = ToLinear8[cb = (wp[2] & mask)]; n -= 3; while (n > 0) { n -= 3; @@ -358,10 +358,10 @@ horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op, 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]]; + 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)]; n -= 4; while (n > 0) { n -= 4; @@ -396,9 +396,9 @@ horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, mask = CODE_MASK; if (stride == 3) { op[0] = 0; - t1 = ToLinear8[cb = wp[2]]; - t2 = ToLinear8[cg = wp[1]]; - t3 = ToLinear8[cr = wp[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; @@ -416,10 +416,10 @@ horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, 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]]; + 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; @@ -644,6 +644,20 @@ multiply_ms(tmsize_t m1, tmsize_t m2) return bytes; } +static tmsize_t +add_ms(tmsize_t m1, tmsize_t m2) +{ + tmsize_t bytes = m1 + m2; + + /* if either input is zero, assume overflow already occurred */ + if (m1 == 0 || m2 == 0) + bytes = 0; + else if (bytes <= m1 || bytes <= m2) + bytes = 0; + + return bytes; +} + static int PixarLogFixupTags(TIFF* tif) { @@ -671,6 +685,8 @@ PixarLogSetupDecode(TIFF* tif) td->td_samplesperpixel : 1); tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), td->td_rowsperstrip), sizeof(uint16)); + /* add one more stride in case input ends mid-stride */ + tbuf_size = add_ms(tbuf_size, sizeof(uint16) * sp->stride); if (tbuf_size == 0) return (0); /* TODO: this is an error return without error report through TIFFErrorExt */ sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size); diff --git a/thirdparty/libtiff/tif_print.c b/thirdparty/libtiff/tif_print.c index 9481eb62..9e27ae25 100644 --- a/thirdparty/libtiff/tif_print.c +++ b/thirdparty/libtiff/tif_print.c @@ -1,4 +1,4 @@ -/* $Id: tif_print.c,v 1.54 2011-04-02 20:54:09 bfriesen Exp $ */ +/* $Id: tif_print.c,v 1.61 2012-12-12 22:50:18 tgl Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -34,6 +34,9 @@ #include +static void +_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars); + static const char *photoNames[] = { "min-is-white", /* PHOTOMETRIC_MINISWHITE */ "min-is-black", /* PHOTOMETRIC_MINISBLACK */ @@ -44,6 +47,8 @@ static const char *photoNames[] = { "YCbCr", /* PHOTOMETRIC_YCBCR */ "7 (0x7)", "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ + "ICC L*a*b*", /* PHOTOMETRIC_ICCLAB */ + "ITU L*a*b*" /* PHOTOMETRIC_ITULAB */ }; #define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0])) @@ -135,34 +140,51 @@ _TIFFPrintField(FILE* fd, const TIFFField *fip, } static int -_TIFFPrettyPrintField(TIFF* tif, FILE* fd, uint32 tag, +_TIFFPrettyPrintField(TIFF* tif, const TIFFField *fip, FILE* fd, uint32 tag, uint32 value_count, void *raw_data) { (void) tif; + + /* do not try to pretty print auto-defined fields */ + if (strncmp(fip->field_name,"Tag ", 4) == 0) { + return 0; + } switch (tag) { case TIFFTAG_INKSET: - fprintf(fd, " Ink Set: "); - switch (*((uint16*)raw_data)) { + if (value_count == 2 && fip->field_type == TIFF_SHORT) { + fprintf(fd, " Ink Set: "); + switch (*((uint16*)raw_data)) { case INKSET_CMYK: fprintf(fd, "CMYK\n"); break; default: fprintf(fd, "%u (0x%x)\n", - *((uint16*)raw_data), - *((uint16*)raw_data)); + *((uint16*)raw_data), + *((uint16*)raw_data)); break; + } + return 1; } - return 1; + return 0; + case TIFFTAG_DOTRANGE: - fprintf(fd, " Dot Range: %u-%u\n", - ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); - return 1; + if (value_count == 2 && fip->field_type == TIFF_SHORT) { + fprintf(fd, " Dot Range: %u-%u\n", + ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); + return 1; + } + return 0; + case TIFFTAG_WHITEPOINT: - fprintf(fd, " White Point: %g-%g\n", - ((float *)raw_data)[0], ((float *)raw_data)[1]); - return 1; + if (value_count == 2 && fip->field_type == TIFF_RATIONAL) { + fprintf(fd, " White Point: %g-%g\n", + ((float *)raw_data)[0], ((float *)raw_data)[1]); + return 1; + } + return 0; + case TIFFTAG_XMLPACKET: { uint32 i; @@ -182,19 +204,25 @@ _TIFFPrettyPrintField(TIFF* tif, FILE* fd, uint32 tag, " RichTIFFIPTC Data: , %lu bytes\n", (unsigned long) value_count * 4); return 1; + case TIFFTAG_PHOTOSHOP: fprintf(fd, " Photoshop Data: , %lu bytes\n", (unsigned long) value_count); return 1; + case TIFFTAG_ICCPROFILE: fprintf(fd, " ICC Profile: , %lu bytes\n", (unsigned long) value_count); return 1; + case TIFFTAG_STONITS: - fprintf(fd, - " Sample to Nits conversion factor: %.4e\n", - *((double*)raw_data)); - return 1; + if (value_count == 1 && fip->field_type == TIFF_DOUBLE) { + fprintf(fd, + " Sample to Nits conversion factor: %.4e\n", + *((double*)raw_data)); + return 1; + } + return 0; } return 0; @@ -364,9 +392,13 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) fprintf(fd, " Ink Names: "); i = td->td_samplesperpixel; sep = ""; - for (cp = td->td_inknames; i > 0; cp = strchr(cp,'\0')+1, i--) { + for (cp = td->td_inknames; + i > 0 && cp < td->td_inknames + td->td_inknameslen; + cp = strchr(cp,'\0')+1, i--) { + int max_chars = + td->td_inknameslen - (cp - td->td_inknames); fputs(sep, fd); - _TIFFprintAscii(fd, cp); + _TIFFprintAsciiBounded(fd, cp, max_chars); sep = ", "; } fputs("\n", fd); @@ -449,14 +481,16 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue); if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) { + int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; fprintf(fd, " SMin Sample Value:"); - for (i = 0; i < td->td_samplesperpixel; ++i) + for (i = 0; i < count; ++i) fprintf(fd, " %g", td->td_sminsamplevalue[i]); fprintf(fd, "\n"); } if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) { + int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; fprintf(fd, " SMax Sample Value:"); - for (i = 0; i < td->td_samplesperpixel; ++i) + for (i = 0; i < count; ++i) fprintf(fd, " %g", td->td_smaxsamplevalue[i]); fprintf(fd, "\n"); } @@ -548,8 +582,19 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) continue; if(fip->field_passcount) { - if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) + if (fip->field_readcount == TIFF_VARIABLE2 ) { + if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) + continue; + } else if (fip->field_readcount == TIFF_VARIABLE ) { + uint16 small_value_count; + if(TIFFGetField(tif, tag, &small_value_count, &raw_data) != 1) + continue; + value_count = small_value_count; + } else { + assert (fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2); continue; + } } else { if (fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2) @@ -558,21 +603,23 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) value_count = td->td_samplesperpixel; else value_count = fip->field_readcount; - if ((fip->field_type == TIFF_ASCII - || fip->field_readcount == TIFF_VARIABLE - || fip->field_readcount == TIFF_VARIABLE2 - || fip->field_readcount == TIFF_SPP - || value_count > 1) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { + if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + static uint16 dotrange[2]; + raw_data = dotrange; + TIFFGetField(tif, tag, dotrange+0, dotrange+1); + } else if (fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || value_count > 1) { if(TIFFGetField(tif, tag, &raw_data) != 1) continue; - } else if (fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { + } else { raw_data = _TIFFmalloc( _TIFFDataSize(fip->field_type) * value_count); @@ -581,26 +628,6 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) _TIFFfree(raw_data); continue; } - } else { - /* - * XXX: Should be fixed and removed, - * see the notes related to - * TIFFTAG_PAGENUMBER, - * TIFFTAG_HALFTONEHINTS, - * TIFFTAG_YCBCRSUBSAMPLING and - * TIFFTAG_DOTRANGE tags in tif_dir.c. - */ - char *tmp; - raw_data = _TIFFmalloc( - _TIFFDataSize(fip->field_type) - * value_count); - tmp = raw_data; - mem_alloc = 1; - if(TIFFGetField(tif, tag, tmp, - tmp + _TIFFDataSize(fip->field_type)) != 1) { - _TIFFfree(raw_data); - continue; - } } } @@ -610,7 +637,7 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) * _TIFFPrettyPrintField() fall down and print it as * any other tag. */ - if (!_TIFFPrettyPrintField(tif, fd, tag, value_count, raw_data)) + if (!_TIFFPrettyPrintField(tif, fip, fd, tag, value_count, raw_data)) _TIFFPrintField(fd, fip, value_count, raw_data); if(mem_alloc) @@ -648,7 +675,13 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) void _TIFFprintAscii(FILE* fd, const char* cp) { - for (; *cp != '\0'; cp++) { + _TIFFprintAsciiBounded( fd, cp, strlen(cp)); +} + +static void +_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars) +{ + for (; max_chars > 0 && *cp != '\0'; cp++, max_chars--) { const char* tp; if (isprint((int)*cp)) { diff --git a/thirdparty/libtiff/tif_read.c b/thirdparty/libtiff/tif_read.c index 594733f8..5cb419bd 100644 --- a/thirdparty/libtiff/tif_read.c +++ b/thirdparty/libtiff/tif_read.c @@ -1,4 +1,4 @@ -/* $Id: tif_read.c,v 1.38 2011-12-09 03:29:10 fwarmerdam Exp $ */ +/* $Id: tif_read.c,v 1.45 2015-06-07 22:35:40 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -47,10 +47,10 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) { static const char module[] = "TIFFFillStripPartial"; register TIFFDirectory *td = &tif->tif_dir; - uint64 unused_data; + tmsize_t unused_data; uint64 read_offset; tmsize_t cc, to_read; - tmsize_t bytecountm; + /* tmsize_t bytecountm; */ if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; @@ -61,7 +61,7 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) * bound on the size of a buffer we'll use?). */ - bytecountm=(tmsize_t) td->td_stripbytecount[strip]; + /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ if (read_ahead*2 > tif->tif_rawdatasize) { assert( restart ); @@ -93,6 +93,7 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) if( unused_data > 0 ) { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); memmove( tif->tif_rawdata, tif->tif_rawcp, unused_data ); } @@ -116,10 +117,11 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) if( (uint64) to_read > td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded ) { - to_read = td->td_stripbytecount[strip] + to_read = (tmsize_t) td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded; } + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read); if (cc != to_read) { @@ -145,8 +147,10 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) tif->tif_rawcp = tif->tif_rawdata; if (!isFillOrder(tif, td->td_fillorder) && - (tif->tif_flags & TIFF_NOBITREV) == 0) + (tif->tif_flags & TIFF_NOBITREV) == 0) { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); TIFFReverseBits(tif->tif_rawdata + unused_data, to_read ); + } /* ** When starting a strip from the beginning we need to @@ -454,7 +458,7 @@ TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size) return ((tmsize_t)(-1)); } bytecount = td->td_stripbytecount[strip]; - if (bytecount <= 0) { + if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "%I64u: Invalid strip byte count, strip %lu", @@ -494,7 +498,7 @@ TIFFFillStrip(TIFF* tif, uint32 strip) if ((tif->tif_flags&TIFF_NOREADRAW)==0) { uint64 bytecount = td->td_stripbytecount[strip]; - if (bytecount <= 0) { + if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "Invalid strip byte count %I64u, strip %lu", @@ -522,8 +526,11 @@ TIFFFillStrip(TIFF* tif, uint32 strip) * 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) + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } tif->tif_flags &= ~TIFF_MYBUFFER; /* * We must check for overflow, potentially causing @@ -565,6 +572,14 @@ TIFFFillStrip(TIFF* tif, uint32 strip) tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[strip]; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; + + /* + * When we have tif_rawdata reference directly into the memory mapped file + * we need to be pretty careful about how we use the rawdata. It is not + * a general purpose working buffer as it normally otherwise is. So we + * keep track of this fact to avoid using it improperly. + */ + tif->tif_flags |= TIFF_BUFFERMMAP; } else { /* * Expand raw data buffer, if needed, to hold data @@ -589,6 +604,11 @@ TIFFFillStrip(TIFF* tif, uint32 strip) if (!TIFFReadBufferSetup(tif, 0, bytecountm)) return (0); } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curstrip = NOSTRIP; + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, bytecountm, module) != bytecountm) return (0); @@ -781,7 +801,7 @@ TIFFFillTile(TIFF* tif, uint32 tile) if ((tif->tif_flags&TIFF_NOREADRAW)==0) { uint64 bytecount = td->td_stripbytecount[tile]; - if (bytecount <= 0) { + if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "%I64u: Invalid tile byte count, tile %lu", @@ -809,8 +829,11 @@ TIFFFillTile(TIFF* tif, uint32 tile) * 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) + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } tif->tif_flags &= ~TIFF_MYBUFFER; /* * We must check for overflow, potentially causing @@ -831,6 +854,7 @@ TIFFFillTile(TIFF* tif, uint32 tile) tif->tif_base + (tmsize_t)td->td_stripoffset[tile]; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; + tif->tif_flags |= TIFF_BUFFERMMAP; } else { /* * Expand raw data buffer, if needed, to hold data @@ -855,6 +879,12 @@ TIFFFillTile(TIFF* tif, uint32 tile) if (!TIFFReadBufferSetup(tif, 0, bytecountm)) return (0); } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curtile = NOTILE; + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } + if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, bytecountm, module) != bytecountm) return (0); @@ -886,10 +916,13 @@ TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size) static const char module[] = "TIFFReadBufferSetup"; assert((tif->tif_flags&TIFF_NOREADRAW)==0); + tif->tif_flags &= ~TIFF_BUFFERMMAP; + if (tif->tif_rawdata) { if (tif->tif_flags & TIFF_MYBUFFER) _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; } if (bp) { tif->tif_rawdatasize = size; @@ -897,8 +930,11 @@ TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size) tif->tif_flags &= ~TIFF_MYBUFFER; } else { tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64)size, 1024); - if (tif->tif_rawdatasize==0) - tif->tif_rawdatasize=(tmsize_t)(-1); + if (tif->tif_rawdatasize==0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid buffer size"); + return (0); + } tif->tif_rawdata = (uint8*) _TIFFmalloc(tif->tif_rawdatasize); tif->tif_flags |= TIFF_MYBUFFER; } @@ -954,10 +990,12 @@ TIFFStartStrip(TIFF* tif, uint32 strip) static int TIFFStartTile(TIFF* tif, uint32 tile) { + static const char module[] = "TIFFStartTile"; TIFFDirectory *td = &tif->tif_dir; + uint32 howmany32; - if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) - return 0; + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupdecode)(tif)) @@ -965,12 +1003,18 @@ TIFFStartTile(TIFF* tif, uint32 tile) tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_curtile = tile; - tif->tif_row = - (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth)) * - td->td_tilelength; - tif->tif_col = - (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength)) * - td->td_tilewidth; + howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return 0; + } + tif->tif_row = (tile % howmany32) * td->td_tilelength; + howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return 0; + } + tif->tif_col = (tile % howmany32) * td->td_tilewidth; tif->tif_flags &= ~TIFF_BUF4WRITE; if (tif->tif_flags&TIFF_NOREADRAW) { diff --git a/thirdparty/libtiff/tif_stream.cxx b/thirdparty/libtiff/tif_stream.cxx index 163447eb..ecca1fd5 100644 --- a/thirdparty/libtiff/tif_stream.cxx +++ b/thirdparty/libtiff/tif_stream.cxx @@ -1,4 +1,4 @@ -/* $Id: tif_stream.cxx,v 1.11 2010-12-11 23:12:29 faxguy Exp $ */ +/* $Id: tif_stream.cxx,v 1.13 2015-05-28 01:50:22 bfriesen Exp $ */ /* * Copyright (c) 1988-1996 Sam Leffler @@ -340,12 +340,16 @@ _tiffisCloseProc(thandle_t fd) static int _tiffDummyMapProc(thandle_t , void** base, toff_t* size ) { + (void) base; + (void) size; return (0); } static void _tiffDummyUnmapProc(thandle_t , void* base, toff_t size ) { + (void) base; + (void) size; } /* @@ -417,9 +421,10 @@ TIFFStreamOpen(const char* name, istream *is) /* vim: set ts=8 sts=8 sw=8 noet: */ /* - Local Variables: - mode: c - indent-tabs-mode: true - c-basic-offset: 8 - End: -*/ + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ + diff --git a/thirdparty/libtiff/tif_strip.c b/thirdparty/libtiff/tif_strip.c index 3ced5a8d..6cac71dd 100644 --- a/thirdparty/libtiff/tif_strip.c +++ b/thirdparty/libtiff/tif_strip.c @@ -1,4 +1,4 @@ -/* $Id: tif_strip.c,v 1.34 2011-04-02 20:54:09 bfriesen Exp $ */ +/* $Id: tif_strip.c,v 1.36 2015-06-07 22:35:40 bfriesen Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler @@ -107,11 +107,13 @@ TIFFVStripSize64(TIFF* tif, uint32 nrows) } TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, ycbcrsubsampling+1); - if (((ycbcrsubsampling[0]!=1)&&(ycbcrsubsampling[0]!=2)&&(ycbcrsubsampling[0]!=4)) || - ((ycbcrsubsampling[1]!=1)&&(ycbcrsubsampling[1]!=2)&&(ycbcrsubsampling[1]!=4))) + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) { TIFFErrorExt(tif->tif_clientdata,module, - "Invalid YCbCr subsampling"); + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); return 0; } samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; @@ -315,7 +317,14 @@ TIFFScanlineSize64(TIFF* tif) } } else + { scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,td->td_imagewidth,td->td_bitspersample,module),8); + } + if (scanline_size == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Computed scanline size is zero"); + return 0; + } return(scanline_size); } tmsize_t @@ -326,8 +335,7 @@ TIFFScanlineSize(TIFF* tif) tmsize_t n; m=TIFFScanlineSize64(tif); n=(tmsize_t)m; - if ((uint64)n!=m) - { + if ((uint64)n!=m) { TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow"); n=0; } diff --git a/thirdparty/libtiff/tif_tile.c b/thirdparty/libtiff/tif_tile.c index 062d943f..388e168a 100644 --- a/thirdparty/libtiff/tif_tile.c +++ b/thirdparty/libtiff/tif_tile.c @@ -1,4 +1,4 @@ -/* $Id: tif_tile.c,v 1.22 2010-07-01 15:33:28 dron Exp $ */ +/* $Id: tif_tile.c,v 1.24 2015-06-07 22:35:40 bfriesen Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler @@ -143,17 +143,40 @@ TIFFNumberOfTiles(TIFF* tif) uint64 TIFFTileRowSize64(TIFF* tif) { + static const char module[] = "TIFFTileRowSize64"; TIFFDirectory *td = &tif->tif_dir; uint64 rowsize; + uint64 tilerowsize; - if (td->td_tilelength == 0 || td->td_tilewidth == 0) + if (td->td_tilelength == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Tile length is zero"); + return 0; + } + if (td->td_tilewidth == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Tile width is zero"); return (0); + } rowsize = _TIFFMultiply64(tif, td->td_bitspersample, td->td_tilewidth, "TIFFTileRowSize"); if (td->td_planarconfig == PLANARCONFIG_CONTIG) + { + if (td->td_samplesperpixel == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Samples per pixel is zero"); + return 0; + } rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel, "TIFFTileRowSize"); - return (TIFFhowmany8_64(rowsize)); + } + tilerowsize=TIFFhowmany8_64(rowsize); + if (tilerowsize == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Computed tile row size is zero"); + return 0; + } + return (tilerowsize); } tmsize_t TIFFTileRowSize(TIFF* tif) @@ -203,12 +226,13 @@ TIFFVTileSize64(TIFF* tif, uint32 nrows) uint64 samplingrow_size; TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, ycbcrsubsampling+1); - assert((ycbcrsubsampling[0]==1)||(ycbcrsubsampling[0]==2)||(ycbcrsubsampling[0]==4)); - assert((ycbcrsubsampling[1]==1)||(ycbcrsubsampling[1]==2)||(ycbcrsubsampling[1]==4)); - if (ycbcrsubsampling[0]*ycbcrsubsampling[1]==0) + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) { TIFFErrorExt(tif->tif_clientdata,module, - "Invalid YCbCr subsampling"); + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); return 0; } samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; diff --git a/thirdparty/libtiff/tif_unix.c b/thirdparty/libtiff/tif_unix.c index 7c5cc50f..e96841a4 100644 --- a/thirdparty/libtiff/tif_unix.c +++ b/thirdparty/libtiff/tif_unix.c @@ -1,4 +1,4 @@ -/* $Id: tif_unix.c,v 1.22 2010-03-10 18:56:49 bfriesen Exp $ */ +/* $Id: tif_unix.c,v 1.26 2015-06-16 15:33:17 erouault Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -55,53 +55,69 @@ #include "tiffiop.h" +typedef union fd_as_handle_union +{ + int fd; + thandle_t h; +} fd_as_handle_union_t; + static tmsize_t _tiffReadProc(thandle_t fd, void* buf, tmsize_t size) { + fd_as_handle_union_t fdh; size_t size_io = (size_t) size; if ((tmsize_t) size_io != size) { errno=EINVAL; return (tmsize_t) -1; } - return ((tmsize_t) read((int) fd, buf, size_io)); + fdh.h = fd; + return ((tmsize_t) read(fdh.fd, buf, size_io)); } static tmsize_t _tiffWriteProc(thandle_t fd, void* buf, tmsize_t size) { + fd_as_handle_union_t fdh; size_t size_io = (size_t) size; if ((tmsize_t) size_io != size) { errno=EINVAL; return (tmsize_t) -1; } - return ((tmsize_t) write((int) fd, buf, size_io)); + fdh.h = fd; + return ((tmsize_t) write(fdh.fd, buf, size_io)); } static uint64 _tiffSeekProc(thandle_t fd, uint64 off, int whence) { + fd_as_handle_union_t fdh; off_t off_io = (off_t) off; if ((uint64) off_io != off) { errno=EINVAL; return (uint64) -1; /* this is really gross */ } - return((uint64)lseek((int)fd,off_io,whence)); + fdh.h = fd; + return((uint64)lseek(fdh.fd,off_io,whence)); } static int _tiffCloseProc(thandle_t fd) { - return(close((int)fd)); + fd_as_handle_union_t fdh; + fdh.h = fd; + return(close(fdh.fd)); } static uint64 _tiffSizeProc(thandle_t fd) { struct stat sb; - if (fstat((int)fd,&sb)<0) + fd_as_handle_union_t fdh; + fdh.h = fd; + if (fstat(fdh.fd,&sb)<0) return(0); else return((uint64)sb.st_size); @@ -116,8 +132,10 @@ _tiffMapProc(thandle_t fd, void** pbase, toff_t* psize) uint64 size64 = _tiffSizeProc(fd); tmsize_t sizem = (tmsize_t)size64; if ((uint64)sizem==size64) { + fd_as_handle_union_t fdh; + fdh.h = fd; *pbase = (void*) - mmap(0, (size_t)sizem, PROT_READ, MAP_SHARED, (int) fd, 0); + mmap(0, (size_t)sizem, PROT_READ, MAP_SHARED, fdh.fd, 0); if (*pbase != (void*) -1) { *psize = (tmsize_t)sizem; return (1); @@ -155,8 +173,10 @@ TIFFFdOpen(int fd, const char* name, const char* mode) { TIFF* tif; + fd_as_handle_union_t fdh; + fdh.fd = fd; tif = TIFFClientOpen(name, mode, - (thandle_t) fd, + fdh.h, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); @@ -186,7 +206,11 @@ TIFFOpen(const char* name, const char* mode) fd = open(name, m, 0666); if (fd < 0) { - TIFFErrorExt(0, module, "%s: Cannot open", name); + if (errno > 0 && strerror(errno) != NULL ) { + TIFFErrorExt(0, module, "%s: %s", name, strerror(errno) ); + } else { + TIFFErrorExt(0, module, "%s: Cannot open", name); + } return ((TIFF *)0); } @@ -253,6 +277,9 @@ TIFFOpenW(const wchar_t* name, const char* mode) void* _TIFFmalloc(tmsize_t s) { + if (s == 0) + return ((void *) NULL); + return (malloc((size_t) s)); } diff --git a/thirdparty/libtiff/tif_win32.c b/thirdparty/libtiff/tif_win32.c index 2cf1de93..5d294746 100644 --- a/thirdparty/libtiff/tif_win32.c +++ b/thirdparty/libtiff/tif_win32.c @@ -1,4 +1,4 @@ -/* $Id: tif_win32.c,v 1.39 2011-12-22 17:07:57 bfriesen Exp $ */ +/* $Id: tif_win32.c,v 1.40 2012-11-18 17:51:52 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -329,6 +329,9 @@ TIFFOpenW(const wchar_t* name, const char* mode) void* _TIFFmalloc(tmsize_t s) { + if (s == 0) + return ((void *) NULL); + return (malloc((size_t) s)); } diff --git a/thirdparty/libtiff/tif_write.c b/thirdparty/libtiff/tif_write.c index eaa1f814..7996c31e 100644 --- a/thirdparty/libtiff/tif_write.c +++ b/thirdparty/libtiff/tif_write.c @@ -1,4 +1,4 @@ -/* $Id: tif_write.c,v 1.36 2011-02-18 20:53:04 fwarmerdam Exp $ */ +/* $Id: tif_write.c,v 1.42 2015-06-07 23:00:23 bfriesen Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -115,6 +115,10 @@ TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample) if (strip >= td->td_stripsperimage && imagegrew) td->td_stripsperimage = TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip); + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image"); + return (-1); + } tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { @@ -220,23 +224,39 @@ TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc) tif->tif_flags |= TIFF_BUF4WRITE; tif->tif_curstrip = strip; + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image"); + return ((tmsize_t) -1); + } + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupencode)(tif)) return ((tmsize_t) -1); tif->tif_flags |= TIFF_CODERSETUP; } - - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; if( td->td_stripbytecount[strip] > 0 ) { + /* Make sure that at the first attempt of rewriting the tile, we will have */ + /* more bytes available in the output buffer than the previous byte count, */ + /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */ + /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */ + if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[strip] ) + { + if( !(TIFFWriteBufferSetup(tif, NULL, + (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[strip] + 1), 1024))) ) + return ((tmsize_t)(-1)); + } + /* Force TIFFAppendToStrip() to consider placing data at end of file. */ tif->tif_curoff = 0; } - + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_flags &= ~TIFF_POSTENCODE; sample = (uint16)(strip / td->td_stripsperimage); if (!(*tif->tif_preencode)(tif, sample)) @@ -300,6 +320,10 @@ TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc) return ((tmsize_t) -1); } tif->tif_curstrip = strip; + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module,"Zero strips per image"); + return ((tmsize_t) -1); + } tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; return (TIFFAppendToStrip(tif, strip, (uint8*) data, cc) ? cc : (tmsize_t) -1); @@ -342,6 +366,7 @@ TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc) static const char module[] = "TIFFWriteEncodedTile"; TIFFDirectory *td; uint16 sample; + uint32 howmany32; if (!WRITECHECKTILES(tif, module)) return ((tmsize_t)(-1)); @@ -362,24 +387,43 @@ TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc) tif->tif_flags |= TIFF_BUF4WRITE; tif->tif_curtile = tile; - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - if( td->td_stripbytecount[tile] > 0 ) { + /* Make sure that at the first attempt of rewriting the tile, we will have */ + /* more bytes available in the output buffer than the previous byte count, */ + /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */ + /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */ + if( tif->tif_rawdatasize <= (tmsize_t) td->td_stripbytecount[tile] ) + { + if( !(TIFFWriteBufferSetup(tif, NULL, + (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[tile] + 1), 1024))) ) + return ((tmsize_t)(-1)); + } + /* Force TIFFAppendToStrip() to consider placing data at end of file. */ tif->tif_curoff = 0; } - + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + /* * Compute tiles per row & per column to compute * current row and column */ - tif->tif_row = (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength)) - * td->td_tilelength; - tif->tif_col = (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth)) - * td->td_tilewidth; + howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return ((tmsize_t)(-1)); + } + tif->tif_row = (tile % howmany32) * td->td_tilelength; + howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return ((tmsize_t)(-1)); + } + tif->tif_col = (tile % howmany32) * td->td_tilewidth; if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { if (!(*tif->tif_setupencode)(tif)) diff --git a/thirdparty/libtiff/tif_zip.c b/thirdparty/libtiff/tif_zip.c index f5aa2a96..22e9f35b 100644 --- a/thirdparty/libtiff/tif_zip.c +++ b/thirdparty/libtiff/tif_zip.c @@ -1,4 +1,4 @@ -/* $Id: tif_zip.c,v 1.31 2011-01-06 16:00:23 fwarmerdam Exp $ */ +/* $Id: tif_zip.c,v 1.33 2014-12-25 18:29:11 erouault Exp $ */ /* * Copyright (c) 1995-1997 Sam Leffler @@ -36,7 +36,7 @@ * 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 + * older versions of this codec avoided this bug by suppressing 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. @@ -61,6 +61,8 @@ #error "Antiquated ZLIB software; you must use version 1.0 or later" #endif +#define SAFE_MSG(sp) ((sp)->stream.msg == NULL ? "" : (sp)->stream.msg) + /* * State block for each open TIFF * file using ZIP compression/decompression. @@ -106,7 +108,7 @@ ZIPSetupDecode(TIFF* tif) } if (inflateInit(&sp->stream) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp)); return (0); } else { sp->state |= ZSTATE_INIT_DECODE; @@ -174,14 +176,14 @@ ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) if (state == Z_DATA_ERROR) { TIFFErrorExt(tif->tif_clientdata, module, "Decoding error at scanline %lu, %s", - (unsigned long) tif->tif_row, sp->stream.msg); + (unsigned long) tif->tif_row, SAFE_MSG(sp)); if (inflateSync(&sp->stream) != Z_OK) return (0); continue; } if (state != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", - sp->stream.msg); + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib error: %s", SAFE_MSG(sp)); return (0); } } while (sp->stream.avail_out > 0); @@ -211,7 +213,7 @@ ZIPSetupEncode(TIFF* tif) } if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp)); return (0); } else { sp->state |= ZSTATE_INIT_ENCODE; @@ -273,8 +275,9 @@ ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) } do { if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s", - sp->stream.msg); + TIFFErrorExt(tif->tif_clientdata, module, + "Encoder error: %s", + SAFE_MSG(sp)); return (0); } if (sp->stream.avail_out == 0) { @@ -313,8 +316,8 @@ ZIPPostEncode(TIFF* tif) } break; default: - TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", - sp->stream.msg); + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib error: %s", SAFE_MSG(sp)); return (0); } } while (state != Z_STREAM_END); @@ -359,7 +362,7 @@ ZIPVSetField(TIFF* tif, uint32 tag, va_list ap) if (deflateParams(&sp->stream, sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) { TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", - sp->stream.msg); + SAFE_MSG(sp)); return (0); } } diff --git a/thirdparty/libtiff/tiff.h b/thirdparty/libtiff/tiff.h index 5c32d3ae..bc46acd0 100644 --- a/thirdparty/libtiff/tiff.h +++ b/thirdparty/libtiff/tiff.h @@ -1,4 +1,4 @@ -/* $Id: tiff.h,v 1.67 2011-01-24 21:06:32 olivier Exp $ */ +/* $Id: tiff.h,v 1.69 2014-04-02 17:23:06 fwarmerdam Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -166,6 +166,8 @@ typedef enum { #define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ #define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ #define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_T85 9 /* !TIFF/FX T.85 JBIG compression */ +#define COMPRESSION_T43 10 /* !TIFF/FX T.43 colour by layered JBIG compression */ #define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ #define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ #define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ @@ -199,6 +201,7 @@ typedef enum { #define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ #define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ #define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_CFA 32803 /* color filter array */ #define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ #define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ #define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ @@ -319,6 +322,30 @@ typedef enum { [Adobe TIFF Technote 3] */ #define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ #define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* Tags 400-435 are from the TIFF/FX spec */ +#define TIFFTAG_GLOBALPARAMETERSIFD 400 /* ! */ +#define TIFFTAG_PROFILETYPE 401 /* ! */ +#define PROFILETYPE_UNSPECIFIED 0 /* ! */ +#define PROFILETYPE_G3_FAX 1 /* ! */ +#define TIFFTAG_FAXPROFILE 402 /* ! */ +#define FAXPROFILE_S 1 /* !TIFF/FX FAX profile S */ +#define FAXPROFILE_F 2 /* !TIFF/FX FAX profile F */ +#define FAXPROFILE_J 3 /* !TIFF/FX FAX profile J */ +#define FAXPROFILE_C 4 /* !TIFF/FX FAX profile C */ +#define FAXPROFILE_L 5 /* !TIFF/FX FAX profile L */ +#define FAXPROFILE_M 6 /* !TIFF/FX FAX profile LM */ +#define TIFFTAG_CODINGMETHODS 403 /* !TIFF/FX coding methods */ +#define CODINGMETHODS_T4_1D (1 << 1) /* !T.4 1D */ +#define CODINGMETHODS_T4_2D (1 << 2) /* !T.4 2D */ +#define CODINGMETHODS_T6 (1 << 3) /* !T.6 */ +#define CODINGMETHODS_T85 (1 << 4) /* !T.85 JBIG */ +#define CODINGMETHODS_T42 (1 << 5) /* !T.42 JPEG */ +#define CODINGMETHODS_T43 (1 << 6) /* !T.43 colour by layered JBIG */ +#define TIFFTAG_VERSIONYEAR 404 /* !TIFF/FX version year */ +#define TIFFTAG_MODENUMBER 405 /* !TIFF/FX mode number */ +#define TIFFTAG_DECODE 433 /* !TIFF/FX decode */ +#define TIFFTAG_IMAGEBASECOLOR 434 /* !TIFF/FX image base colour */ +#define TIFFTAG_T82OPTIONS 435 /* !TIFF/FX T.82 options */ /* * Tags 512-521 are obsoleted by Technical Note #2 which specifies a * revised JPEG-in-TIFF scheme. @@ -340,6 +367,7 @@ typedef enum { #define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ #define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ #define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_STRIPROWCOUNTS 559 /* !TIFF/FX strip row counts */ #define TIFFTAG_XMLPACKET 700 /* %XML packet [Adobe XMP Specification, January 2004 */ @@ -375,6 +403,8 @@ typedef enum { #define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 /* tag 33405 is a private tag registered to Eastman Kodak */ #define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +#define TIFFTAG_CFAREPEATPATTERNDIM 33421 /* dimensions of CFA pattern */ +#define TIFFTAG_CFAPATTERN 33422 /* color filter array pattern */ /* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ #define TIFFTAG_COPYRIGHT 33432 /* copyright string */ /* IPTC TAG from RichTIFF specifications */ @@ -406,6 +436,7 @@ typedef enum { #define TIFFTAG_EXIFIFD 34665 /* Pointer to EXIF private directory */ /* tag 34750 is a private tag registered to Adobe? */ #define TIFFTAG_ICCPROFILE 34675 /* ICC profile data */ +#define TIFFTAG_IMAGELAYER 34732 /* !TIFF/FX image layer information */ /* tag 34750 is a private tag registered to Pixel Magic */ #define TIFFTAG_JBIGOPTIONS 34750 /* JBIG options */ #define TIFFTAG_GPSIFD 34853 /* Pointer to GPS private directory */ diff --git a/thirdparty/libtiff/tiffconf.h.cmake.in b/thirdparty/libtiff/tiffconf.h.cmake.in index 53a66d41..177c3010 100644 --- a/thirdparty/libtiff/tiffconf.h.cmake.in +++ b/thirdparty/libtiff/tiffconf.h.cmake.in @@ -11,6 +11,9 @@ #if defined( HAVE_STDINT_H ) #include #endif +#if defined( HAVE_UNISTD_H ) +#include +#endif /* Define as 0 or 1 according to the floating point format suported by the machine */ diff --git a/thirdparty/libtiff/tiffio.h b/thirdparty/libtiff/tiffio.h index 6ca74343..038b6701 100644 --- a/thirdparty/libtiff/tiffio.h +++ b/thirdparty/libtiff/tiffio.h @@ -1,4 +1,4 @@ -/* $Id: tiffio.h,v 1.89 2012-02-18 16:20:26 bfriesen Exp $ */ +/* $Id: tiffio.h,v 1.91 2012-07-29 15:45:29 tgl Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -319,6 +319,13 @@ extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType); extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32); extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); +extern uint32 TIFFFieldTag(const TIFFField*); +extern const char* TIFFFieldName(const TIFFField*); +extern TIFFDataType TIFFFieldDataType(const TIFFField*); +extern int TIFFFieldPassCount(const TIFFField*); +extern int TIFFFieldReadCount(const TIFFField*); +extern int TIFFFieldWriteCount(const TIFFField*); + typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list); typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list); typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); @@ -392,6 +399,8 @@ extern int TIFFSetupStrips(TIFF *); extern int TIFFWriteCheck(TIFF*, int, const char *); extern void TIFFFreeDirectory(TIFF*); extern int TIFFCreateDirectory(TIFF*); +extern int TIFFCreateCustomDirectory(TIFF*,const TIFFFieldArray*); +extern int TIFFCreateEXIFDirectory(TIFF*); extern int TIFFLastDirectory(TIFF*); extern int TIFFSetDirectory(TIFF*, uint16); extern int TIFFSetSubDirectory(TIFF*, uint64); @@ -400,6 +409,7 @@ extern int TIFFSetField(TIFF*, uint32, ...); extern int TIFFVSetField(TIFF*, uint32, va_list); extern int TIFFUnsetField(TIFF*, uint32); extern int TIFFWriteDirectory(TIFF *); +extern int TIFFWriteCustomDirectory(TIFF *, uint64 *); extern int TIFFCheckpointDirectory(TIFF *); extern int TIFFRewriteDirectory(TIFF *); diff --git a/thirdparty/libtiff/tiffiop.h b/thirdparty/libtiff/tiffiop.h index 7bed4abd..53357d85 100644 --- a/thirdparty/libtiff/tiffiop.h +++ b/thirdparty/libtiff/tiffiop.h @@ -1,4 +1,4 @@ -/* $Id: tiffiop.h,v 1.82 2011-02-18 20:53:05 fwarmerdam Exp $ */ +/* $Id: tiffiop.h,v 1.84 2012-05-30 01:50:17 fwarmerdam Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -121,6 +121,7 @@ struct tiff { #define TIFF_BUF4WRITE 0x100000 /* rawcc bytes are for writing */ #define TIFF_DIRTYSTRIP 0x200000 /* stripoffsets/stripbytecount dirty*/ #define TIFF_PERSAMPLE 0x400000 /* get/set per sample tags as arrays */ + #define TIFF_BUFFERMMAP 0x800000 /* read buffer (tif_rawdata) points into mmap() memory */ uint64 tif_diroff; /* file offset of current directory */ uint64 tif_nextdiroff; /* file offset of following directory */ uint64* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */ @@ -250,7 +251,7 @@ struct tiff { #define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y)) /* Safe multiply which returns zero if there is an integer overflow */ -#define TIFFSafeMultiply(t,v,m) ((((t)m != (t)0) && (((t)((v*m)/m)) == (t)v)) ? (t)(v*m) : (t)0) +#define TIFFSafeMultiply(t,v,m) ((((t)(m) != (t)0) && (((t)(((v)*(m))/(m))) == (t)(v))) ? (t)((v)*(m)) : (t)0) #define TIFFmax(A,B) ((A)>(B)?(A):(B)) #define TIFFmin(A,B) ((A)<(B)?(A):(B)) diff --git a/thirdparty/libtiff/tiffvers.h b/thirdparty/libtiff/tiffvers.h index fbdc5a10..1ed5b8f3 100644 --- a/thirdparty/libtiff/tiffvers.h +++ b/thirdparty/libtiff/tiffvers.h @@ -1,4 +1,4 @@ -#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.1\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.4\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." /* * This define can be used in code that requires * compilation-related definitions specific to a @@ -6,4 +6,4 @@ * version checking should be done based on the * string returned by TIFFGetVersion. */ -#define TIFFLIB_VERSION 20120218 +#define TIFFLIB_VERSION 20150621 diff --git a/thirdparty/libz/adler32.c b/thirdparty/libz/adler32.c index 65ad6a5a..a868f073 100644 --- a/thirdparty/libz/adler32.c +++ b/thirdparty/libz/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2007 Mark Adler + * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,9 +9,9 @@ #define local static -local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); -#define BASE 65521UL /* largest prime smaller than 65536 */ +#define BASE 65521 /* 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 */ @@ -21,39 +21,44 @@ local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); -/* use NO_DIVIDE if your processor does not do division in hardware */ +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ #ifdef NO_DIVIDE -# define MOD(a) \ +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) -# define MOD4(a) \ +# define MOD(a) \ do { \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE -# define MOD4(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE #endif /* ========================================================================= */ @@ -92,7 +97,7 @@ uLong ZEXPORT adler32(adler, buf, len) } if (adler >= BASE) adler -= BASE; - MOD4(sum2); /* only added so many BASE's */ + MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } @@ -137,8 +142,13 @@ local uLong adler32_combine_(adler1, adler2, len2) unsigned long sum2; unsigned rem; + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + /* the derivation of this formula is left as an exercise for the reader */ - rem = (unsigned)(len2 % BASE); + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); diff --git a/thirdparty/libz/compress.c b/thirdparty/libz/compress.c index ea4dfbe9..6e976267 100644 --- a/thirdparty/libz/compress.c +++ b/thirdparty/libz/compress.c @@ -29,7 +29,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) z_stream stream; int err; - stream.next_in = (Bytef*)source; + stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */ diff --git a/thirdparty/libz/crc32.c b/thirdparty/libz/crc32.c index 91be372d..979a7190 100644 --- a/thirdparty/libz/crc32.c +++ b/thirdparty/libz/crc32.c @@ -1,5 +1,5 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010 Mark Adler + * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster @@ -17,6 +17,8 @@ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH @@ -30,31 +32,11 @@ #define local static -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - /* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif #ifdef BYFOUR -# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, @@ -68,16 +50,16 @@ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); -local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; +local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); + local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: @@ -107,9 +89,9 @@ local void make_crc_table OF((void)); */ local void make_crc_table() { - unsigned long c; + z_crc_t c; int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ + z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; @@ -121,13 +103,13 @@ local void make_crc_table() first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { - c = (unsigned long)n; + c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; @@ -138,11 +120,11 @@ local void make_crc_table() and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; - crc_table[4][n] = REV(c); + crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); + crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ @@ -164,7 +146,7 @@ local void make_crc_table() if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); + fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR @@ -184,12 +166,13 @@ local void make_crc_table() #ifdef MAKECRCH local void write_table(out, table) FILE *out; - const unsigned long FAR *table; + const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ @@ -204,13 +187,13 @@ local void write_table(out, table) /* ========================================================================= * This function can be used by asm versions of crc32() */ -const unsigned long FAR * ZEXPORT get_crc_table() +const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; + return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ @@ -232,7 +215,7 @@ unsigned long ZEXPORT crc32(crc, buf, len) #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; + z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) @@ -266,17 +249,17 @@ local unsigned long crc32_little(crc, buf, len) const unsigned char FAR *buf; unsigned len; { - register u4 c; - register const u4 FAR *buf4; + register z_crc_t c; + register const z_crc_t FAR *buf4; - c = (u4)crc; + c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } - buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; @@ -306,17 +289,17 @@ local unsigned long crc32_big(crc, buf, len) const unsigned char FAR *buf; unsigned len; { - register u4 c; - register const u4 FAR *buf4; + register z_crc_t c; + register const z_crc_t FAR *buf4; - c = REV((u4)crc); + c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } - buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; @@ -333,7 +316,7 @@ local unsigned long crc32_big(crc, buf, len) c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; - return (unsigned long)(REV(c)); + return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ diff --git a/thirdparty/libz/crc32.h b/thirdparty/libz/crc32.h index 8053b611..9e0c7781 100644 --- a/thirdparty/libz/crc32.h +++ b/thirdparty/libz/crc32.h @@ -2,7 +2,7 @@ * Generated automatically by crc32.c */ -local const unsigned long FAR crc_table[TBLS][256] = +local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, diff --git a/thirdparty/libz/deflate.c b/thirdparty/libz/deflate.c index 5c4022f3..69695770 100644 --- a/thirdparty/libz/deflate.c +++ b/thirdparty/libz/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -37,7 +37,7 @@ * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt + * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and 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 @@ -155,6 +155,9 @@ local const config configuration_table[10] = { struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) + /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive @@ -235,10 +238,19 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif #ifdef FASTEST if (level != 0) level = 1; @@ -293,7 +305,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } @@ -314,43 +326,70 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) uInt dictLength; { deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; - s = strm->state; - if (s->wrap) + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ - if (length < MIN_MATCH) return Z_OK; - if (length > s->w_size) { - length = s->w_size; - dictionary += dictLength - length; /* use the tail of the dictionary */ + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; } - 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); + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); } - if (hash_head) hash_head = 0; /* to make compiler happy */ + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; return Z_OK; } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) +int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; @@ -380,11 +419,22 @@ int ZEXPORT deflateReset (strm) s->last_flush = Z_NO_FLUSH; _tr_init(s); - lm_init(s); return Z_OK; } +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; @@ -396,15 +446,43 @@ int ZEXPORT deflateSetHeader (strm, head) return Z_OK; } +/* ========================================================================= */ +int ZEXPORT deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { + deflate_state *s; + int put; + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + s = strm->state; + if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); return Z_OK; } @@ -435,6 +513,8 @@ int ZEXPORT deflateParams(strm, level, strategy) strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); + if (err == Z_BUF_ERROR && s->pending == 0) + err = Z_OK; } if (s->level != level) { s->level = level; @@ -562,19 +642,22 @@ local void putShortMSB (s, b) local void flush_pending(strm) z_streamp strm; { - unsigned len = strm->state->pending; + unsigned len; + deflate_state *s = strm->state; + _tr_flush_bits(s); + len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; - zmemcpy(strm->next_out, strm->state->pending_out, len); + zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; - strm->state->pending_out += len; + s->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; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; } } @@ -801,7 +884,7 @@ int ZEXPORT deflate (strm, flush) * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ - } else if (strm->avail_in == 0 && flush <= old_flush && + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } @@ -850,6 +933,7 @@ int ZEXPORT deflate (strm, flush) if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; + s->insert = 0; } } } @@ -945,12 +1029,12 @@ int ZEXPORT deflateCopy (dest, source) ss = source->state; - zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(deflate_state)); + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); @@ -966,8 +1050,8 @@ int ZEXPORT deflateCopy (dest, source) } /* 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((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)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); @@ -1001,15 +1085,15 @@ local int read_buf(strm, buf, size) strm->avail_in -= len; + zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); + strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); + strm->adler = crc32(strm->adler, buf, len); } #endif - zmemcpy(buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; @@ -1036,6 +1120,7 @@ local void lm_init (s) s->strstart = 0; s->block_start = 0L; s->lookahead = 0; + s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; @@ -1310,6 +1395,8 @@ local void fill_window(s) unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); @@ -1362,7 +1449,7 @@ local void fill_window(s) #endif more += wsize; } - if (s->strm->avail_in == 0) return; + if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && @@ -1381,12 +1468,24 @@ local void fill_window(s) 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 (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } } /* 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. @@ -1427,6 +1526,9 @@ local void fill_window(s) s->high_water += init; } } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); } /* =========================================================================== @@ -1506,8 +1608,14 @@ local block_state deflate_stored(s, flush) FLUSH_BLOCK(s, 0); } } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if ((long)s->strstart > s->block_start) + FLUSH_BLOCK(s, 0); + return block_done; } /* =========================================================================== @@ -1603,8 +1711,14 @@ local block_state deflate_fast(s, flush) } if (bflush) FLUSH_BLOCK(s, 0); } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; } #ifndef FASTEST @@ -1728,8 +1842,14 @@ local block_state deflate_slow(s, flush) _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; + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; } #endif /* FASTEST */ @@ -1749,11 +1869,11 @@ local block_state deflate_rle(s, flush) for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes - * for the longest encodable run. + * for the longest run, plus one for the unrolled loop. */ - if (s->lookahead < MAX_MATCH) { + if (s->lookahead <= MAX_MATCH) { fill_window(s); - if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ @@ -1776,6 +1896,7 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -1796,8 +1917,14 @@ local block_state deflate_rle(s, flush) } if (bflush) FLUSH_BLOCK(s, 0); } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; } /* =========================================================================== @@ -1829,6 +1956,12 @@ local block_state deflate_huff(s, flush) s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; } diff --git a/thirdparty/libz/deflate.h b/thirdparty/libz/deflate.h index cbf0d1ea..ce0299ed 100644 --- a/thirdparty/libz/deflate.h +++ b/thirdparty/libz/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2010 Jean-loup Gailly + * Copyright (C) 1995-2012 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -48,6 +48,9 @@ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 @@ -101,7 +104,7 @@ typedef struct internal_state { int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ + Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ @@ -188,7 +191,7 @@ typedef struct internal_state { 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 */ + /* Didn't use ct_data typedef below to suppress 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 */ @@ -244,7 +247,7 @@ typedef struct internal_state { 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 */ + uInt insert; /* bytes at end of window left to insert */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ @@ -294,6 +297,7 @@ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); diff --git a/thirdparty/libz/example.c b/thirdparty/libz/example.c deleted file mode 100644 index 604736f1..00000000 --- a/thirdparty/libz/example.c +++ /dev/null @@ -1,565 +0,0 @@ -/* example.c -- usage example of the zlib compression library - * Copyright (C) 1995-2006 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zlib.h" -#include - -#ifdef STDC -# include -# include -#endif - -#if defined(VMS) || defined(RISCOS) -# define TESTFILE "foo-gz" -#else -# define TESTFILE "foo.gz" -#endif - -#define CHECK_ERR(err, msg) { \ - if (err != Z_OK) { \ - fprintf(stderr, "%s error: %d\n", msg, err); \ - exit(1); \ - } \ -} - -const char hello[] = "hello, hello!"; -/* "hello world" would be more standard, but the repeated "hello" - * stresses the compression code better, sorry... - */ - -const char dictionary[] = "hello"; -uLong dictId; /* Adler32 value of the dictionary */ - -void test_compress OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_gzio OF((const char *fname, - Byte *uncompr, uLong uncomprLen)); -void test_deflate OF((Byte *compr, uLong comprLen)); -void test_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_deflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_flush OF((Byte *compr, uLong *comprLen)); -void test_sync OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_dict_deflate OF((Byte *compr, uLong comprLen)); -void test_dict_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -int main OF((int argc, char *argv[])); - -/* =========================================================================== - * Test compress() and uncompress() - */ -void test_compress(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - uLong len = (uLong)strlen(hello)+1; - - err = compress(compr, &comprLen, (const Bytef*)hello, len); - CHECK_ERR(err, "compress"); - - strcpy((char*)uncompr, "garbage"); - - err = uncompress(uncompr, &uncomprLen, compr, comprLen); - CHECK_ERR(err, "uncompress"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad uncompress\n"); - exit(1); - } else { - printf("uncompress(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test read/write of .gz files - */ -void test_gzio(fname, uncompr, uncomprLen) - const char *fname; /* compressed file name */ - Byte *uncompr; - uLong uncomprLen; -{ -#ifdef NO_GZCOMPRESS - fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); -#else - int err; - int len = (int)strlen(hello)+1; - gzFile file; - z_off_t pos; - - file = gzopen(fname, "wb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - gzputc(file, 'h'); - if (gzputs(file, "ello") != 4) { - fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); - exit(1); - } - if (gzprintf(file, ", %s!", "hello") != 8) { - fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); - exit(1); - } - gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ - gzclose(file); - - file = gzopen(fname, "rb"); - if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); - } - strcpy((char*)uncompr, "garbage"); - - if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { - fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); - exit(1); - } else { - printf("gzread(): %s\n", (char*)uncompr); - } - - pos = gzseek(file, -8L, SEEK_CUR); - if (pos != 6 || gztell(file) != pos) { - fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", - (long)pos, (long)gztell(file)); - exit(1); - } - - if (gzgetc(file) != ' ') { - fprintf(stderr, "gzgetc error\n"); - exit(1); - } - - if (gzungetc(' ', file) != ' ') { - fprintf(stderr, "gzungetc error\n"); - exit(1); - } - - gzgets(file, (char*)uncompr, (int)uncomprLen); - if (strlen((char*)uncompr) != 7) { /* " hello!" */ - fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); - exit(1); - } - if (strcmp((char*)uncompr, hello + 6)) { - fprintf(stderr, "bad gzgets after gzseek\n"); - exit(1); - } else { - printf("gzgets() after gzseek: %s\n", (char*)uncompr); - } - - gzclose(file); -#endif -} - -/* =========================================================================== - * Test deflate() with small buffers - */ -void test_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uLong len = (uLong)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - - while (c_stream.total_in != len && c_stream.total_out < comprLen) { - c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - } - /* Finish the stream, still forcing small buffers: */ - for (;;) { - c_stream.avail_out = 1; - err = deflate(&c_stream, Z_FINISH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "deflate"); - } - - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with small buffers - */ -void test_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 0; - d_stream.next_out = uncompr; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { - d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate\n"); - exit(1); - } else { - printf("inflate(): %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Test deflate() with large buffers and dynamic change of compression level - */ -void test_large_deflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_SPEED); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - /* At this point, uncompr is still mostly zeroes, so it should compress - * very well: - */ - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - if (c_stream.avail_in != 0) { - fprintf(stderr, "deflate not greedy\n"); - exit(1); - } - - /* Feed in already compressed data and switch to no compression: */ - deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); - c_stream.next_in = compr; - c_stream.avail_in = (uInt)comprLen/2; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - /* Switch back to compressing mode: */ - deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); - c_stream.next_in = uncompr; - c_stream.avail_in = (uInt)uncomprLen; - err = deflate(&c_stream, Z_NO_FLUSH); - CHECK_ERR(err, "deflate"); - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with large buffers - */ -void test_large_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - for (;;) { - d_stream.next_out = uncompr; /* discard the output */ - d_stream.avail_out = (uInt)uncomprLen; - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - CHECK_ERR(err, "large inflate"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (d_stream.total_out != 2*uncomprLen + comprLen/2) { - fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); - exit(1); - } else { - printf("large_inflate(): OK\n"); - } -} - -/* =========================================================================== - * Test deflate() with full flush - */ -void test_flush(compr, comprLen) - Byte *compr; - uLong *comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - uInt len = (uInt)strlen(hello)+1; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - c_stream.next_in = (Bytef*)hello; - c_stream.next_out = compr; - c_stream.avail_in = 3; - c_stream.avail_out = (uInt)*comprLen; - err = deflate(&c_stream, Z_FULL_FLUSH); - CHECK_ERR(err, "deflate"); - - compr[3]++; /* force an error in first compressed block */ - c_stream.avail_in = len - 3; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - CHECK_ERR(err, "deflate"); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); - - *comprLen = c_stream.total_out; -} - -/* =========================================================================== - * Test inflateSync() - */ -void test_sync(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = 2; /* just read the zlib header */ - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - inflate(&d_stream, Z_NO_FLUSH); - CHECK_ERR(err, "inflate"); - - d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ - err = inflateSync(&d_stream); /* but skip the damaged part */ - CHECK_ERR(err, "inflateSync"); - - err = inflate(&d_stream, Z_FINISH); - if (err != Z_DATA_ERROR) { - fprintf(stderr, "inflate should report DATA_ERROR\n"); - /* Because of incorrect adler32 */ - exit(1); - } - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - printf("after inflateSync(): hel%s\n", (char *)uncompr); -} - -/* =========================================================================== - * Test deflate() with preset dictionary - */ -void test_dict_deflate(compr, comprLen) - Byte *compr; - uLong comprLen; -{ - z_stream c_stream; /* compression stream */ - int err; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - err = deflateInit(&c_stream, Z_BEST_COMPRESSION); - CHECK_ERR(err, "deflateInit"); - - err = deflateSetDictionary(&c_stream, - (const Bytef*)dictionary, sizeof(dictionary)); - CHECK_ERR(err, "deflateSetDictionary"); - - dictId = c_stream.adler; - c_stream.next_out = compr; - c_stream.avail_out = (uInt)comprLen; - - c_stream.next_in = (Bytef*)hello; - c_stream.avail_in = (uInt)strlen(hello)+1; - - err = deflate(&c_stream, Z_FINISH); - if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); - } - err = deflateEnd(&c_stream); - CHECK_ERR(err, "deflateEnd"); -} - -/* =========================================================================== - * Test inflate() with a preset dictionary - */ -void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) - Byte *compr, *uncompr; - uLong comprLen, uncomprLen; -{ - int err; - z_stream d_stream; /* decompression stream */ - - strcpy((char*)uncompr, "garbage"); - - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = compr; - d_stream.avail_in = (uInt)comprLen; - - err = inflateInit(&d_stream); - CHECK_ERR(err, "inflateInit"); - - d_stream.next_out = uncompr; - d_stream.avail_out = (uInt)uncomprLen; - - for (;;) { - err = inflate(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - if (err == Z_NEED_DICT) { - if (d_stream.adler != dictId) { - fprintf(stderr, "unexpected dictionary"); - exit(1); - } - err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, - sizeof(dictionary)); - } - CHECK_ERR(err, "inflate with dict"); - } - - err = inflateEnd(&d_stream); - CHECK_ERR(err, "inflateEnd"); - - if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate with dict\n"); - exit(1); - } else { - printf("inflate with dictionary: %s\n", (char *)uncompr); - } -} - -/* =========================================================================== - * Usage: example [output.gz [input.gz]] - */ - -int main(argc, argv) - int argc; - char *argv[]; -{ - Byte *compr, *uncompr; - uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ - uLong uncomprLen = comprLen; - static const char* myVersion = ZLIB_VERSION; - - if (zlibVersion()[0] != myVersion[0]) { - fprintf(stderr, "incompatible zlib version\n"); - exit(1); - - } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { - fprintf(stderr, "warning: different zlib version\n"); - } - - printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", - ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); - - compr = (Byte*)calloc((uInt)comprLen, 1); - uncompr = (Byte*)calloc((uInt)uncomprLen, 1); - /* compr and uncompr are cleared to avoid reading uninitialized - * data and to ensure that uncompr compresses well. - */ - if (compr == Z_NULL || uncompr == Z_NULL) { - printf("out of memory\n"); - exit(1); - } - test_compress(compr, comprLen, uncompr, uncomprLen); - - test_gzio((argc > 1 ? argv[1] : TESTFILE), - uncompr, uncomprLen); - - test_deflate(compr, comprLen); - test_inflate(compr, comprLen, uncompr, uncomprLen); - - test_large_deflate(compr, comprLen, uncompr, uncomprLen); - test_large_inflate(compr, comprLen, uncompr, uncomprLen); - - test_flush(compr, &comprLen); - test_sync(compr, comprLen, uncompr, uncomprLen); - comprLen = uncomprLen; - - test_dict_deflate(compr, comprLen); - test_dict_inflate(compr, comprLen, uncompr, uncomprLen); - - free(compr); - free(uncompr); - - return 0; -} diff --git a/thirdparty/libz/gzguts.h b/thirdparty/libz/gzguts.h index 0f8fb79f..d87659d0 100644 --- a/thirdparty/libz/gzguts.h +++ b/thirdparty/libz/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -12,7 +12,7 @@ # endif #endif -#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +#ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL @@ -27,13 +27,80 @@ #endif #include +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99, yet still not supported by + Microsoft more than a decade later!), _snprintf does not guarantee null + termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ #ifdef _MSC_VER -# include -# define vsnprintf _vsnprintf +# define snprintf _snprintf #endif #ifndef local @@ -52,7 +119,7 @@ # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else -# ifdef STDC +# ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else @@ -68,7 +135,15 @@ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif -/* default i/o buffer size -- double this for output when reading */ +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ @@ -84,23 +159,25 @@ /* internal gzip file state data structure */ typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ - z_off64_t pos; /* current position in uncompressed data */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer */ unsigned char *out; /* output buffer (double-sized when reading) */ - unsigned char *next; /* next output data to deliver or write */ + int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ - unsigned have; /* amount of output data unused at next */ - int eof; /* true if end of input file reached */ - z_off64_t start; /* where the gzip data started, for rewinding */ - z_off64_t raw; /* where the raw data started, for seeking */ int how; /* 0: get header, 1: copy, 2: decompress */ - int direct; /* true if last read direct, false if gzip */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ diff --git a/thirdparty/libz/gzlib.c b/thirdparty/libz/gzlib.c index 603e60ed..fae202ef 100644 --- a/thirdparty/libz/gzlib.c +++ b/thirdparty/libz/gzlib.c @@ -1,19 +1,23 @@ /* gzlib.c -- zlib functions common to reading and writing gzip files - * Copyright (C) 2004, 2010 Mark Adler + * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif +#endif /* Local functions */ local void gz_reset OF((gz_statep)); -local gzFile gz_open OF((const char *, int, const char *)); +local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE @@ -71,28 +75,40 @@ char ZLIB_INTERNAL *gz_strwinerror (error) local void gz_reset(state) gz_statep state; { + state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ - state->have = 0; /* no output data available */ state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ - state->direct = 1; /* default for empty file */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ - state->pos = 0; /* no uncompressed data yet */ + state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) - const char *path; + const void *path; int fd; const char *mode; { gz_statep state; + size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; /* allocate gzFile structure to return */ - state = malloc(sizeof(gz_state)); + state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ @@ -103,6 +119,7 @@ local gzFile gz_open(path, fd, mode) state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; @@ -124,6 +141,16 @@ local gzFile gz_open(path, fd, mode) return NULL; case 'b': /* ignore -- will request binary anyway */ break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif case 'f': state->strategy = Z_FILTERED; break; @@ -135,6 +162,10 @@ local gzFile gz_open(path, fd, mode) break; case 'F': state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; default: /* could consider as an error, but just ignore */ ; } @@ -147,30 +178,71 @@ local gzFile gz_open(path, fd, mode) return NULL; } + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + /* save the path name for error messages */ - state->path = malloc(strlen(path) + 1); +#ifdef _WIN32 + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } - strcpy(state->path, path); +#ifdef _WIN32 + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif - /* open the file with the appropriate mode (or just use fd) */ - state->fd = fd != -1 ? fd : - open(path, + /* compute the flags for open() */ + oflag = #ifdef O_LARGEFILE - O_LARGEFILE | + O_LARGEFILE | #endif #ifdef O_BINARY - O_BINARY | + O_BINARY | #endif - (state->mode == GZ_READ ? - O_RDONLY : - (O_WRONLY | O_CREAT | ( - state->mode == GZ_WRITE ? - O_TRUNC : - O_APPEND))), - 0666); +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef _WIN32 + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); @@ -216,14 +288,28 @@ gzFile ZEXPORT gzdopen(fd, mode) char *path; /* identifier for error messages */ gzFile gz; - if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ +#else sprintf(path, "", fd); /* for debugging */ +#endif gz = gz_open(path, fd, mode); free(path); return gz; } +/* -- see zlib.h -- */ +#ifdef _WIN32 +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ + return gz_open(path, -2, mode); +} +#endif + /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; @@ -243,8 +329,8 @@ int ZEXPORT gzbuffer(file, size) return -1; /* check and set requested size */ - if (size == 0) - return -1; + if (size < 2) + size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } @@ -261,7 +347,8 @@ int ZEXPORT gzrewind(file) state = (gz_statep)file; /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || state->err != Z_OK) + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ @@ -289,7 +376,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) return -1; /* check that there's no error */ - if (state->err != Z_OK) + if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ @@ -298,31 +385,32 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) - offset -= state->pos; + offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && - state->pos + offset >= state->raw) { - ret = LSEEK(state->fd, offset - state->have, SEEK_CUR); + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; - state->have = 0; + state->x.have = 0; state->eof = 0; + state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; - state->pos += offset; - return state->pos; + state->x.pos += offset; + return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; - offset += state->pos; + offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ @@ -331,11 +419,11 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { - n = GT_OFF(state->have) || (z_off64_t)state->have > offset ? - (unsigned)offset : state->have; - state->have -= n; - state->next += n; - state->pos += n; + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; offset -= n; } @@ -344,7 +432,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) state->seek = 1; state->skip = offset; } - return state->pos + offset; + return state->x.pos + offset; } /* -- see zlib.h -- */ @@ -373,7 +461,7 @@ z_off64_t ZEXPORT gztell64(file) return -1; /* return position */ - return state->pos + (state->seek ? state->skip : 0); + return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ @@ -433,8 +521,7 @@ int ZEXPORT gzeof(file) return 0; /* return end-of-file state */ - return state->mode == GZ_READ ? - (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0; + return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ @@ -454,7 +541,8 @@ const char * ZEXPORT gzerror(file, errnum) /* return error information */ if (errnum != NULL) *errnum = state->err; - return state->msg == NULL ? "" : state->msg; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ @@ -471,8 +559,10 @@ void ZEXPORT gzclearerr(file) return; /* clear error and end-of-file */ - if (state->mode == GZ_READ) + if (state->mode == GZ_READ) { state->eof = 0; + state->past = 0; + } gz_error(state, Z_OK, NULL); } @@ -494,26 +584,33 @@ void ZLIB_INTERNAL gz_error(state, err, msg) state->msg = NULL; } + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; - /* for an out of memory error, save as static string */ - if (err == Z_MEM_ERROR) { - state->msg = (char *)msg; + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) return; - } /* construct error message with path */ - if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { state->err = Z_MEM_ERROR; - state->msg = (char *)"out of memory"; return; } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); +#endif return; } diff --git a/thirdparty/libz/gzread.c b/thirdparty/libz/gzread.c index 548201ab..bf4538eb 100644 --- a/thirdparty/libz/gzread.c +++ b/thirdparty/libz/gzread.c @@ -1,5 +1,5 @@ /* gzread.c -- zlib functions for reading gzip files - * Copyright (C) 2004, 2005, 2010 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,10 +8,9 @@ /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); -local int gz_next4 OF((gz_statep, unsigned long *)); -local int gz_head OF((gz_statep)); +local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); -local int gz_make OF((gz_statep)); +local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from @@ -46,73 +45,54 @@ local int gz_load(state, buf, len, have) error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. - gz_avail() assumes that strm->avail_in == 0. */ + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ local int gz_avail(state) gz_statep state; { + unsigned got; z_streamp strm = &(state->strm); - if (state->err != Z_OK) + if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { - if (gz_load(state, state->in, state->size, - (unsigned *)&(strm->avail_in)) == -1) + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) return -1; + strm->avail_in += got; strm->next_in = state->in; } return 0; } -/* Get next byte from input, or -1 if end or error. */ -#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ - (strm->avail_in == 0 ? -1 : \ - (strm->avail_in--, *(strm->next_in)++))) - -/* Get a four-byte little-endian integer and return 0 on success and the value - in *ret. Otherwise -1 is returned and *ret is not modified. */ -local int gz_next4(state, ret) - gz_statep state; - unsigned long *ret; -{ - int ch; - unsigned long val; - z_streamp strm = &(state->strm); - - val = NEXT(); - val += (unsigned)NEXT() << 8; - val += (unsigned long)NEXT() << 16; - ch = NEXT(); - if (ch == -1) - return -1; - val += (unsigned long)ch << 24; - *ret = val; - return 0; -} - -/* Look for gzip header, set up for inflate or copy. state->have must be zero. +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will - be set to GZIP for decompression, and the gzip header will be skipped so - that the next available input data is the raw deflate stream. If direct - copying, then leftover input data from the input buffer will be copied to - the output buffer. In that case, all further file reads will be directly to - either the output buffer or a user buffer. If decompressing, the inflate - state and the check value will be initialized. gz_head() will return 0 on - success or -1 on failure. Failures may include read errors or gzip header - errors. */ -local int gz_head(state) + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) gz_statep state; { z_streamp strm = &(state->strm); - int flags; - unsigned len; /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ - state->in = malloc(state->want); - state->out = malloc(state->want << 1); + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); @@ -129,7 +109,7 @@ local int gz_head(state) state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; - if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; @@ -138,83 +118,45 @@ local int gz_head(state) } } - /* get some data in the input buffer */ - if (strm->avail_in == 0) { + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } - /* look for the gzip magic header bytes 31 and 139 */ - if (strm->next_in[0] == 31) { - strm->avail_in--; - strm->next_in++; - if (strm->avail_in == 0 && gz_avail(state) == -1) - return -1; - if (strm->avail_in && strm->next_in[0] == 139) { - /* we have a gzip header, woo hoo! */ - strm->avail_in--; - strm->next_in++; - - /* skip rest of header */ - if (NEXT() != 8) { /* compression method */ - gz_error(state, Z_DATA_ERROR, "unknown compression method"); - return -1; - } - flags = NEXT(); - if (flags & 0xe0) { /* reserved flag bits */ - gz_error(state, Z_DATA_ERROR, "unknown header flags set"); - return -1; - } - NEXT(); /* modification time */ - NEXT(); - NEXT(); - NEXT(); - NEXT(); /* extra flags */ - NEXT(); /* operating system */ - if (flags & 4) { /* extra field */ - len = (unsigned)NEXT(); - len += (unsigned)NEXT() << 8; - while (len--) - if (NEXT() < 0) - break; - } - if (flags & 8) /* file name */ - while (NEXT() > 0) - ; - if (flags & 16) /* comment */ - while (NEXT() > 0) - ; - if (flags & 2) { /* header crc */ - NEXT(); - NEXT(); - } - /* an unexpected end of file is not checked for here -- it will be - noticed on the first request for uncompressed data */ - - /* set up for decompression */ - inflateReset(strm); - strm->adler = crc32(0L, Z_NULL, 0); - state->how = GZIP; - state->direct = 0; - return 0; - } - else { - /* not a gzip file -- save first byte (31) and fall to raw i/o */ - state->out[0] = 31; - state->have = 1; - } + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; } - /* doing raw i/o, save start of raw data for seeking, copy any leftover - input to output -- this assumes that the output buffer is larger than - the input buffer, which also assures space for gzungetc() */ - state->raw = state->pos; - state->next = state->out; + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; if (strm->avail_in) { - memcpy(state->next + state->have, strm->next_in, strm->avail_in); - state->have += strm->avail_in; + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; @@ -223,19 +165,15 @@ local int gz_head(state) } /* Decompress from input to the provided next_out and avail_out in the state. - If the end of the compressed data is reached, then verify the gzip trailer - check value and length (modulo 2^32). state->have and state->next are set - to point to the just decompressed data, and the crc is updated. If the - trailer is verified, state->how is reset to LOOK to look for the next gzip - stream or raw data, once state->have is depleted. Returns 0 on success, -1 - on failure. Failures may include invalid compressed data or a failed gzip - trailer verification. */ + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ local int gz_decomp(state) gz_statep state; { - int ret; + int ret = Z_OK; unsigned had; - unsigned long crc, len; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ @@ -245,15 +183,15 @@ local int gz_decomp(state) if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { - gz_error(state, Z_DATA_ERROR, "unexpected end of file"); - return -1; + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, - "internal error: inflate stream corrupt"); + "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { @@ -262,67 +200,55 @@ local int gz_decomp(state) } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, - strm->msg == NULL ? "compressed data error" : strm->msg); + strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); - /* update available output and crc check value */ - state->have = had - strm->avail_out; - state->next = strm->next_out - state->have; - strm->adler = crc32(strm->adler, state->next, state->have); + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; - /* check gzip trailer if at end of deflate stream */ - if (ret == Z_STREAM_END) { - if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { - gz_error(state, Z_DATA_ERROR, "unexpected end of file"); - return -1; - } - if (crc != strm->adler) { - gz_error(state, Z_DATA_ERROR, "incorrect data check"); - return -1; - } - if (len != (strm->total_out & 0xffffffffL)) { - gz_error(state, Z_DATA_ERROR, "incorrect length check"); - return -1; - } - state->how = LOOK; /* ready for next stream, once have is 0 (leave - state->direct unchanged to remember how) */ - } + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; /* good decompression */ return 0; } -/* Make data and put in the output buffer. Assumes that state->have == 0. +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is - looked for (and skipped if found) to determine wither to copy or decompress. - Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY - or GZIP unless the end of the input file has been reached and all data has - been processed. */ -local int gz_make(state) + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) gz_statep state; { z_streamp strm = &(state->strm); - if (state->how == LOOK) { /* look for gzip header */ - if (gz_head(state) == -1) - return -1; - if (state->have) /* got some data from gz_head() */ + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; return 0; - } - if (state->how == COPY) { /* straight copy */ - if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) - return -1; - state->next = state->out; - } - else if (state->how == GZIP) { /* decompress */ - strm->avail_out = state->size << 1; - strm->next_out = state->out; - if (gz_decomp(state) == -1) - return -1; - } + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } @@ -336,12 +262,12 @@ local int gz_skip(state, len) /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ - if (state->have) { - n = GT_OFF(state->have) || (z_off64_t)state->have > len ? - (unsigned)len : state->have; - state->have -= n; - state->next += n; - state->pos += n; + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; len -= n; } @@ -352,7 +278,7 @@ local int gz_skip(state, len) /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ - if (gz_make(state) == -1) + if (gz_fetch(state) == -1) return -1; } return 0; @@ -374,14 +300,15 @@ int ZEXPORT gzread(file, buf, len) state = (gz_statep)file; strm = &(state->strm); - /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || state->err != Z_OK) + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { - gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return -1; } @@ -400,49 +327,51 @@ int ZEXPORT gzread(file, buf, len) got = 0; do { /* first just try copying data from the output buffer */ - if (state->have) { - n = state->have > len ? len : state->have; - memcpy(buf, state->next, n); - state->next += n; - state->have -= n; + if (state->x.have) { + n = state->x.have > len ? len : state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ - else if (state->eof && strm->avail_in == 0) + else if (state->eof && strm->avail_in == 0) { + state->past = 1; /* tried to read past end */ break; + } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || len < (state->size << 1)) { /* get more output, looking for header if required */ - if (gz_make(state) == -1) + if (gz_fetch(state) == -1) return -1; - continue; /* no progress yet -- go back to memcpy() above */ + continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ - if (gz_load(state, buf, len, &n) == -1) + if (gz_load(state, (unsigned char *)buf, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; - strm->next_out = buf; + strm->next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return -1; - n = state->have; - state->have = 0; + n = state->x.have; + state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; - state->pos += n; + state->x.pos += n; } while (len); /* return number of bytes read into user buffer (will fit in int) */ @@ -450,6 +379,11 @@ int ZEXPORT gzread(file, buf, len) } /* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif int ZEXPORT gzgetc(file) gzFile file; { @@ -462,15 +396,16 @@ int ZEXPORT gzgetc(file) return -1; state = (gz_statep)file; - /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || state->err != Z_OK) + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ - if (state->have) { - state->have--; - state->pos++; - return *(state->next)++; + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; } /* nothing there -- try gzread() */ @@ -478,6 +413,12 @@ int ZEXPORT gzgetc(file) return ret < 1 ? -1 : buf[0]; } +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); +} + /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; @@ -490,8 +431,9 @@ int ZEXPORT gzungetc(c, file) return -1; state = (gz_statep)file; - /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || state->err != Z_OK) + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ @@ -506,32 +448,34 @@ int ZEXPORT gzungetc(c, file) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ - if (state->have == 0) { - state->have = 1; - state->next = state->out + (state->size << 1) - 1; - state->next[0] = c; - state->pos--; + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ - if (state->have == (state->size << 1)) { - gz_error(state, Z_BUF_ERROR, "out of room to push characters"); + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ - if (state->next == state->out) { - unsigned char *src = state->out + state->have; + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; - state->next = dest; + state->x.next = dest; } - state->have++; - state->next--; - state->next[0] = c; - state->pos--; + state->x.have++; + state->x.next--; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; return c; } @@ -551,8 +495,9 @@ char * ZEXPORT gzgets(file, buf, len) return NULL; state = (gz_statep)file; - /* check that we're reading and that there's no error */ - if (state->mode != GZ_READ || state->err != Z_OK) + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ @@ -569,32 +514,31 @@ char * ZEXPORT gzgets(file, buf, len) left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ - if (state->have == 0) { - if (gz_make(state) == -1) - return NULL; /* error */ - if (state->have == 0) { /* end of file */ - if (buf == str) /* got bupkus */ - return NULL; - break; /* got something -- return it */ - } + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ } /* look for end-of-line in current output buffer */ - n = state->have > left ? left : state->have; - eol = memchr(state->next, '\n', n); + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) - n = (unsigned)(eol - state->next) + 1; + n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ - memcpy(buf, state->next, n); - state->have -= n; - state->next += n; - state->pos += n; + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); - /* found end-of-line or out of space -- terminate string and return it */ + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; buf[0] = 0; return str; } @@ -610,16 +554,12 @@ int ZEXPORT gzdirect(file) return 0; state = (gz_statep)file; - /* check that we're reading */ - if (state->mode != GZ_READ) - return 0; - /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ - if (state->how == LOOK && state->have == 0) - (void)gz_head(state); + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); - /* return 1 if reading direct, 0 if decompressing a gzip stream */ + /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } @@ -627,7 +567,7 @@ int ZEXPORT gzdirect(file) int ZEXPORT gzclose_r(file) gzFile file; { - int ret; + int ret, err; gz_statep state; /* get internal structure */ @@ -645,9 +585,10 @@ int ZEXPORT gzclose_r(file) free(state->out); free(state->in); } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); - return ret ? Z_ERRNO : Z_OK; + return ret ? Z_ERRNO : err; } diff --git a/thirdparty/libz/gzwrite.c b/thirdparty/libz/gzwrite.c index e8defc68..aa767fbf 100644 --- a/thirdparty/libz/gzwrite.c +++ b/thirdparty/libz/gzwrite.c @@ -1,5 +1,5 @@ /* gzwrite.c -- zlib functions for writing gzip files - * Copyright (C) 2004, 2005, 2010 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -18,44 +18,55 @@ local int gz_init(state) int ret; z_streamp strm = &(state->strm); - /* allocate input and output buffers */ - state->in = malloc(state->want); - state->out = malloc(state->want); - if (state->in == NULL || state->out == NULL) { - if (state->out != NULL) - free(state->out); - if (state->in != NULL) - free(state->in); + /* allocate input buffer */ + state->in = (unsigned char *)malloc(state->want); + if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } - /* allocate deflate memory, set up for gzip compression */ - strm->zalloc = Z_NULL; - strm->zfree = Z_NULL; - strm->opaque = Z_NULL; - ret = deflateInit2(strm, state->level, Z_DEFLATED, - 15 + 16, 8, state->strategy); - if (ret != Z_OK) { - free(state->in); - gz_error(state, Z_MEM_ERROR, "out of memory"); - return -1; + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } } /* mark state as initialized */ state->size = state->want; - /* initialize write buffer */ - strm->avail_out = state->size; - strm->next_out = state->out; - state->next = strm->next_out; + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, - then the deflate() state is reset to start a new gzip stream. */ + then the deflate() state is reset to start a new gzip stream. If gz->direct + is true, then simply write to the output file without compressing, and + ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; @@ -68,6 +79,17 @@ local int gz_comp(state, flush) if (state->size == 0 && gz_init(state) == -1) return -1; + /* write directly if requested */ + if (state->direct) { + got = write(state->fd, strm->next_in, strm->avail_in); + if (got < 0 || (unsigned)got != strm->avail_in) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in = 0; + return 0; + } + /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { @@ -75,8 +97,8 @@ local int gz_comp(state, flush) doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { - have = (unsigned)(strm->next_out - state->next); - if (have && ((got = write(state->fd, state->next, have)) < 0 || + have = (unsigned)(strm->next_out - state->x.next); + if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; @@ -85,7 +107,7 @@ local int gz_comp(state, flush) strm->avail_out = state->size; strm->next_out = state->out; } - state->next = strm->next_out; + state->x.next = strm->next_out; } /* compress */ @@ -131,7 +153,7 @@ local int gz_zero(state, len) } strm->avail_in = n; strm->next_in = state->in; - state->pos += n; + state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; @@ -146,7 +168,6 @@ int ZEXPORT gzwrite(file, buf, len) unsigned len; { unsigned put = len; - unsigned n; gz_statep state; z_streamp strm; @@ -163,7 +184,7 @@ int ZEXPORT gzwrite(file, buf, len) /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { - gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } @@ -186,16 +207,19 @@ int ZEXPORT gzwrite(file, buf, len) if (len < state->size) { /* copy to input buffer, compress when full */ do { + unsigned have, copy; + if (strm->avail_in == 0) strm->next_in = state->in; - n = state->size - strm->avail_in; - if (n > len) - n = len; - memcpy(strm->next_in + strm->avail_in, buf, n); - strm->avail_in += n; - state->pos += n; - buf = (char *)buf + n; - len -= n; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + copy = state->size - have; + if (copy > len) + copy = len; + memcpy(state->in + have, buf, copy); + strm->avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); @@ -207,8 +231,8 @@ int ZEXPORT gzwrite(file, buf, len) /* directly compress user buffer to file */ strm->avail_in = len; - strm->next_in = (voidp)buf; - state->pos += len; + strm->next_in = (z_const Bytef *)buf; + state->x.pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } @@ -222,6 +246,7 @@ int ZEXPORT gzputc(file, c) gzFile file; int c; { + unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; @@ -245,19 +270,23 @@ int ZEXPORT gzputc(file, c) /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ - if (strm->avail_in < state->size) { + if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; - strm->next_in[strm->avail_in++] = c; - state->pos++; - return c; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; - return c; + return c & 0xff; } /* -- see zlib.h -- */ @@ -274,16 +303,15 @@ int ZEXPORT gzputs(file, str) return ret == 0 && len != 0 ? -1 : ret; } -#ifdef STDC +#if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ -int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int size, len; gz_statep state; z_streamp strm; - va_list va; /* get internal structure */ if (file == NULL) @@ -313,25 +341,20 @@ int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; - va_start(va, format); #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void - (void)vsprintf(state->in, format, va); - va_end(va); + (void)vsprintf((char *)(state->in), format, va); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else - len = vsprintf(state->in, format, va); - va_end(va); + len = vsprintf((char *)(state->in), format, va); # endif #else # ifdef HAS_vsnprintf_void - (void)vsnprintf(state->in, size, format, va); - va_end(va); - len = strlen(state->in); + (void)vsnprintf((char *)(state->in), size, format, va); + len = strlen((char *)(state->in)); # else len = vsnprintf((char *)(state->in), size, format, va); - va_end(va); # endif #endif @@ -342,11 +365,22 @@ int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; - state->pos += len; + state->x.pos += len; return len; } -#else /* !STDC */ +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, @@ -366,6 +400,10 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, state = (gz_statep)file; strm = &(state->strm); + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return 0; + /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; @@ -390,22 +428,23 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, state->in[size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void - sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else - len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void - snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(state->in); + len = strlen((char *)(state->in)); # else - len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, + a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, + a19, a20); # endif #endif @@ -416,7 +455,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; - state->pos += len; + state->x.pos += len; return len; } @@ -500,7 +539,7 @@ int ZEXPORT gzsetparams(file, level, strategy) int ZEXPORT gzclose_w(file) gzFile file; { - int ret = 0; + int ret = Z_OK; gz_statep state; /* get internal structure */ @@ -515,17 +554,24 @@ int ZEXPORT gzclose_w(file) /* check for seek request */ if (state->seek) { state->seek = 0; - ret += gz_zero(state, state->skip); + if (gz_zero(state, state->skip) == -1) + ret = state->err; } /* flush, free memory, and close file */ - ret += gz_comp(state, Z_FINISH); - (void)deflateEnd(&(state->strm)); - free(state->out); - free(state->in); + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } gz_error(state, Z_OK, NULL); free(state->path); - ret += close(state->fd); + if (close(state->fd) == -1) + ret = Z_ERRNO; free(state); - return ret ? Z_ERRNO : Z_OK; + return ret; } diff --git a/thirdparty/libz/infback.c b/thirdparty/libz/infback.c index af3a8c96..f3833c2e 100644 --- a/thirdparty/libz/infback.c +++ b/thirdparty/libz/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2009 Mark Adler + * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -42,10 +42,19 @@ int stream_size; return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; @@ -246,7 +255,7 @@ out_func out; void FAR *out_desc; { struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ + z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ @@ -394,7 +403,6 @@ void FAR *out_desc; PULLBYTE(); } if (here.val < 16) { - NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; } diff --git a/thirdparty/libz/inffast.c b/thirdparty/libz/inffast.c index 2f1d60b4..bda59ceb 100644 --- a/thirdparty/libz/inffast.c +++ b/thirdparty/libz/inffast.c @@ -1,5 +1,5 @@ /* inffast.c -- fast decoding - * Copyright (C) 1995-2008, 2010 Mark Adler + * Copyright (C) 1995-2008, 2010, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -69,8 +69,8 @@ z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ diff --git a/thirdparty/libz/inffixed.h b/thirdparty/libz/inffixed.h index 75ed4b59..d6283277 100644 --- a/thirdparty/libz/inffixed.h +++ b/thirdparty/libz/inffixed.h @@ -2,9 +2,9 @@ * Generated automatically by makefixed(). */ - /* 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. + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { diff --git a/thirdparty/libz/inflate.c b/thirdparty/libz/inflate.c index a8431abe..870f89bb 100644 --- a/thirdparty/libz/inflate.c +++ b/thirdparty/libz/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2010 Mark Adler + * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -93,14 +93,15 @@ /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); -int ZEXPORT inflateReset(strm) +int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; @@ -109,15 +110,13 @@ z_streamp strm; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; - state->wsize = 0; - state->whave = 0; - state->wnext = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; @@ -127,6 +126,19 @@ z_streamp strm; return Z_OK; } +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; @@ -180,10 +192,19 @@ int stream_size; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; @@ -321,8 +342,8 @@ void makefixed() low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } @@ -355,12 +376,13 @@ void makefixed() output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -local int updatewindow(strm, out) +local int updatewindow(strm, end, copy) z_streamp strm; -unsigned out; +const Bytef *end; +unsigned copy; { struct inflate_state FAR *state; - unsigned copy, dist; + unsigned dist; state = (struct inflate_state FAR *)strm->state; @@ -380,19 +402,18 @@ unsigned out; } /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; - zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); + zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); + zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } @@ -499,11 +520,6 @@ unsigned out; bits -= bits & 7; \ } while (0) -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is @@ -591,7 +607,7 @@ z_streamp strm; int flush; { struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ + z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ @@ -797,7 +813,7 @@ int flush; #endif case DICTID: NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); + strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: @@ -905,7 +921,7 @@ int flush; while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; - state->lencode = (code const FAR *)(state->next); + state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); @@ -925,7 +941,6 @@ int flush; PULLBYTE(); } if (here.val < 16) { - NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; } @@ -980,7 +995,7 @@ int flush; values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; - state->lencode = (code const FAR *)(state->next); + state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); @@ -989,7 +1004,7 @@ int flush; state->mode = BAD; break; } - state->distcode = (code const FAR *)(state->next); + state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); @@ -1170,7 +1185,7 @@ int flush; #ifdef GUNZIP state->flags ? hold : #endif - REVERSE(hold)) != state->check) { + ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; @@ -1214,8 +1229,9 @@ int flush; */ inf_leave: RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } @@ -1249,13 +1265,37 @@ z_streamp strm; return Z_OK; } +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; - unsigned long id; + unsigned long dictid; + int ret; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; @@ -1263,29 +1303,21 @@ uInt dictLength; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; - /* check for correct dictionary id */ + /* check for correct dictionary identifier */ if (state->mode == DICT) { - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) return Z_DATA_ERROR; } - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { state->mode = MEM; return Z_MEM_ERROR; } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; @@ -1321,7 +1353,7 @@ gz_headerp head; */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; -unsigned char FAR *buf; +const unsigned char FAR *buf; unsigned len; { unsigned got; @@ -1433,8 +1465,8 @@ z_streamp source; } /* copy state */ - zmemcpy(dest, source, sizeof(z_stream)); - zmemcpy(copy, state, sizeof(struct inflate_state)); + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); diff --git a/thirdparty/libz/inftrees.c b/thirdparty/libz/inftrees.c index 11e9c52a..44d89cf2 100644 --- a/thirdparty/libz/inftrees.c +++ b/thirdparty/libz/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2010 Mark Adler + * Copyright (C) 1995-2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; + " inflate 1.2.8 Copyright 1995-2013 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 @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 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, @@ -208,8 +208,8 @@ unsigned short FAR *work; mask = used - 1; /* mask for comparing low */ /* check available table space */ - if ((type == LENS && used >= ENOUGH_LENS) || - (type == DISTS && used >= ENOUGH_DISTS)) + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ @@ -277,8 +277,8 @@ unsigned short FAR *work; /* check for enough space */ used += 1U << curr; - if ((type == LENS && used >= ENOUGH_LENS) || - (type == DISTS && used >= ENOUGH_DISTS)) + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ @@ -289,38 +289,14 @@ unsigned short FAR *work; } } - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)(len - drop); - here.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - here.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = here; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; } /* set return parameters */ diff --git a/thirdparty/libz/minigzip.c b/thirdparty/libz/minigzip.c deleted file mode 100644 index 9825ccc3..00000000 --- a/thirdparty/libz/minigzip.c +++ /dev/null @@ -1,440 +0,0 @@ -/* minigzip.c -- simulate gzip using the zlib compression library - * Copyright (C) 1995-2006, 2010 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * minigzip is a minimal implementation of the gzip utility. This is - * only an example of using zlib and isn't meant to replace the - * full-featured gzip. No attempt is made to deal with file systems - * limiting names to 14 or 8+3 characters, etc... Error checking is - * very limited. So use minigzip only for testing; use gzip for the - * real thing. On MSDOS, use only on file names without extension - * or in pipe mode. - */ - -/* @(#) $Id$ */ - -#include "zlib.h" -#include - -#ifdef STDC -# include -# include -#endif - -#ifdef USE_MMAP -# include -# include -# include -#endif - -#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) -# include -# include -# ifdef UNDER_CE -# include -# endif -# 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 - -#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) -#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ - extern int unlink OF((const char *)); -#endif -#endif - -#if defined(UNDER_CE) -# include -# define perror(s) pwinerror(s) - -/* Map the Windows error number in ERROR to a locale-dependent error - message string and return a pointer to it. Typically, the values - for ERROR come from GetLastError. - - The string pointed to shall not be modified by the application, - but may be overwritten by a subsequent call to strwinerror - - The strwinerror function does not change the current setting - of GetLastError. */ - -static char *strwinerror (error) - DWORD error; -{ - static char buf[1024]; - - wchar_t *msgbuf; - DWORD lasterr = GetLastError(); - DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ALLOCATE_BUFFER, - NULL, - error, - 0, /* Default language */ - (LPVOID)&msgbuf, - 0, - NULL); - if (chars != 0) { - /* If there is an \r\n appended, zap it. */ - if (chars >= 2 - && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { - chars -= 2; - msgbuf[chars] = 0; - } - - if (chars > sizeof (buf) - 1) { - chars = sizeof (buf) - 1; - msgbuf[chars] = 0; - } - - wcstombs(buf, msgbuf, chars + 1); - LocalFree(msgbuf); - } - else { - sprintf(buf, "unknown win32 error (%ld)", error); - } - - SetLastError(lasterr); - return buf; -} - -static void pwinerror (s) - const char *s; -{ - if (s && *s) - fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); - else - fprintf(stderr, "%s\n", strwinerror(GetLastError ())); -} - -#endif /* UNDER_CE */ - -#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 = (int)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; - - if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { - fprintf(stderr, "%s: filename too long\n", prog); - exit(1); - } - - 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; - size_t len = strlen(file); - - if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { - fprintf(stderr, "%s: filename too long\n", prog); - exit(1); - } - - 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 [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] - * -c : write to standard output - * -d : decompress - * -f : compress with Z_FILTERED - * -h : compress with Z_HUFFMAN_ONLY - * -r : compress with Z_RLE - * -1 to -9 : compression level - */ - -int main(argc, argv) - int argc; - char *argv[]; -{ - int copyout = 0; - int uncompr = 0; - gzFile file; - char *bname, outmode[20]; - - strcpy(outmode, "wb6 "); - - prog = argv[0]; - bname = strrchr(argv[0], '/'); - if (bname) - bname++; - else - bname = argv[0]; - argc--, argv++; - - if (!strcmp(bname, "gunzip")) - uncompr = 1; - else if (!strcmp(bname, "zcat")) - copyout = uncompr = 1; - - while (argc > 0) { - if (strcmp(*argv, "-c") == 0) - copyout = 1; - else 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 (strcmp(*argv, "-r") == 0) - outmode[3] = 'R'; - else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && - (*argv)[2] == 0) - outmode[2] = (*argv)[1]; - else - break; - argc--, argv++; - } - if (outmode[3] == ' ') - outmode[3] = 0; - 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 { - if (copyout) { - SET_BINARY_MODE(stdout); - } - do { - if (uncompr) { - if (copyout) { - file = gzopen(*argv, "rb"); - if (file == NULL) - fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); - else - gz_uncompress(file, stdout); - } else { - file_uncompress(*argv); - } - } else { - if (copyout) { - FILE * in = fopen(*argv, "rb"); - - if (in == NULL) { - perror(*argv); - } else { - file = gzdopen(fileno(stdout), outmode); - if (file == NULL) error("can't gzdopen stdout"); - - gz_compress(in, file); - } - - } else { - file_compress(*argv, outmode); - } - } - } while (argv++, --argc); - } - return 0; -} diff --git a/thirdparty/libz/trees.c b/thirdparty/libz/trees.c index 56e9bb1c..1fd7759e 100644 --- a/thirdparty/libz/trees.c +++ b/thirdparty/libz/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2010 Jean-loup Gailly + * Copyright (C) 1995-2012 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -74,11 +74,6 @@ local const uch bl_order[BL_CODES] * 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. */ @@ -151,8 +146,8 @@ 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 compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); @@ -399,7 +394,6 @@ void ZLIB_INTERNAL _tr_init(s) 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; @@ -882,16 +876,18 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + /* =========================================================================== * 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 ZLIB_INTERNAL _tr_align(s) deflate_state *s; @@ -902,20 +898,6 @@ void ZLIB_INTERNAL _tr_align(s) 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; } /* =========================================================================== @@ -990,7 +972,8 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif @@ -998,7 +981,8 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) send_bits(s, (DYN_TREES<<1)+last, 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); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif @@ -1075,8 +1059,8 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) */ local void compress_block(s, ltree, dtree) deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ @@ -1118,7 +1102,6 @@ local void compress_block(s, ltree, dtree) } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; } /* =========================================================================== @@ -1226,7 +1209,6 @@ local void copy_block(s, buf, len, header) 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); diff --git a/thirdparty/libz/uncompr.c b/thirdparty/libz/uncompr.c index ad98be3a..242e9493 100644 --- a/thirdparty/libz/uncompr.c +++ b/thirdparty/libz/uncompr.c @@ -30,7 +30,7 @@ int ZEXPORT uncompress (dest, destLen, source, sourceLen) z_stream stream; int err; - stream.next_in = (Bytef*)source; + stream.next_in = (z_const 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; diff --git a/thirdparty/libz/zlib.h b/thirdparty/libz/zlib.h index bfbba83e..3e0c7672 100644 --- a/thirdparty/libz/zlib.h +++ b/thirdparty/libz/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.5, April 19th, 2010 + version 1.2.8, April 28th, 2013 - Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2013 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 @@ -24,8 +24,8 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.5" -#define ZLIB_VERNUM 0x1250 +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /* @@ -83,15 +83,15 @@ typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ + z_const 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 */ + uLong total_in; /* total number 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 */ + uLong total_out; /* total number of bytes output so far */ - char *msg; /* last error message, NULL if no error */ + z_const 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 */ @@ -327,8 +327,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); 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 the - value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and 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). @@ -451,23 +452,29 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); 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 approach may be used for the single - inflate() call. + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK or Z_TREES is used. + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary + below), inflate sets strm->adler to the Adler-32 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, + strm->adler to the Adler-32 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 @@ -478,7 +485,9 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. 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 @@ -580,10 +589,15 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, 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). + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. 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 @@ -610,8 +624,8 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) 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(). + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, @@ -688,9 +702,29 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. */ +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); @@ -703,8 +737,9 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, than or equal to 16, and that many of the least significant bits of value will be inserted in the output. - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, @@ -790,10 +825,11 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is @@ -803,19 +839,38 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + 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 + Skips invalid compressed data until a possible full flush point (see above + for 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. + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible 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 inflateCopy OF((z_streamp dest, @@ -962,12 +1017,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, @@ -975,11 +1031,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. @@ -1088,6 +1145,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); 27-31: 0 (reserved) */ +#ifndef Z_SOLO /* utility functions */ @@ -1149,10 +1207,11 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, 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 or incomplete. + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. */ - /* gzip file access functions */ /* @@ -1162,7 +1221,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, wrapper, documented in RFC 1952, wrapped around a deflate stream. */ -typedef voidp gzFile; /* opaque gzip file descriptor */ +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); @@ -1172,13 +1231,28 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) Also "a" - can be used instead of "w" to request that the gzip stream that will be - written be appended to the file. "+" will result in an error, since reading - and writing to the same gzip file is not supported. + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. 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. + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was @@ -1197,7 +1271,11 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not @@ -1235,14 +1313,26 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); 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. + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream, or failing that, reading the rest - of the input file directly without decompression. The entire input file - will be read if gzread is called until it returns less than the requested - len. + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. @@ -1256,7 +1346,7 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, error. */ -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of @@ -1301,7 +1391,10 @@ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); 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. + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); @@ -1397,9 +1490,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. This state can change from - false to true while reading the input file if the end of a gzip stream is - reached, but is followed by data that is not another gzip stream. + (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. @@ -1408,6 +1499,13 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); @@ -1419,7 +1517,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, or Z_OK on success. + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); @@ -1457,6 +1556,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); file that is being written concurrently. */ +#endif /* !Z_SOLO */ /* checksum functions */ @@ -1492,16 +1592,17 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the for the crc. Pre- and post-conditioning (one's - complement) is performed within this function so it shouldn't be done by the - application. + 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: @@ -1544,17 +1645,42 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); #define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if @@ -1562,7 +1688,7 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +#ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); @@ -1571,14 +1697,23 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif -#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# ifdef _LARGEFILE64_SOURCE +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); @@ -1595,6 +1730,13 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; @@ -1603,8 +1745,21 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif #ifdef __cplusplus } diff --git a/thirdparty/libz/zutil.c b/thirdparty/libz/zutil.c index 898ed345..23d2ebef 100644 --- a/thirdparty/libz/zutil.c +++ b/thirdparty/libz/zutil.c @@ -1,17 +1,20 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005, 2010 Jean-loup Gailly. + * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif -const char * const z_errmsg[10] = { +z_const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ @@ -85,27 +88,27 @@ uLong ZEXPORT zlibCompileFlags() #ifdef FASTEST flags += 1L << 21; #endif -#ifdef STDC +#if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf - flags += 1L << 25; + flags += 1L << 25; # ifdef HAS_vsprintf_void - flags += 1L << 26; + flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void - flags += 1L << 26; + flags += 1L << 26; # endif # endif #else - flags += 1L << 24; + flags += 1L << 24; # ifdef NO_snprintf - flags += 1L << 25; + flags += 1L << 25; # ifdef HAS_sprintf_void - flags += 1L << 26; + flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void - flags += 1L << 26; + flags += 1L << 26; # endif # endif #endif @@ -181,6 +184,7 @@ void ZLIB_INTERNAL zmemzero(dest, len) } #endif +#ifndef Z_SOLO #ifdef SYS16BIT @@ -316,3 +320,5 @@ void ZLIB_INTERNAL zcfree (opaque, ptr) } #endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/thirdparty/libz/zutil.h b/thirdparty/libz/zutil.h index 258fa887..24ab06b1 100644 --- a/thirdparty/libz/zutil.h +++ b/thirdparty/libz/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. + * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -13,7 +13,7 @@ #ifndef ZUTIL_H #define ZUTIL_H -#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +#ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL @@ -21,7 +21,7 @@ #include "zlib.h" -#ifdef STDC +#if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif @@ -29,6 +29,10 @@ # include #endif +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + #ifndef local # define local static #endif @@ -40,13 +44,13 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +extern z_const char * const 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)) + return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ @@ -78,16 +82,18 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # 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 +# ifndef Z_SOLO +# 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 -# else /* MSC or DJGPP */ -# include # endif #endif @@ -107,18 +113,20 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #ifdef OS2 # define OS_CODE 0x06 -# ifdef M_I86 +# if defined(M_I86) && !defined(Z_SOLO) # include # endif #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() */ +# ifndef Z_SOLO +# 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 #endif @@ -153,14 +161,15 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#if defined(__BORLANDC__) +#if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ -#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif @@ -177,42 +186,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* functions */ -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) -# define vsnprintf _vsnprintf -# endif -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) +#if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) @@ -261,14 +235,19 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define Tracecv(c,x) #endif - -voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); -void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif #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);} +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + #endif /* ZUTIL_H */ diff --git a/tools/abi-tracker/openjpeg.json b/tools/abi-tracker/openjpeg.json new file mode 100644 index 00000000..2cfa4438 --- /dev/null +++ b/tools/abi-tracker/openjpeg.json @@ -0,0 +1,132 @@ +{ + "Name": "openjpeg", + "Title": "OpenJPEG", + "SourceUrl": "https://github.com/uclouvain/openjpeg/tags", + "Git": "https://github.com/uclouvain/openjpeg.git", + "Maintainer": "Antonin D.", + "MaintainerUrl": "http://www.openjpeg.org/", + "Package": "version.", + "Configure": "-DCMAKE_C_FLAGS='-fvisibility=hidden -g -Og -w -fpermissive'", + + "Versions": [ + { + "Number": "current", + "Installed": "installed/openjpeg/current", + "Source": "src/openjpeg/current", + "Changelog": "On", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/current/list", + "PublicTypes": "public_types/openjpeg/current/list" + }, + { + "Number": "2.1", + "Installed": "installed/openjpeg/2.1", + "Source": "src/openjpeg/2.1/version.2.1.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/2.1/list", + "PublicTypes": "public_types/openjpeg/2.1/list" + }, + { + "Number": "2.0.1", + "Installed": "installed/openjpeg/2.0.1", + "Source": "src/openjpeg/2.0.1/version.2.0.1.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/2.0.1/list", + "PublicTypes": "public_types/openjpeg/2.0.1/list" + }, + { + "Number": "2.0", + "Installed": "installed/openjpeg/2.0", + "Source": "src/openjpeg/2.0/version.2.0.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "On", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/2.0/list", + "PublicTypes": "public_types/openjpeg/2.0/list" + }, + { + "Number": "1.5.2", + "Installed": "installed/openjpeg/1.5.2", + "Source": "src/openjpeg/1.5.2/version.1.5.2.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.5.2/list", + "PublicTypes": "public_types/openjpeg/1.5.2/list" + }, + { + "Number": "1.5.1", + "Installed": "installed/openjpeg/1.5.1", + "Source": "src/openjpeg/1.5.1/version.1.5.1.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.5.1/list", + "PublicTypes": "public_types/openjpeg/1.5.1/list" + }, + { + "Number": "1.5", + "Installed": "installed/openjpeg/1.5", + "Source": "src/openjpeg/1.5/version.1.5.tar.gz", + "Changelog": "NEWS", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.5/list", + "PublicTypes": "public_types/openjpeg/1.5/list" + }, + { + "Number": "1.4", + "Installed": "installed/openjpeg/1.4", + "Source": "src/openjpeg/1.4/version.1.4.tar.gz", + "Changelog": "CHANGES", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.4/list", + "PublicTypes": "public_types/openjpeg/1.4/list" + }, + { + "Number": "1.3", + "Installed": "installed/openjpeg/1.3", + "Source": "src/openjpeg/1.3/version.1.3.tar.gz", + "Changelog": "ChangeLog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.3/list", + "PublicTypes": "public_types/openjpeg/1.3/list" + }, + { + "Number": "1.2", + "Installed": "installed/openjpeg/1.2", + "Source": "src/openjpeg/1.2/version.1.2.tar.gz", + "Changelog": "ChangeLog", + "HeadersDiff": "On", + "PkgDiff": "Off", + "ABIView": "Off", + "ABIDiff": "Off", + "PublicSymbols": "public_symbols/openjpeg/1.2/list", + "PublicTypes": "public_types/openjpeg/1.2/list" + }] +} diff --git a/tools/ctest_scripts/toolchain-mingw32.cmake b/tools/ctest_scripts/toolchain-mingw32.cmake new file mode 100644 index 00000000..1728f9ea --- /dev/null +++ b/tools/ctest_scripts/toolchain-mingw32.cmake @@ -0,0 +1,26 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# +# Copyright (c) 2006-2014 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +set(CMAKE_RC_COMPILER i686-w64-mingw32-windres) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/tools/ctest_scripts/toolchain-mingw64.cmake b/tools/ctest_scripts/toolchain-mingw64.cmake new file mode 100644 index 00000000..5fe1507f --- /dev/null +++ b/tools/ctest_scripts/toolchain-mingw64.cmake @@ -0,0 +1,26 @@ +# http://www.cmake.org/Wiki/CmakeMingw +# +# Copyright (c) 2006-2014 Mathieu Malaterre +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/tools/ctest_scripts/travis-ci.cmake b/tools/ctest_scripts/travis-ci.cmake new file mode 100644 index 00000000..f8b23ada --- /dev/null +++ b/tools/ctest_scripts/travis-ci.cmake @@ -0,0 +1,151 @@ +# ----------------------------------------------------------------------------- +# Travis-ci ctest script for OpenJPEG project +# This will compile/run tests/upload to cdash OpenJPEG +# Results will be available at: http://my.cdash.org/index.php?project=OPENJPEG +# ----------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 2.8) + +set( ENV{LANG} en_US.UTF-8) +if($ENV{OPJ_BINARY_DIR}) + set( CTEST_DASHBOARD_ROOT "$ENV{OPJ_BINARY_DIR}" ) +else() + set( CTEST_DASHBOARD_ROOT "$ENV{PWD}/build" ) +endif() + +if("$ENV{TRAVIS_OS_NAME}" STREQUAL "windows") + set( CTEST_CMAKE_GENERATOR "NMake Makefiles") + set( CTEST_BUILD_COMMAND "nmake" ) + set( JPYLYZER_EXT "exe" ) +else() + set( CTEST_CMAKE_GENERATOR "Unix Makefiles") # Always makefile in travis-ci environment + set( CCFLAGS_WARNING "-Wall -Wextra -Wconversion -Wno-unused-parameter -Wdeclaration-after-statement") + set( JPYLYZER_EXT "py" ) +endif() + +if ("$ENV{OPJ_BUILD_CONFIGURATION}" STREQUAL "") + set( CTEST_BUILD_CONFIGURATION "Release") +else() + set( CTEST_BUILD_CONFIGURATION "$ENV{OPJ_BUILD_CONFIGURATION}") +endif() + +if ("$ENV{OPJ_SITE}" STREQUAL "") + set( CTEST_SITE "Unknown") +else() + set( CTEST_SITE "$ENV{OPJ_SITE}") +endif() + +if ("$ENV{OPJ_BUILDNAME}" STREQUAL "") + set( CTEST_BUILD_NAME "Unknown-${CTEST_BUILD_CONFIGURATION}") +else() + set( CTEST_BUILD_NAME "$ENV{OPJ_BUILDNAME}") +endif() + +if (NOT "$ENV{OPJ_CI_ARCH}" STREQUAL "") + if (APPLE) + set(CCFLAGS_ARCH "-arch $ENV{OPJ_CI_ARCH}") + else() + if ("$ENV{OPJ_CI_ARCH}" MATCHES "^i[3-6]86$") + set(CCFLAGS_ARCH "-m32 -march=$ENV{OPJ_CI_ARCH}") + elseif ("$ENV{OPJ_CI_ARCH}" STREQUAL "x86_64") + set(CCFLAGS_ARCH "-m64") + endif() + endif() +endif() + +if ("$ENV{OPJ_CI_ASAN}" STREQUAL "1") + set(OPJ_HAS_MEMCHECK TRUE) + set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer") + set(CCFLAGS_ARCH "${CCFLAGS_ARCH} -O1 -g -fsanitize=address -fno-omit-frame-pointer") +endif() + +if("$ENV{CC}" MATCHES ".*mingw.*") + # We are trying to use mingw + if ("$ENV{OPJ_CI_ARCH}" MATCHES "^i[3-6]86$") + set(CTEST_CONFIGURE_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${CTEST_SCRIPT_DIRECTORY}/toolchain-mingw32.cmake") + else() + set(CTEST_CONFIGURE_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${CTEST_SCRIPT_DIRECTORY}/toolchain-mingw64.cmake") + endif() +endif() + +if(NOT "$ENV{OPJ_CI_SKIP_TESTS}" STREQUAL "1") + # To execute part of the encoding test suite, kakadu binaries are needed to decode encoded image and compare + # it to the baseline. Kakadu binaries are freely available for non-commercial purposes + # at http://www.kakadusoftware.com. + # Here's the copyright notice from kakadu: + # Copyright is owned by NewSouth Innovations Pty Limited, commercial arm of the UNSW Australia in Sydney. + # You are free to trial these executables and even to re-distribute them, + # so long as such use or re-distribution is accompanied with this copyright notice and is not for commercial gain. + # Note: Binaries can only be used for non-commercial purposes. + if ("$ENV{OPJ_NONCOMMERCIAL}" STREQUAL "1" ) + set(KDUPATH $ENV{PWD}/kdu) + if("$ENV{TRAVIS_OS_NAME}" STREQUAL "windows") + set(ENV{PATH} "$ENV{PATH};${KDUPATH}") + else() + set(ENV{LD_LIBRARY_PATH} ${KDUPATH}) + set(ENV{PATH} $ENV{PATH}:${KDUPATH}) + endif() + endif() + set(BUILD_TESTING "TRUE") +else() + set(BUILD_TESTING "FALSE") +endif(NOT "$ENV{OPJ_CI_SKIP_TESTS}" STREQUAL "1") + +# Options +set( CACHE_CONTENTS " + +# Build kind +CMAKE_BUILD_TYPE:STRING=${CTEST_BUILD_CONFIGURATION} + +# Warning level +CMAKE_C_FLAGS:STRING= ${CCFLAGS_ARCH} ${CCFLAGS_WARNING} + +# Use to activate the test suite +BUILD_TESTING:BOOL=${BUILD_TESTING} + +# Build Thirdparty, useful but not required for test suite +BUILD_THIRDPARTY:BOOL=TRUE + +# JPEG2000 test files are available with git clone https://github.com/uclouvain/openjpeg-data.git +OPJ_DATA_ROOT:PATH=$ENV{PWD}/data + +# jpylyzer is available with on GitHub: https://github.com/openpreserve/jpylyzer +JPYLYZER_EXECUTABLE=$ENV{PWD}/jpylyzer/jpylyzer.${JPYLYZER_EXT} + +" ) + +#--------------------- +#1. openjpeg specific: +set( CTEST_PROJECT_NAME "OPENJPEG" ) +if(NOT EXISTS $ENV{OPJ_SOURCE_DIR}) + message(FATAL_ERROR "OPJ_SOURCE_DIR not defined or does not exist:$ENV{OPJ_SOURCE_DIR}") +endif() +set( CTEST_SOURCE_DIRECTORY "$ENV{OPJ_SOURCE_DIR}") +set( CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}") + +#--------------------- +# Files to submit to the dashboard +set (CTEST_NOTES_FILES +${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME} +${CTEST_BINARY_DIRECTORY}/CMakeCache.txt ) + +ctest_empty_binary_directory( "${CTEST_BINARY_DIRECTORY}" ) +file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CACHE_CONTENTS}") + +# Perform a Experimental build +ctest_start(Experimental) +#ctest_update(SOURCE "${CTEST_SOURCE_DIRECTORY}") +ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" OPTIONS "${CTEST_CONFIGURE_OPTIONS}") +ctest_read_custom_files(${CTEST_BINARY_DIRECTORY}) +ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}") +if(NOT "$ENV{OPJ_CI_SKIP_TESTS}" STREQUAL "1") + ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" PARALLEL_LEVEL 2) + if(OPJ_HAS_MEMCHECK) + ctest_memcheck(BUILD "${CTEST_BINARY_DIRECTORY}" PARALLEL_LEVEL 2) + endif() +endif() +if ("$ENV{OPJ_DO_SUBMIT}" STREQUAL "1") + ctest_submit() +endif() +# Do not clean, we'll parse the log for known failure +#ctest_empty_binary_directory( "${CTEST_BINARY_DIRECTORY}" ) diff --git a/tools/travis-ci/abi-check.sh b/tools/travis-ci/abi-check.sh new file mode 100755 index 00000000..3eb6e18f --- /dev/null +++ b/tools/travis-ci/abi-check.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# This script executes the abi-check step when running under travis-ci (in run step) + +# Set-up some bash options +set -o nounset ## set -u : exit the script if you try to use an uninitialised variable +set -o errexit ## set -e : exit the script if any statement returns a non-true return value +set -o pipefail ## Fail on error in pipe +set -o xtrace ## set -x : Print a trace of simple commands and their arguments after they are expanded and before they are executed. + +# Exit if not ABI check +if [ "${OPJ_CI_ABI_CHECK:-}" != "1" ]; then + exit 0 +fi + +OPJ_UPLOAD_ABI_REPORT=0 +OPJ_LIMIT_ABI_BUILDS="-limit 2" +if [ "${TRAVIS_REPO_SLUG:-}" != "" ]; then + if [ "$(echo "${TRAVIS_REPO_SLUG}" | sed 's/\(^.*\)\/.*/\1/')" == "uclouvain" ] && [ "${TRAVIS_PULL_REQUEST:-}" == "false" ]; then + # Upload report + OPJ_UPLOAD_ABI_REPORT=1 + # Build full report + OPJ_LIMIT_ABI_BUILDS= + fi +fi + +OPJ_SOURCE_DIR=$(cd $(dirname $0)/../.. && pwd) + + +mkdir ${HOME}/abi-check +cd ${HOME}/abi-check +# Let's get tools not available with apt +mkdir tools +# Travis doesn't allow package wdiff... +wget -qO - http://mirrors.kernel.org/gnu/wdiff/wdiff-latest.tar.gz | tar -xz +cd wdiff-* +./configure --prefix=${HOME}/abi-check/tools/wdiff &> /dev/null +make &> /dev/null +make check &> /dev/null +make install &> /dev/null +cd .. +export PATH=${PWD}/tools/wdiff/bin:$PATH + +wget -qO - https://tools.ietf.org/tools/rfcdiff/rfcdiff-1.42.tgz | tar -xz +mv rfcdiff-1.42 ${PWD}/tools/rfcdiff +export PATH=${PWD}/tools/rfcdiff:$PATH +wget -qO - https://github.com/lvc/installer/archive/0.4.tar.gz | tar -xz +mkdir ${PWD}/tools/abi-tracker +make -C installer-0.4 install prefix=${PWD}/tools/abi-tracker target=abi-tracker +export PATH=${PWD}/tools/abi-tracker/bin:$PATH + +mkdir tracker +cd tracker + +# Let's create all we need +grep -v Git ${OPJ_SOURCE_DIR}/tools/abi-tracker/openjpeg.json > ./openjpeg.json +abi-monitor ${OPJ_LIMIT_ABI_BUILDS} -get openjpeg.json +if [ "${OPJ_LIMIT_ABI_BUILDS}" != "" ]; then + cp -f ${OPJ_SOURCE_DIR}/tools/abi-tracker/openjpeg.json ./openjpeg.json +else + # Old versions of openjpeg don't like -fvisibility=hidden... + grep -v Configure ${OPJ_SOURCE_DIR}/tools/abi-tracker/openjpeg.json > ./openjpeg.json +fi +cp -rf ${OPJ_SOURCE_DIR} src/openjpeg/current +abi-monitor ${OPJ_LIMIT_ABI_BUILDS} -build openjpeg.json +abi-tracker -build openjpeg.json + +EXIT_CODE=0 + +# Check API +abi-compliance-checker -l openjpeg -old $(find ./abi_dump/openjpeg/2.1 -name '*.dump') -new $(find ./abi_dump/openjpeg/current -name '*.dump') -header openjpeg.h -api -s || EXIT_CODE=1 + +# Check ABI +if [ "${OPJ_LIMIT_ABI_BUILDS}" != "" ]; then + abi-compliance-checker -l openjpeg -old $(find ./abi_dump/openjpeg/2.1 -name '*.dump') -new $(find ./abi_dump/openjpeg/current -name '*.dump') -header openjpeg.h -abi -s || EXIT_CODE=1 +else + echo "Disable ABI check for now, problems with symbol visibility..." +fi + +rm -rf src installed + +if [ ${OPJ_UPLOAD_ABI_REPORT} -eq 1 ]; then + echo "TODO: Where to upload the report" +fi +exit $EXIT_CODE diff --git a/tools/travis-ci/install.sh b/tools/travis-ci/install.sh new file mode 100755 index 00000000..c62feee8 --- /dev/null +++ b/tools/travis-ci/install.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# This script executes the install step when running under travis-ci + +#if cygwin, check path +case ${MACHTYPE} in + *cygwin*) OPJ_CI_IS_CYGWIN=1;; + *) ;; +esac + +if [ "${OPJ_CI_IS_CYGWIN:-}" == "1" ]; then + # PATH is not yet set up + export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin +fi + +# Set-up some error handling +set -o nounset ## set -u : exit the script if you try to use an uninitialised variable +set -o errexit ## set -e : exit the script if any statement returns a non-true return value +set -o pipefail ## Fail on error in pipe + +function exit_handler () +{ + local exit_code="$?" + + test ${exit_code} == 0 && return; + + echo -e "\nInstall failed !!!\nLast command at line ${BASH_LINENO}: ${BASH_COMMAND}"; + exit "${exit_code}" +} +trap exit_handler EXIT +trap exit ERR + +# We don't need anything for coverity scan builds. ABI check is managed in abi-check.sh +if [ "${COVERITY_SCAN_BRANCH:-}" == "1" ] || [ "${OPJ_CI_ABI_CHECK:-}" == "1" ]; then + exit 0 +fi + +if [ "${OPJ_CI_ASAN:-}" == "1" ]; then + # We need a new version of cmake than travis-ci provides + wget --no-check-certificate -qO - https://cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz | tar -xz + # copy to a directory that will not changed every version + mv cmake-3.3.2-Linux-x86_64 cmake-install +fi + +if [ "${OPJ_CI_SKIP_TESTS:-}" != "1" ]; then + + OPJ_SOURCE_DIR=$(cd $(dirname $0)/../.. && pwd) + + # We need test data + if [ "${TRAVIS_BRANCH:-}" != "" ]; then + OPJ_DATA_BRANCH=${TRAVIS_BRANCH} + elif [ "${APPVEYOR_REPO_BRANCH:-}" != "" ]; then + OPJ_DATA_BRANCH=${APPVEYOR_REPO_BRANCH} + else + OPJ_DATA_BRANCH=$(git -C ${OPJ_SOURCE_DIR} branch | grep '*' | tr -d '*[[:blank:]]') #default to same branch as we're setting up + fi + OPJ_DATA_HAS_BRANCH=$(git ls-remote --heads git://github.com/uclouvain/openjpeg-data.git ${OPJ_DATA_BRANCH} | wc -l) + if [ ${OPJ_DATA_HAS_BRANCH} -eq 0 ]; then + OPJ_DATA_BRANCH=master #default to master + fi + echo "Cloning openjpeg-data from ${OPJ_DATA_BRANCH} branch" + git clone --depth=1 --branch=${OPJ_DATA_BRANCH} git://github.com/uclouvain/openjpeg-data.git data + + # We need jpylyzer for the test suite + echo "Retrieving jpylyzer" + if [ "${APPVEYOR:-}" == "True" ]; then + wget --local-encoding=UTF-8 -q http://dl.bintray.com/openplanets/opf-windows/jpylyzer_1.14.2_win32.zip + mkdir jpylyzer + cd jpylyzer + cmake -E tar -xf ../jpylyzer_1.14.2_win32.zip + cd .. + else + wget -qO - https://github.com/openpreserve/jpylyzer/archive/1.14.2.tar.gz | tar -xz + mv jpylyzer-1.14.2/jpylyzer ./ + chmod +x jpylyzer/jpylyzer.py + fi + + # When OPJ_NONCOMMERCIAL=1, kakadu trial binaries are used for testing. Here's the copyright notice from kakadu: + # Copyright is owned by NewSouth Innovations Pty Limited, commercial arm of the UNSW Australia in Sydney. + # You are free to trial these executables and even to re-distribute them, + # so long as such use or re-distribution is accompanied with this copyright notice and is not for commercial gain. + # Note: Binaries can only be used for non-commercial purposes. + if [ "${OPJ_NONCOMMERCIAL:-}" == "1" ]; then + if [ "${TRAVIS_OS_NAME:-}" == "linux" ] || uname -s | grep -i Linux &> /dev/null; then + echo "Retrieving Kakadu" + wget -q http://kakadusoftware.com/wp-content/uploads/2014/06/KDU77_Demo_Apps_for_Linux-x86-64_150710.zip + cmake -E tar -xf KDU77_Demo_Apps_for_Linux-x86-64_150710.zip + mv KDU77_Demo_Apps_for_Linux-x86-64_150710 kdu + elif [ "${TRAVIS_OS_NAME:-}" == "osx" ] || uname -s | grep -i Darwin &> /dev/null; then + echo "Retrieving Kakadu" + wget -q http://kakadusoftware.com/wp-content/uploads/2014/06/KDU77_Demo_Apps_for_OSX109_150710.dmg_.zip + cmake -E tar -xf KDU77_Demo_Apps_for_OSX109_150710.dmg_.zip + wget -q http://downloads.sourceforge.net/project/catacombae/HFSExplorer/0.23/hfsexplorer-0.23-bin.zip + mkdir hfsexplorer && cmake -E chdir hfsexplorer tar -xf ../hfsexplorer-0.23-bin.zip + ./hfsexplorer/bin/unhfs.sh -o ./ -fsroot Kakadu-demo-apps.pkg KDU77_Demo_Apps_for_OSX109_150710.dmg + pkgutil --expand Kakadu-demo-apps.pkg ./kdu + cd kdu + cat libkduv77r.pkg/Payload | gzip -d | cpio -id + cat kduexpand.pkg/Payload | gzip -d | cpio -id + cat kducompress.pkg/Payload | gzip -d | cpio -id + install_name_tool -id ${PWD}/libkdu_v77R.dylib libkdu_v77R.dylib + install_name_tool -change /usr/local/lib/libkdu_v77R.dylib ${PWD}/libkdu_v77R.dylib kdu_compress + install_name_tool -change /usr/local/lib/libkdu_v77R.dylib ${PWD}/libkdu_v77R.dylib kdu_expand + elif [ "${APPVEYOR:-}" == "True" ] || uname -s | grep -i MINGW &> /dev/null || uname -s | grep -i CYGWIN &> /dev/null; then + echo "Retrieving Kakadu" + wget -q http://kakadusoftware.com/wp-content/uploads/2014/06/KDU77_Demo_Apps_for_Win32_150710.msi_.zip + cmake -E tar -xf KDU77_Demo_Apps_for_Win32_150710.msi_.zip + msiexec /i KDU77_Demo_Apps_for_Win32_150710.msi /quiet /qn /norestart + if [ -d "C:/Program Files/Kakadu" ]; then + cp -r "C:/Program Files/Kakadu" ./kdu + else + cp -r "C:/Program Files (x86)/Kakadu" ./kdu + fi + fi + fi +fi diff --git a/tools/travis-ci/knownfailures-Ubuntu12.04-clang3.4-x86_64-Debug-3rdP-ASan.txt b/tools/travis-ci/knownfailures-Ubuntu12.04-clang3.4-x86_64-Debug-3rdP-ASan.txt new file mode 100644 index 00000000..ab2169d3 --- /dev/null +++ b/tools/travis-ci/knownfailures-Ubuntu12.04-clang3.4-x86_64-Debug-3rdP-ASan.txt @@ -0,0 +1 @@ +NR-ENC-Bretagne2.ppm-7-compare_dec-ref-out2base diff --git a/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.3-i386-Release-3rdP.txt b/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.3-i386-Release-3rdP.txt new file mode 100644 index 00000000..2c74d31a --- /dev/null +++ b/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.3-i386-Release-3rdP.txt @@ -0,0 +1,53 @@ +NR-DEC-issue104_jpxstream.jp2-33-decode-md5 +NR-DEC-issue226.j2k-74-decode +NR-DEC-issue226.j2k-74-decode-md5 +NR-DEC-p1_06.j2k-156-decode +NR-DEC-p1_06.j2k-156-decode-md5 +NR-DEC-p1_06.j2k-164-decode-md5 +NR-C1P0-p0_04.j2k-compare2base +NR-C1P0-p0_05.j2k-compare2base +NR-C1P0-p0_06.j2k-compare2base +NR-C1P1-p1_02.j2k-compare2base +NR-C1P1-p1_03.j2k-compare2base +NR-C1P1-p1_04.j2k-compare2base +NR-C1P1-p1_05.j2k-compare2base +NR-JP2-file2.jp2-compare2base +NR-JP2-file3.jp2-compare2base +NR-RIC-subsampling_1.jp2-compare2base +NR-RIC-subsampling_2.jp2-compare2base +NR-RIC-zoo1.jp2-compare2base +NR-RIC-zoo2.jp2-compare2base +NR-DEC-_00042.j2k-2-decode-md5 +NR-DEC-buxI.j2k-9-decode-md5 +NR-DEC-CT_Phillips_JPEG2K_Decompr_Problem.j2k-13-decode-md5 +NR-DEC-Marrin.jp2-18-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +NR-DEC-file409752.jp2-40-decode-md5 +NR-DEC-issue188_beach_64bitsbox.jp2-41-decode-md5 +NR-DEC-issue206_image-000.jp2-42-decode-md5 +NR-DEC-issue205.jp2-43-decode-md5 +NR-DEC-issue228.j2k-60-decode-md5 +NR-DEC-issue134.jp2-67-decode-md5 +NR-DEC-issue208.jp2-69-decode-md5 +NR-DEC-issue211.jp2-70-decode-md5 +NR-DEC-issue135.j2k-68-decode-md5 +NR-DEC-issue414.jp2-110-decode-md5 +NR-DEC-p1_04.j2k-124-decode-md5 +NR-DEC-p1_04.j2k-125-decode-md5 +NR-DEC-p1_04.j2k-126-decode-md5 +NR-DEC-p1_04.j2k-127-decode-md5 +NR-DEC-p1_04.j2k-128-decode-md5 +NR-DEC-p1_04.j2k-129-decode-md5 +NR-DEC-p1_04.j2k-131-decode-md5 +NR-DEC-p1_04.j2k-134-decode-md5 +NR-DEC-p1_04.j2k-138-decode-md5 +NR-DEC-p1_04.j2k-140-decode-md5 +NR-DEC-p0_04.j2k-166-decode-md5 +NR-DEC-p0_04.j2k-168-decode-md5 +NR-DEC-p0_04.j2k-172-decode-md5 +NR-DEC-issue205.jp2-253-decode-md5 +NR-DEC-issue559-eci-090-CIELab.jp2-255-decode-md5 +NR-DEC-issue236-ESYCC-CDEF.jp2-254-decode-md5 +NR-DEC-issue559-eci-091-CIELab.jp2-256-decode-md5 +NR-DEC-p1_06.j2k-164-decode diff --git a/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.4-i386-Release-3rdP.txt b/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.4-i386-Release-3rdP.txt new file mode 100644 index 00000000..2c74d31a --- /dev/null +++ b/tools/travis-ci/knownfailures-Ubuntu12.04-gcc4.6.4-i386-Release-3rdP.txt @@ -0,0 +1,53 @@ +NR-DEC-issue104_jpxstream.jp2-33-decode-md5 +NR-DEC-issue226.j2k-74-decode +NR-DEC-issue226.j2k-74-decode-md5 +NR-DEC-p1_06.j2k-156-decode +NR-DEC-p1_06.j2k-156-decode-md5 +NR-DEC-p1_06.j2k-164-decode-md5 +NR-C1P0-p0_04.j2k-compare2base +NR-C1P0-p0_05.j2k-compare2base +NR-C1P0-p0_06.j2k-compare2base +NR-C1P1-p1_02.j2k-compare2base +NR-C1P1-p1_03.j2k-compare2base +NR-C1P1-p1_04.j2k-compare2base +NR-C1P1-p1_05.j2k-compare2base +NR-JP2-file2.jp2-compare2base +NR-JP2-file3.jp2-compare2base +NR-RIC-subsampling_1.jp2-compare2base +NR-RIC-subsampling_2.jp2-compare2base +NR-RIC-zoo1.jp2-compare2base +NR-RIC-zoo2.jp2-compare2base +NR-DEC-_00042.j2k-2-decode-md5 +NR-DEC-buxI.j2k-9-decode-md5 +NR-DEC-CT_Phillips_JPEG2K_Decompr_Problem.j2k-13-decode-md5 +NR-DEC-Marrin.jp2-18-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +NR-DEC-file409752.jp2-40-decode-md5 +NR-DEC-issue188_beach_64bitsbox.jp2-41-decode-md5 +NR-DEC-issue206_image-000.jp2-42-decode-md5 +NR-DEC-issue205.jp2-43-decode-md5 +NR-DEC-issue228.j2k-60-decode-md5 +NR-DEC-issue134.jp2-67-decode-md5 +NR-DEC-issue208.jp2-69-decode-md5 +NR-DEC-issue211.jp2-70-decode-md5 +NR-DEC-issue135.j2k-68-decode-md5 +NR-DEC-issue414.jp2-110-decode-md5 +NR-DEC-p1_04.j2k-124-decode-md5 +NR-DEC-p1_04.j2k-125-decode-md5 +NR-DEC-p1_04.j2k-126-decode-md5 +NR-DEC-p1_04.j2k-127-decode-md5 +NR-DEC-p1_04.j2k-128-decode-md5 +NR-DEC-p1_04.j2k-129-decode-md5 +NR-DEC-p1_04.j2k-131-decode-md5 +NR-DEC-p1_04.j2k-134-decode-md5 +NR-DEC-p1_04.j2k-138-decode-md5 +NR-DEC-p1_04.j2k-140-decode-md5 +NR-DEC-p0_04.j2k-166-decode-md5 +NR-DEC-p0_04.j2k-168-decode-md5 +NR-DEC-p0_04.j2k-172-decode-md5 +NR-DEC-issue205.jp2-253-decode-md5 +NR-DEC-issue559-eci-090-CIELab.jp2-255-decode-md5 +NR-DEC-issue236-ESYCC-CDEF.jp2-254-decode-md5 +NR-DEC-issue559-eci-091-CIELab.jp2-256-decode-md5 +NR-DEC-p1_06.j2k-164-decode diff --git a/tools/travis-ci/knownfailures-Ubuntu14.04-gcc4.8.4-i386-Release-3rdP.txt b/tools/travis-ci/knownfailures-Ubuntu14.04-gcc4.8.4-i386-Release-3rdP.txt new file mode 100644 index 00000000..fe66aa36 --- /dev/null +++ b/tools/travis-ci/knownfailures-Ubuntu14.04-gcc4.8.4-i386-Release-3rdP.txt @@ -0,0 +1,45 @@ +NR-C1P0-p0_04.j2k-compare2base +NR-C1P0-p0_05.j2k-compare2base +NR-C1P0-p0_06.j2k-compare2base +NR-C1P1-p1_02.j2k-compare2base +NR-C1P1-p1_03.j2k-compare2base +NR-C1P1-p1_04.j2k-compare2base +NR-C1P1-p1_05.j2k-compare2base +NR-JP2-file2.jp2-compare2base +NR-JP2-file3.jp2-compare2base +NR-RIC-subsampling_1.jp2-compare2base +NR-RIC-subsampling_2.jp2-compare2base +NR-RIC-zoo1.jp2-compare2base +NR-RIC-zoo2.jp2-compare2base +NR-DEC-_00042.j2k-2-decode-md5 +NR-DEC-buxI.j2k-9-decode-md5 +NR-DEC-CT_Phillips_JPEG2K_Decompr_Problem.j2k-13-decode-md5 +NR-DEC-Marrin.jp2-18-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +NR-DEC-file409752.jp2-40-decode-md5 +NR-DEC-issue188_beach_64bitsbox.jp2-41-decode-md5 +NR-DEC-issue206_image-000.jp2-42-decode-md5 +NR-DEC-issue205.jp2-43-decode-md5 +NR-DEC-issue228.j2k-60-decode-md5 +NR-DEC-issue134.jp2-67-decode-md5 +NR-DEC-issue208.jp2-69-decode-md5 +NR-DEC-issue211.jp2-70-decode-md5 +NR-DEC-issue414.jp2-110-decode-md5 +NR-DEC-p1_04.j2k-124-decode-md5 +NR-DEC-p1_04.j2k-125-decode-md5 +NR-DEC-p1_04.j2k-126-decode-md5 +NR-DEC-p1_04.j2k-127-decode-md5 +NR-DEC-p1_04.j2k-128-decode-md5 +NR-DEC-p1_04.j2k-129-decode-md5 +NR-DEC-p1_04.j2k-131-decode-md5 +NR-DEC-p1_04.j2k-134-decode-md5 +NR-DEC-p1_04.j2k-138-decode-md5 +NR-DEC-p1_04.j2k-140-decode-md5 +NR-DEC-p0_04.j2k-166-decode-md5 +NR-DEC-p0_04.j2k-168-decode-md5 +NR-DEC-p0_04.j2k-172-decode-md5 +NR-DEC-issue205.jp2-253-decode-md5 +NR-DEC-issue236-ESYCC-CDEF.jp2-254-decode-md5 +NR-DEC-issue559-eci-090-CIELab.jp2-255-decode-md5 +NR-DEC-issue559-eci-091-CIELab.jp2-256-decode-md5 diff --git a/tools/travis-ci/knownfailures-all.txt b/tools/travis-ci/knownfailures-all.txt new file mode 100644 index 00000000..e2c01aaa --- /dev/null +++ b/tools/travis-ci/knownfailures-all.txt @@ -0,0 +1,9 @@ +NR-DEC-p1_06.j2k-164-decode +NR-DEC-issue104_jpxstream.jp2-33-decode-md5 +NR-DEC-issue135.j2k-68-decode-md5 +NR-DEC-issue226.j2k-74-decode-md5 +NR-DEC-p1_06.j2k-156-decode-md5 +NR-DEC-p1_06.j2k-164-decode-md5 +NR-DEC-p1_06.j2k-156-decode +NR-DEC-issue226.j2k-74-decode +NR-DEC-broken.jpc-73-decode diff --git a/tools/travis-ci/knownfailures-windows-vs2010-x86-Release-3rdP.txt b/tools/travis-ci/knownfailures-windows-vs2010-x86-Release-3rdP.txt new file mode 100644 index 00000000..d243c235 --- /dev/null +++ b/tools/travis-ci/knownfailures-windows-vs2010-x86-Release-3rdP.txt @@ -0,0 +1,46 @@ +NR-C1P0-p0_04.j2k-compare2base +NR-C1P0-p0_05.j2k-compare2base +NR-C1P0-p0_06.j2k-compare2base +NR-C1P1-p1_02.j2k-compare2base +NR-C1P1-p1_03.j2k-compare2base +NR-C1P1-p1_04.j2k-compare2base +NR-C1P1-p1_05.j2k-compare2base +NR-RIC-subsampling_1.jp2-compare2base +NR-RIC-subsampling_2.jp2-compare2base +NR-RIC-zoo1.jp2-compare2base +NR-RIC-zoo2.jp2-compare2base +NR-ENC-Bretagne2.ppm-7-compare_dec-ref-out2base +NR-DEC-_00042.j2k-2-decode-md5 +NR-DEC-buxI.j2k-9-decode-md5 +NR-DEC-CT_Phillips_JPEG2K_Decompr_Problem.j2k-13-decode-md5 +NR-DEC-Marrin.jp2-18-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +NR-DEC-file409752.jp2-40-decode-md5 +NR-DEC-issue188_beach_64bitsbox.jp2-41-decode-md5 +NR-DEC-issue206_image-000.jp2-42-decode-md5 +NR-DEC-issue205.jp2-43-decode-md5 +NR-DEC-issue228.j2k-60-decode-md5 +NR-DEC-issue134.jp2-67-decode-md5 +NR-DEC-issue208.jp2-69-decode-md5 +NR-DEC-issue211.jp2-70-decode-md5 +NR-DEC-issue414.jp2-110-decode-md5 +NR-DEC-p1_04.j2k-124-decode-md5 +NR-DEC-p1_04.j2k-125-decode-md5 +NR-DEC-p1_04.j2k-126-decode-md5 +NR-DEC-p1_04.j2k-127-decode-md5 +NR-DEC-p1_04.j2k-128-decode-md5 +NR-DEC-p1_04.j2k-129-decode-md5 +NR-DEC-p1_04.j2k-131-decode-md5 +NR-DEC-p1_04.j2k-134-decode-md5 +NR-DEC-p1_04.j2k-138-decode-md5 +NR-DEC-p1_04.j2k-140-decode-md5 +NR-DEC-p0_04.j2k-166-decode-md5 +NR-DEC-p0_04.j2k-168-decode-md5 +NR-DEC-p0_04.j2k-172-decode-md5 +NR-DEC-issue205.jp2-253-decode-md5 +NR-DEC-issue236-ESYCC-CDEF.jp2-254-decode-md5 +NR-DEC-issue559-eci-090-CIELab.jp2-255-decode-md5 +NR-DEC-issue559-eci-091-CIELab.jp2-256-decode-md5 +ETS-C1P0-p0_12.j2k-compare2ref +NR-C1P0-p0_12.j2k-compare2base diff --git a/tools/travis-ci/knownfailures-windows-vs2015-x64-Release-3rdP.txt b/tools/travis-ci/knownfailures-windows-vs2015-x64-Release-3rdP.txt new file mode 100644 index 00000000..e52efb85 --- /dev/null +++ b/tools/travis-ci/knownfailures-windows-vs2015-x64-Release-3rdP.txt @@ -0,0 +1,5 @@ +NR-ENC-Bretagne2.ppm-7-compare_dec-ref-out2base +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +ETS-C1P0-p0_12.j2k-compare2ref +NR-C1P0-p0_12.j2k-compare2base diff --git a/tools/travis-ci/knownfailures-windows-vs2015-x86-Release-3rdP.txt b/tools/travis-ci/knownfailures-windows-vs2015-x86-Release-3rdP.txt new file mode 100644 index 00000000..e52efb85 --- /dev/null +++ b/tools/travis-ci/knownfailures-windows-vs2015-x86-Release-3rdP.txt @@ -0,0 +1,5 @@ +NR-ENC-Bretagne2.ppm-7-compare_dec-ref-out2base +NR-DEC-kodak_2layers_lrcp.j2c-31-decode-md5 +NR-DEC-kodak_2layers_lrcp.j2c-32-decode-md5 +ETS-C1P0-p0_12.j2k-compare2ref +NR-C1P0-p0_12.j2k-compare2base diff --git a/tools/travis-ci/run.sh b/tools/travis-ci/run.sh new file mode 100755 index 00000000..e8c5a281 --- /dev/null +++ b/tools/travis-ci/run.sh @@ -0,0 +1,275 @@ +#!/bin/bash + +# This script executes the script step when running under travis-ci + +#if cygwin, check path +case ${MACHTYPE} in + *cygwin*) OPJ_CI_IS_CYGWIN=1;; + *) ;; +esac + +# Hack for appveyor to get GNU find in path before windows one. +export PATH=$(dirname ${BASH}):$PATH + +# Set-up some bash options +set -o nounset ## set -u : exit the script if you try to use an uninitialised variable +set -o errexit ## set -e : exit the script if any statement returns a non-true return value +set -o pipefail ## Fail on error in pipe + +function opjpath () +{ + if [ "${OPJ_CI_IS_CYGWIN:-}" == "1" ]; then + cygpath $1 "$2" + else + echo "$2" + fi +} + +# ABI check is done by abi-check.sh +if [ "${OPJ_CI_ABI_CHECK:-}" == "1" ]; then + exit 0 +fi + +# Set-up some variables +if [ "${OPJ_CI_BUILD_CONFIGURATION:-}" == "" ]; then + export OPJ_CI_BUILD_CONFIGURATION=Release #default +fi +OPJ_SOURCE_DIR=$(cd $(dirname $0)/../.. && pwd) + +if [ "${OPJ_DO_SUBMIT:-}" == "" ]; then + OPJ_DO_SUBMIT=0 # Do not flood cdash by default +fi +if [ "${TRAVIS_REPO_SLUG:-}" != "" ]; then + OPJ_OWNER=$(echo "${TRAVIS_REPO_SLUG}" | sed 's/\(^.*\)\/.*/\1/') + OPJ_SITE="${OPJ_OWNER}.travis-ci.org" + if [ "${OPJ_OWNER}" == "uclouvain" ]; then + OPJ_DO_SUBMIT=1 + fi +elif [ "${APPVEYOR_REPO_NAME:-}" != "" ]; then + OPJ_OWNER=$(echo "${APPVEYOR_REPO_NAME}" | sed 's/\(^.*\)\/.*/\1/') + OPJ_SITE="${OPJ_OWNER}.appveyor.com" + if [ "${OPJ_OWNER}" == "uclouvain" ]; then + OPJ_DO_SUBMIT=1 + fi +else + OPJ_SITE="$(hostname)" +fi + +if [ "${TRAVIS_OS_NAME:-}" == "" ]; then + # Let's guess OS for testing purposes + echo "Guessing OS" + if uname -s | grep -i Darwin &> /dev/null; then + TRAVIS_OS_NAME=osx + elif uname -s | grep -i Linux &> /dev/null; then + TRAVIS_OS_NAME=linux + if [ "${CC:-}" == "" ]; then + # default to gcc + export CC=gcc + fi + elif uname -s | grep -i CYGWIN &> /dev/null; then + TRAVIS_OS_NAME=windows + elif uname -s | grep -i MINGW &> /dev/null; then + TRAVIS_OS_NAME=windows + elif [ "${APPVEYOR:-}" == "True" ]; then + TRAVIS_OS_NAME=windows + else + echo "Failed to guess OS"; exit 1 + fi + echo "${TRAVIS_OS_NAME}" +fi + +if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + OPJ_OS_NAME=$(sw_vers -productName | tr -d ' ')$(sw_vers -productVersion | sed 's/\([^0-9]*\.[0-9]*\).*/\1/') + OPJ_CC_VERSION=$(xcodebuild -version | grep -i xcode) + OPJ_CC_VERSION=xcode${OPJ_CC_VERSION:6} +elif [ "${TRAVIS_OS_NAME}" == "linux" ]; then + OPJ_OS_NAME=linux + if which lsb_release > /dev/null; then + OPJ_OS_NAME=$(lsb_release -si)$(lsb_release -sr | sed 's/\([^0-9]*\.[0-9]*\).*/\1/') + fi + if [ -z "${CC##*gcc*}" ]; then + OPJ_CC_VERSION=$(${CC} --version | head -1 | sed 's/.*\ \([0-9.]*[0-9]\)/\1/') + if [ -z "${CC##*mingw*}" ]; then + OPJ_CC_VERSION=mingw${OPJ_CC_VERSION} + # disable testing for now + export OPJ_CI_SKIP_TESTS=1 + else + OPJ_CC_VERSION=gcc${OPJ_CC_VERSION} + fi + elif [ -z "${CC##*clang*}" ]; then + OPJ_CC_VERSION=clang$(${CC} --version | grep version | sed 's/.*version \([^0-9.]*[0-9.]*\).*/\1/') + else + echo "Compiler not supported: ${CC}"; exit 1 + fi +elif [ "${TRAVIS_OS_NAME}" == "windows" ]; then + OPJ_OS_NAME=windows + if which cl > /dev/null; then + OPJ_CL_VERSION=$(cl 2>&1 | grep Version | sed 's/.*Version \([0-9]*\).*/\1/') + if [ ${OPJ_CL_VERSION} -eq 19 ]; then + OPJ_CC_VERSION=vs2015 + elif [ ${OPJ_CL_VERSION} -eq 18 ]; then + OPJ_CC_VERSION=vs2013 + elif [ ${OPJ_CL_VERSION} -eq 17 ]; then + OPJ_CC_VERSION=vs2012 + elif [ ${OPJ_CL_VERSION} -eq 16 ]; then + OPJ_CC_VERSION=vs2010 + elif [ ${OPJ_CL_VERSION} -eq 15 ]; then + OPJ_CC_VERSION=vs2008 + elif [ ${OPJ_CL_VERSION} -eq 14 ]; then + OPJ_CC_VERSION=vs2005 + else + OPJ_CC_VERSION=vs???? + fi + fi +else + echo "OS not supported: ${TRAVIS_OS_NAME}"; exit 1 +fi + +if [ "${OPJ_CI_ARCH:-}" == "" ]; then + echo "Guessing build architecture" + MACHINE_ARCH=$(uname -m) + if [ "${MACHINE_ARCH}" == "x86_64" ]; then + export OPJ_CI_ARCH=x86_64 + fi + echo "${OPJ_CI_ARCH}" +fi + +if [ "${TRAVIS_BRANCH:-}" == "" ]; then + if [ "${APPVEYOR_REPO_BRANCH:-}" != "" ]; then + TRAVIS_BRANCH=${APPVEYOR_REPO_BRANCH} + else + echo "Guessing branch" + TRAVIS_BRANCH=$(git -C ${OPJ_SOURCE_DIR} branch | grep '*' | tr -d '*[[:blank:]]') + fi +fi + +OPJ_BUILDNAME=${OPJ_OS_NAME}-${OPJ_CC_VERSION}-${OPJ_CI_ARCH}-${TRAVIS_BRANCH} +OPJ_BUILDNAME_TEST=${OPJ_OS_NAME}-${OPJ_CC_VERSION}-${OPJ_CI_ARCH} +if [ "${TRAVIS_PULL_REQUEST:-}" != "false" ] && [ "${TRAVIS_PULL_REQUEST:-}" != "" ]; then + OPJ_BUILDNAME=${OPJ_BUILDNAME}-pr${TRAVIS_PULL_REQUEST} +elif [ "${APPVEYOR_PULL_REQUEST_NUMBER:-}" != "" ]; then + OPJ_BUILDNAME=${OPJ_BUILDNAME}-pr${APPVEYOR_PULL_REQUEST_NUMBER} +fi +OPJ_BUILDNAME=${OPJ_BUILDNAME}-${OPJ_CI_BUILD_CONFIGURATION}-3rdP +OPJ_BUILDNAME_TEST=${OPJ_BUILDNAME_TEST}-${OPJ_CI_BUILD_CONFIGURATION}-3rdP +if [ "${OPJ_CI_ASAN:-}" == "1" ]; then + OPJ_BUILDNAME=${OPJ_BUILDNAME}-ASan + OPJ_BUILDNAME_TEST=${OPJ_BUILDNAME_TEST}-ASan +fi + +if [ "${OPJ_NONCOMMERCIAL:-}" == "1" ] && [ "${OPJ_CI_SKIP_TESTS:-}" != "1" ] && [ -d kdu ]; then + echo " +Testing will use Kakadu trial binaries. Here's the copyright notice from kakadu: +Copyright is owned by NewSouth Innovations Pty Limited, commercial arm of the UNSW Australia in Sydney. +You are free to trial these executables and even to re-distribute them, +so long as such use or re-distribution is accompanied with this copyright notice and is not for commercial gain. +Note: Binaries can only be used for non-commercial purposes. +" +fi + +if [ -d cmake-install ]; then + export PATH=${PWD}/cmake-install/bin:${PATH} +fi + +set -x +# This will print configuration +# travis-ci doesn't dump cmake version in system info, let's print it +cmake --version + +export TRAVIS_OS_NAME=${TRAVIS_OS_NAME} +export OPJ_SITE=${OPJ_SITE} +export OPJ_BUILDNAME=${OPJ_BUILDNAME} +export OPJ_SOURCE_DIR=$(opjpath -m ${OPJ_SOURCE_DIR}) +export OPJ_BINARY_DIR=$(opjpath -m ${PWD}/build) +export OPJ_BUILD_CONFIGURATION=${OPJ_CI_BUILD_CONFIGURATION} +export OPJ_DO_SUBMIT=${OPJ_DO_SUBMIT} + +ctest -S ${OPJ_SOURCE_DIR}/tools/ctest_scripts/travis-ci.cmake -V || true +# ctest will exit with various error codes depending on version. +# ignore ctest exit code & parse this ourselves +set +x + +# let's parse configure/build/tests for failure + +echo " +Parsing logs for failures +" +OPJ_CI_RESULT=0 + +# 1st configure step +OPJ_CONFIGURE_XML=$(find build -path 'build/Testing/*' -name 'Configure.xml') +if [ ! -f "${OPJ_CONFIGURE_XML}" ]; then + echo "No configure log found" + OPJ_CI_RESULT=1 +else + if ! grep '0' ${OPJ_CONFIGURE_XML} &> /dev/null; then + echo "Errors were found in configure log" + OPJ_CI_RESULT=1 + fi +fi + +# 2nd build step +# We must have one Build.xml file +OPJ_BUILD_XML=$(find build -path 'build/Testing/*' -name 'Build.xml') +if [ ! -f "${OPJ_BUILD_XML}" ]; then + echo "No build log found" + OPJ_CI_RESULT=1 +else + if grep '' ${OPJ_BUILD_XML} &> /dev/null; then + echo "Errors were found in build log" + OPJ_CI_RESULT=1 + fi +fi + +if [ ${OPJ_CI_RESULT} -ne 0 ]; then + # Don't trash output with failing tests when there are configure/build errors + exit ${OPJ_CI_RESULT} +fi + +if [ "${OPJ_CI_SKIP_TESTS:-}" != "1" ]; then + OPJ_TEST_XML=$(find build -path 'build/Testing/*' -name 'Test.xml') + if [ ! -f "${OPJ_TEST_XML}" ]; then + echo "No test log found" + OPJ_CI_RESULT=1 + else + echo "Parsing tests for new/unknown failures" + # 3rd test step + OPJ_FAILEDTEST_LOG=$(find build -path 'build/Testing/Temporary/*' -name 'LastTestsFailed_*.log') + if [ -f "${OPJ_FAILEDTEST_LOG}" ]; then + awk -F: '{ print $2 }' ${OPJ_FAILEDTEST_LOG} > failures.txt + while read FAILEDTEST; do + # Start with common errors + if grep -x "${FAILEDTEST}" $(opjpath -u ${OPJ_SOURCE_DIR})/tools/travis-ci/knownfailures-all.txt > /dev/null; then + continue + fi + if [ -f $(opjpath -u ${OPJ_SOURCE_DIR})/tools/travis-ci/knownfailures-${OPJ_BUILDNAME_TEST}.txt ]; then + if grep -x "${FAILEDTEST}" $(opjpath -u ${OPJ_SOURCE_DIR})/tools/travis-ci/knownfailures-${OPJ_BUILDNAME_TEST}.txt > /dev/null; then + continue + fi + fi + echo "${FAILEDTEST}" + OPJ_CI_RESULT=1 + done < failures.txt + fi + fi + + if [ ${OPJ_CI_RESULT} -eq 0 ]; then + echo "No new/unknown test failure found + " + else + echo " +New/unknown test failure found!!! + " + fi + + # 4th memcheck step + OPJ_MEMCHECK_XML=$(find build -path 'build/Testing/*' -name 'DynamicAnalysis.xml') + if [ -f "${OPJ_MEMCHECK_XML}" ]; then + if grep ' /dev/null; then + echo "Errors were found in dynamic analysis log" + OPJ_CI_RESULT=1 + fi + fi +fi + +exit ${OPJ_CI_RESULT} diff --git a/wrapping/java/openjp2/JavaOpenJPEG.c b/wrapping/java/openjp2/JavaOpenJPEG.c index c0a877d6..368cbfdb 100644 --- a/wrapping/java/openjp2/JavaOpenJPEG.c +++ b/wrapping/java/openjp2/JavaOpenJPEG.c @@ -206,7 +206,7 @@ static void encode_help_display() { fprintf(stdout," Indicate multiple modes by adding their values. \n"); fprintf(stdout," ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); fprintf(stdout,"\n"); - fprintf(stdout,"-TP : devide packets of every tile into tile-parts (-TP R) [R, L, C]\n"); + fprintf(stdout,"-TP : divide packets of every tile into tile-parts (-TP R) [R, L, C]\n"); fprintf(stdout,"\n"); fprintf(stdout,"-x : create an index file *.Idx (-x index_name.Idx) \n"); fprintf(stdout,"\n"); @@ -1696,7 +1696,7 @@ static opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobjec len = (*env)->GetArrayLength(env, jba); jbBody = (*env)->GetPrimitiveArrayCritical(env, jba, &isCopy); - /*printf("C: before transfering 8 bpp image\n");*/ + /*printf("C: before transferring 8 bpp image\n");*/ if (comp->sgnd) { for(i=0; i< len;i++) { comp->data[i] = (char) jbBody[i]; @@ -1715,7 +1715,7 @@ static opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobjec len = (*env)->GetArrayLength(env, jsa); jsBody = (*env)->GetPrimitiveArrayCritical(env, jsa, &isCopy); - /*printf("C: before transfering 16 bpp image\n");*/ + /*printf("C: before transferring 16 bpp image\n");*/ if (comp->sgnd) { /* Special behaviour to deal with signed elements ??*/ comp->data[i] = (short) jsBody[i]; for(i=0; i< len;i++) { @@ -1735,7 +1735,7 @@ static opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobjec shift = compno*8; jiBody = (*env)->GetPrimitiveArrayCritical(env, jia, &isCopy); - /*printf("C: before transfering 24 bpp image (component %d, signed = %d)\n", compno, comp->sgnd);*/ + /*printf("C: before transferring 24 bpp image (component %d, signed = %d)\n", compno, comp->sgnd);*/ if (comp->sgnd) { /* Special behaviour to deal with signed elements ?? XXXXX*/ for(i=0; i< len;i++) { comp->data[i] = ( ((int) jiBody[i]) & (0xFF << shift) ) >> shift; diff --git a/wrapping/java/openjp2/JavaOpenJPEGDecoder.c b/wrapping/java/openjp2/JavaOpenJPEGDecoder.c index 80e09c39..f91267fc 100644 --- a/wrapping/java/openjp2/JavaOpenJPEGDecoder.c +++ b/wrapping/java/openjp2/JavaOpenJPEGDecoder.c @@ -604,7 +604,7 @@ JNIEXPORT jint JNICALL Java_org_openJpeg_OpenJPEGJavaDecoder_internalDecodeJ2Kto /*printf("C: %d bytes read from file\n",file_length);*/ } else { /* Preparing the transfer of the codestream from Java to C*/ - /*printf("C: before transfering codestream\n");*/ + /*printf("C: before transferring codestream\n");*/ fid = (*env)->GetFieldID(env, cls,"compressedStream", "[B"); jba = (*env)->GetObjectField(env, obj, fid); file_length = (*env)->GetArrayLength(env, jba); @@ -782,7 +782,7 @@ JNIEXPORT jint JNICALL Java_org_openJpeg_OpenJPEGJavaDecoder_internalDecodeJ2Kto jia = (*env)->GetObjectField(env, obj, fid); jiBody = (*env)->GetIntArrayElements(env, jia, 0); ptrIBody = jiBody; - printf("C: transfering image24: %d int to Java pointer=%d\n",image->numcomps*w*h, ptrIBody); + printf("C: transferring image24: %d int to Java pointer=%d\n",image->numcomps*w*h, ptrIBody); for (i=0; icomps[0].data; - printf("C: before transfering a %d bpp image to java (length = %d)\n",image->comps[0].prec ,w*h); + printf("C: before transferring a %d bpp image to java (length = %d)\n",image->comps[0].prec ,w*h); if (image->comps[0].prec<=8) { fid = (*env)->GetFieldID(env, cls,"image8", "[B"); jba = (*env)->GetObjectField(env, obj, fid); @@ -823,7 +823,7 @@ JNIEXPORT jint JNICALL Java_org_openJpeg_OpenJPEGJavaDecoder_internalDecodeJ2Kto max_value = 255; } #endif - /*printf("C: transfering %d shorts to Java image8 pointer = %d\n", wr*hr,ptrSBody);*/ + /*printf("C: transferring %d shorts to Java image8 pointer = %d\n", wr*hr,ptrSBody);*/ for (i=0; iReleaseByteArrayElements(env, jba, jbBody, 0); - printf("C: image8 transfered to Java\n"); + printf("C: image8 transferred to Java\n"); } else { fid = (*env)->GetFieldID(env, cls,"image16", "[S"); jsa = (*env)->GetObjectField(env, obj, fid); @@ -851,7 +851,7 @@ JNIEXPORT jint JNICALL Java_org_openJpeg_OpenJPEGJavaDecoder_internalDecodeJ2Kto } printf("C: minValue = %d, maxValue = %d\n", min_value, max_value); #endif - printf("C: transfering %d shorts to Java image16 pointer = %d\n", w*h,ptrSBody); + printf("C: transferring %d shorts to Java image16 pointer = %d\n", w*h,ptrSBody); for (i=0; i