Compare commits

...

83 Commits

Author SHA1 Message Date
mayeut
f0dd842b11 Fix warning
applications\codec\convertpng.c(465) : warning C4018: '<' :
signed/unsigned mismatch
2015-11-07 01:29:43 +01:00
mayeut
96c3a8315b PNG support enhancement
Update #611
2015-11-05 22:44:58 +01:00
mayeut
6711fa669a BMP support enhancement
Update #611
2015-11-05 00:29:37 +01:00
mayeut
935816e8c9 Update TIFF conversion to support more bit depth.
Update #611
2015-11-03 22:34:43 +01:00
mayeut
c0abb808f5 Fix invalid read in pngtoimage 2015-10-18 19:10:31 +02:00
mayeut
348e96e44b resets resno_decoded for each tile
Update #574
2015-10-18 18:58:54 +02:00
mayeut
e94720fea0 Fix ycc_to_rgb conversions
Update #574
2015-10-18 18:27:14 +02:00
mayeut
04291bf0ab Fix typo 2015-10-18 18:15:12 +02:00
mayeut
46440fe368 Fix some calculations in tcd_malloc_encode and tcd_malloc_decode_tile
Fix #388
2015-10-18 18:10:38 +02:00
mayeut
9cf9018ffc Update to libtiff 4.0.4 2015-10-18 17:18:21 +02:00
mayeut
001cd957ba Update to libpng 1.6.17 2015-10-18 16:45:42 +02:00
mayeut
a024c148fc Update to lib 1.2.8 2015-10-18 16:39:45 +02:00
mayeut
a4bd2ed06e Update to libcms2-2.6 2015-10-18 16:31:49 +02:00
mayeut
66f65919cf Update color_apply_icc_profile 2015-10-18 16:24:51 +02:00
mayeut
7ad3e2a870 Add "-p", "-force-rgb" and "-upsample" options to j2k_to_image
Fix #606
2015-10-18 16:07:40 +02:00
mayeut
9542c08d62 Don't rely on float equality
Fix #591
2015-10-15 15:52:01 +02:00
mayeut
cbaa2d7d98 Fix j2k_validate_encode 2015-10-15 15:48:02 +02:00
mayeut
650df81e09 Use -ffast-math only for compilation
Updates #488
Closes #554
2015-10-15 14:59:36 +02:00
Antonin Descampe
618e50954f Fixes overflow when high number of decompositions
Update #603
2015-10-09 16:56:54 +02:00
Antonin Descampe
959ebdab5e Gracefully reject codestreams with malformed SIZ markers
Update #603
2015-09-30 09:00:50 +02:00
Antonin Descampe
3cee252347 commented out some tests
No plan to fix this in 1.5 branch right now
2015-09-29 16:28:41 +02:00
Antonin Descampe
2a4101c60e Fixed non regression test config + ignore some files 2015-09-23 22:02:13 +02:00
Antonin Descampe
32b04ad49d Makes j2k_dump focus on parsing j2k codestreams, nothing else.
Avoid processing JP2 PCLR, CMAP, CDEF boxes and J2K packets in j2k_dump.
Fixes #595
2015-09-23 17:48:30 +02:00
Antonin Descampe
5e3fae7f48 update md5 signatures
Updates #604
2015-09-22 17:08:11 +02:00
Pedro Gimeno
4469a98cd7 Wrong TGA header generated by j2k_to_image
The TGA file writer used by j2k_to_image writes a wrong field to the
header for alpha-less images.

To reproduce:
1. Take any 24-bit j2k image with no alpha.
2. Convert it to TGA with j2k_to_image -i <image>.j2k -o <image>.tga
3. Open <image>.tga with Gimp.

When opened, the image will have a wrong alpha channel, because Gimp
uses a certain field in the header to determine if the image has alpha.
That field is saved wrongly by j2k_to_image for alpha-less images. Per
the TGA specification, Gimp is correct in this case.
2015-09-16 20:28:29 +02:00
Antonin Descampe
93c79f8fb1 modified checkmd5 2015-09-16 17:04:51 +02:00
Antonin Descampe
e755ebd1b0 backport fixes for issues #362 (-2863) and #393 on branch 1.5 2015-09-16 16:51:15 +02:00
Antonin Descampe
f35aaa8a82 added tests from master in 1.5 branch 2015-09-16 15:48:24 +02:00
Antonin Descampe
b44e07fe19 removed warnings when configuring with CMake 3.x on MacOS (update issue 443 for 1.5 branch) 2015-09-16 13:14:00 +02:00
Antonin Descampe
d3c0915992 added a validation procedure before launching actual decoding, fixed testempty tests 2015-09-16 13:05:20 +02:00
Antonin Descampe
c91e2099b1 disabled gX_colr kdu tests for now 2015-09-16 10:47:00 +02:00
Antonin Descampe
d0e85b0c52 fixed typo in CMakeLists.txt preventing use of libpng 2015-09-15 18:21:07 +02:00
Antonin Descampe
31e35fcf7b preventde seg fault when unknown long options and fixed ability to use USE_SYSTEM_GETOPT 2015-09-15 18:00:52 +02:00
Antonin Descampe
2d47938b25 added testempty0 test 2015-09-15 15:49:58 +02:00
Antonin Descampe
2e508f1c89 backport issue #80 to 1.5 branch 2015-09-15 15:42:17 +02:00
Antonin Descampe
f8013bec95 update conformance test files on 1.5 branch 2015-09-15 15:11:12 +02:00
Antonin Descampe
770e81eebc Fixed "unsupported platform" error 2015-09-14 17:03:03 +02:00
Antonin Descampe
2c3f5c269a [1.5] added int64_t define for win platforms in int.h so that r2990 actually workswith windows 2015-01-27 16:51:27 +00:00
Antonin Descampe
0ec0b2594c [1.5] fixed int_ceildivpow2 implementation (backport from trunk)
Update issue 388
2015-01-08 23:18:52 +00:00
Mathieu Malaterre
2eebb05ca2 [1.5] Fix a typo in comments 2014-04-01 13:55:28 +00:00
Mathieu Malaterre
ff72d131ed [1.5] Rework r2827. getopt was still being used in java binding
Update issue 301
2014-04-01 13:40:41 +00:00
Mathieu Malaterre
7d6d19c473 [1.5] Rework r2769. getopt was still being used in mj2/jpwl codecs
Update issue 301
2014-04-01 13:32:02 +00:00
Mathieu Malaterre
78053c44c8 [1.5] Make sure to compile java code with a defined source/target version 2014-04-01 11:54:43 +00:00
Mathieu Malaterre
902fe2569c [1.5] Tag this version to be the next 1.5.3 2014-04-01 11:54:21 +00:00
Mathieu Malaterre
8c71728242 [1.5] Fix big endian checking with autotools
Thanks to winfried for patch
Fixes issue 302
2014-03-26 15:25:37 +00:00
Mathieu Malaterre
4140dfdea8 [1.5] Import patch from bug tracker
Thanks to winfried
Fixes issue 304
2014-03-25 16:42:49 +00:00
Rex Dieter
259f629a46 Improve check for standard libs
Previously, with <lib>_LIBS and <lib>_CFLAGS undefined,
the most basic compile command "$CC conftest.c -l<lib>" was not
tested.

issue: 129
2014-03-24 17:01:23 +00:00
Rex Dieter
c302efcf86 Install jpwl man pages only if jpwl is enabled
issue: 129
2014-03-24 16:58:46 +00:00
Rex Dieter
e0b5b08f9a Calling AC_CANONICAL_SYSTEM implies AC_CANONICAL_TARGET, which
gives incorrect results when cross compiling. Calling only
AC_CANONICAL_HOST is enough.

issue: 129
2014-03-24 16:58:06 +00:00
Mathieu Malaterre
dac95eff3a [1.5] Rework r2768 in fact getopt_long is slightly different on GNU. Adapt signature to handle BSD signature and GNU one.
Update issue 301
2014-03-18 16:26:39 +00:00
Mathieu Malaterre
4f4de7070e [1.5] Create a new cmake option to choose between convienient copy of getopt and system installed one
Udapte issue 301
2014-03-18 15:59:08 +00:00
Mathieu Malaterre
78d1820881 [1.5] Add a way for user to override source/target java version
Update issue 303
2014-03-18 14:58:14 +00:00
Mathieu Malaterre
de73cfeec1 [1.5] Fix issues with big endian handling
Fixes issue 302
2014-03-18 14:40:37 +00:00
Mathieu Malaterre
49044ae2a8 [1.5] Rework r2758 the conditions were not quite right. Update checks. 2014-03-18 14:27:56 +00:00
Mathieu Malaterre
6e0162a8a6 [1.5] Check the number of tiles 2014-03-18 14:19:21 +00:00
Mathieu Malaterre
910af7edec [1.5] Import patch from trunk to make test passes. Affects: NR-DEC-2977.pdf.asan.67.2198.jp2-52-decode & NR-DEC-4149.pdf.SIGSEGV.cf7.3501.jp2-50-decode 2014-03-18 14:05:44 +00:00
Mathieu Malaterre
69cd4f9211 [1.5] Import portion of patch from issue 297
Run test suite on new datasets
Update issue 297
2014-03-18 12:47:45 +00:00
Mathieu Malaterre
6fc2b56847 [1.5] Remove another set of simple warnings 2014-03-17 16:11:48 +00:00
Mathieu Malaterre
773bd89130 [1.5] Remove simple warning about C++ style comments 2014-03-17 16:03:07 +00:00
Mathieu Malaterre
5d356d6fcb [1.5] Update BSD-4 copyright into a BSD-3 copyright
Update issue 300
2014-03-17 15:02:20 +00:00
Mathieu Malaterre
a2f90ab2cb [1.5] Prevent buffer overflow in openjpip code 2014-03-12 11:55:54 +00:00
Mathieu Malaterre
a05a9aa4ed [1.5] Fix remainings warnings on 1.5 branch 2014-03-12 11:52:26 +00:00
Mathieu Malaterre
af2be2d456 [1.5] Use improved find_path syntax to help cross-compilation setup find openjpeg data root 2014-03-04 08:29:53 +00:00
Mathieu Malaterre
96dba34ddc [1.5] Declare functions static to track unused ones. 2014-02-26 08:43:20 +00:00
Mathieu Malaterre
6aad1208b2 [1.5] Import first patch (fixes.patch) from issue 249 to fix leaks on error condition.
Update issue 249
2014-02-26 08:38:19 +00:00
Mathieu Malaterre
d2be8c5d21 [1.5] Use new add_test signature to handle cross compilation and execution using wine 2014-02-26 08:34:28 +00:00
Mathieu Malaterre
b42f76cb7f [1.5] Remove addition from r1702 this introduced a regression as seen in issue 205
Fixes issue 205
2014-02-25 14:44:55 +00:00
Mathieu Malaterre
07163be7ed [1.5] Import md5 checker from trunk back onto 1.5 branch 2014-02-25 14:28:30 +00:00
Mathieu Malaterre
4e672cc1e9 [1.5] Do not report warning on third party lib 2014-02-24 12:26:51 +00:00
Mathieu Malaterre
ced9a50367 [1.5] Remove some simple warnings 2014-02-24 10:01:27 +00:00
Mathieu Malaterre
a1683bd7c2 [1.5] Import patch suggested in bug #241 2013-09-26 09:24:55 +00:00
Antonin Descampe
f968a70e22 tests : reactivated conformance tests in openjpeg 1.5 branch to enable comparison with trunk 2013-07-11 17:09:02 +00:00
Mickael Savinaud
2fe6bac6eb [b1.5.x] update the micro version into the configure file (thanks to winfried) 2013-03-14 08:52:38 +00:00
Mathieu Malaterre
15243144c4 [1.5] Rework #ifdef checks. We should check for _M_IX86 instead of not(_M_X64). Thanks to Misha Ulyutin for report on ML 2013-02-27 08:03:39 +00:00
Mickael Savinaud
c0c69d1c36 [1.5] improve the bmp read function for RGB8 case (thanks Winfried). Update issue 203 2012-12-18 08:47:19 +00:00
Rex Dieter
d9d62a77ee backport r2259
Doxyfile: HTML_TIMESTAMP = NO

helps when comparing the output of multiple runs,
and distros will appreciate avoiding multilib conflicts.
2012-12-07 15:10:24 +00:00
Mathieu Malaterre
15488c94d2 [1.5] Fix Java binding issues.
Properly link to math lib on UNIX
Make JNI install location a user configuration
Remove SONAME property from the java module
2012-10-22 11:29:32 +00:00
Mathieu Malaterre
75175b715c [1.5] Build small internal tools to generate t1_luts.h 2012-10-02 07:43:12 +00:00
Mathieu Malaterre
46831582b2 [1.5] missing range check in j2k_read_coc et al.
Fixes issue 166
2012-10-02 07:17:09 +00:00
Mathieu Malaterre
e55d5e29e0 [1.5] division by zero in j2k_read_siz
Fixes issue 169
2012-10-02 07:09:57 +00:00
Mathieu Malaterre
c02f145cd1 [1.5] int main() in t1_generate_luts.c breaks mplayer
Fixes issue 152
2012-10-02 07:02:56 +00:00
Mathieu Malaterre
6280b5ad8d [1.5] jp2_read_boxhdr() can trigger random pointer memory access
Fixes issue 155
2012-10-01 15:57:01 +00:00
Mathieu Malaterre
7720188fa7 [1.5] Start opj 1.5.2 2012-10-01 15:49:16 +00:00
202 changed files with 62313 additions and 36661 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
CMakeLists.txt.user
*.bak

View File

@@ -28,7 +28,7 @@ SET(CTEST_CUSTOM_WARNING_EXCEPTION
# Suppress warning caused by intentional messages about deprecation
".*warning,.* is deprecated"
# supress warnings caused by 3rd party libs:
".*/thirdparty/.*"
".*thirdparty.*"
"libtiff.*has no symbols"
"libpng.*has no symbols"
)

16
CMake/FindCPPCHECK.cmake Normal file
View File

@@ -0,0 +1,16 @@
# cppcheck
#
# Copyright (c) 2011 Mathieu Malaterre <mathieu.malaterre@gmail.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
find_program(CPPCHECK_EXECUTABLE
cppcheck
)
mark_as_advanced(
CPPCHECK_EXECUTABLE
)

12
CMake/FindJPYLYZER.cmake Normal file
View File

@@ -0,0 +1,12 @@
#
# this module looks for JPYLYZER
# http://jpylyzer.openpreservation.org
#
find_program(JPYLYZER_EXECUTABLE
jpylyzer
)
mark_as_advanced(
JPYLYZER_EXECUTABLE
)

View File

@@ -11,6 +11,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
IF(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET CMP0003 NEW)
if (NOT (${CMAKE_VERSION} VERSION_LESS 3.0))
cmake_policy(SET CMP0042 NEW)
endif()
ENDIF(COMMAND CMAKE_POLICY)
IF(NOT OPENJPEG_NAMESPACE)
@@ -29,7 +32,7 @@ INCLUDE_REGULAR_EXPRESSION("^.*$")
# OPENJPEG version number, useful for packaging and doxygen doc:
SET(OPENJPEG_VERSION_MAJOR 1)
SET(OPENJPEG_VERSION_MINOR 5)
SET(OPENJPEG_VERSION_BUILD 0)
SET(OPENJPEG_VERSION_BUILD 3)
SET(OPENJPEG_VERSION
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
SET(PACKAGE_VERSION
@@ -44,6 +47,7 @@ SET(PACKAGE_VERSION
# 1.3 | 3
# 1.4 | 4
# 1.5 | 5
# 1.5.1 | 5
# 2.0 | 6
# above is the recommendation by the OPJ team. If you really need to override this default,
# you can specify your own OPENJPEG_SOVERSION at cmake configuration time:
@@ -135,6 +139,14 @@ IF(NOT OPENJPEG_INSTALL_DOC_DIR)
SET(OPENJPEG_INSTALL_DOC_DIR "share/doc/${OPENJPEG_INSTALL_SUBDIR}")
ENDIF(NOT OPENJPEG_INSTALL_DOC_DIR)
if(NOT OPENJPEG_INSTALL_JNI_DIR)
if(WIN32)
set(OPENJPEG_INSTALL_JNI_DIR ${OPENJPEG_INSTALL_BIN_DIR})
else()
set(OPENJPEG_INSTALL_JNI_DIR ${OPENJPEG_INSTALL_LIB_DIR})
endif()
endif()
IF(NOT OPENJPEG_INSTALL_PACKAGE_DIR)
# We could install *.cmake files in share/ however those files contains
# hardcoded path to libraries on a multi-arch system (fedora/debian) those
@@ -191,7 +203,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} "$<$<CONFIG:Release>:-ffast-math>")
ENDIF(CMAKE_COMPILER_IS_GNUCC)
#-----------------------------------------------------------------------------
@@ -224,6 +236,8 @@ IF(BUILD_JPIP)
ENDIF(BUILD_JPIP)
OPTION(BUILD_VIEWER "Build the OPJViewer executable (C++)" OFF)
OPTION(BUILD_JAVA "Build the openjpeg jar (Java)" OFF)
OPTION(USE_SYSTEM_GETOPT "Prefer system installed getopt()" OFF)
MARK_AS_ADVANCED(USE_SYSTEM_GETOPT)
MARK_AS_ADVANCED(BUILD_VIEWER)
MARK_AS_ADVANCED(BUILD_JAVA)
@@ -261,10 +275,9 @@ IF(BUILD_TESTING)
# They could be found via svn on the OpenJPEG google code project
# svn checkout http://openjpeg.googlecode.com/svn/data (about 70 Mo)
FIND_PATH(OPJ_DATA_ROOT README-OPJ-Data
PATHS
$ENV{OPJ_DATA_ROOT}
${CMAKE_SOURCE_DIR}/../data
${CMAKE_SOURCE_DIR}/../../data
PATHS $ENV{OPJ_DATA_ROOT} ${CMAKE_SOURCE_DIR}/../data
${CMAKE_SOURCE_DIR}/../../data
NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
)
# Add repository where to find tests

View File

@@ -7,8 +7,12 @@ SET(openjpegjni_SRCS
${OPENJPEG_SOURCE_DIR}/applications/codec/index.c
${OPENJPEG_SOURCE_DIR}/applications/codec/convert.c
#${OPENJPEG_SOURCE_DIR}/applications/common/color.c
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
if(NOT USE_SYSTEM_GETOPT)
list(APPEND openjpegjni_SRCS
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
endif()
# JNI binding:
find_package(JNI REQUIRED)
@@ -24,13 +28,14 @@ include_directories(
add_library(openjpegjni MODULE
${openjpegjni_SRCS}
)
# Java module should not have a SONAME:
set_property(TARGET openjpegjni PROPERTY NO_SONAME 1)
TARGET_LINK_LIBRARIES(openjpegjni ${OPENJPEG_LIBRARY_NAME})
IF(WIN32)
SET(OPENJPEG_INSTALL_JNI_DIR ${OPENJPEG_INSTALL_BIN_DIR})
ELSE()
SET(OPENJPEG_INSTALL_JNI_DIR ${OPENJPEG_INSTALL_LIB_DIR})
ENDIF()
if(UNIX)
target_link_libraries(openjpegjni m)
endif()
INSTALL(TARGETS openjpegjni
EXPORT OpenJPEGTargets
@@ -40,6 +45,14 @@ INSTALL(TARGETS openjpegjni
# build jar:
FIND_PACKAGE(Java 1.5 REQUIRED) # javac, jar
# User can override this:
if(NOT DEFINED JAVA_SOURCE_VERSION)
set(JAVA_SOURCE_VERSION 1.5)
endif()
if(NOT DEFINED JAVA_TARGET_VERSION)
set(JAVA_TARGET_VERSION 1.5)
endif()
# build dep list:
file(GLOB java_srcs "java-sources/org/openJpeg/*.java")
@@ -48,7 +61,9 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/classes)
# Build java
ADD_CUSTOM_COMMAND(
OUTPUT ${LIBRARY_OUTPUT_PATH}/openjpeg.jar
COMMAND ${Java_JAVAC_EXECUTABLE} -sourcepath "${CMAKE_CURRENT_SOURCE_DIR}/java-sources"
COMMAND ${Java_JAVAC_EXECUTABLE}
-source ${JAVA_SOURCE_VERSION} -target ${JAVA_TARGET_VERSION}
-sourcepath "${CMAKE_CURRENT_SOURCE_DIR}/java-sources"
${java_srcs} -d ${CMAKE_CURRENT_BINARY_DIR}/classes
COMMAND ${Java_JAR_EXECUTABLE} cvf ${LIBRARY_OUTPUT_PATH}/openjpeg.jar org
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/classes

View File

@@ -1721,7 +1721,7 @@ opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobject obj,
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];
@@ -1740,7 +1740,7 @@ opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobject obj,
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];
@@ -1761,7 +1761,7 @@ opj_image_t* loadImage(opj_cparameters_t *parameters, JNIEnv *env, jobject obj,
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++) {

View File

@@ -615,7 +615,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);
@@ -797,7 +797,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; i<w*h; i++) {
tempUC = (unsigned char)(ptr[i]);
@@ -823,7 +823,7 @@ JNIEXPORT jint JNICALL Java_org_openJpeg_OpenJPEGJavaDecoder_internalDecodeJ2Kto
} else { /* 1 component 8 or 16 bpp image */
ptr = image->comps[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);
@@ -838,7 +838,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; i<w*h; i++) {
tempUC = (unsigned char) (ptr[i]);
#ifdef CHECK_THRESHOLDS
@@ -866,7 +866,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<w*h; i++) {
tempS = (short) (ptr[i]);
#ifdef CHECK_THRESHOLDS

View File

@@ -3,10 +3,17 @@
# First thing define the common source:
SET(common_SRCS
convert.c
converttif.c
convertbmp.c
convertpng.c
index.c
${OPENJPEG_SOURCE_DIR}/applications/common/color.c
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
if(NOT USE_SYSTEM_GETOPT)
list(APPEND common_SRCS
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
endif()
# Headers file are located here:
INCLUDE_DIRECTORIES(

View File

@@ -78,7 +78,7 @@ JPWL_j2k_to_image_CPPFLAGS = \
@LCMS1_CFLAGS@ \
@LCMS2_CFLAGS@
JPWL_j2k_to_image_CFLAGS =
JPWL_j2k_to_image_LDADD = $(top_builddir)/libopenjpeg/jpwl/libopenjpeg_JPWL.la @LCMS1_LIBS@ @LCMS2_LIBS@ @TIFF_LIBS@ @PNG_LIBS@
JPWL_j2k_to_image_LDADD = $(top_builddir)/libopenjpeg/jpwl/libopenjpeg_JPWL.la @LCMS1_LIBS@ @LCMS2_LIBS@ @TIFF_LIBS@ @PNG_LIBS@ -lm
JPWL_j2k_to_image_SOURCES = \
../common/color.c \
../common/opj_getopt.c \
@@ -96,7 +96,7 @@ JPWL_image_to_j2k_CPPFLAGS = \
@TIFF_CFLAGS@ \
@PNG_CFLAGS@
JPWL_image_to_j2k_CFLAGS =
JPWL_image_to_j2k_LDADD = $(top_builddir)/libopenjpeg/jpwl/libopenjpeg_JPWL.la @TIFF_LIBS@ @PNG_LIBS@
JPWL_image_to_j2k_LDADD = $(top_builddir)/libopenjpeg/jpwl/libopenjpeg_JPWL.la @TIFF_LIBS@ @PNG_LIBS@ -lm
JPWL_image_to_j2k_SOURCES = \
../common/opj_getopt.c \

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,21 @@ typedef struct raw_cparameters {
/*@}*/
} raw_cparameters_t;
/* Component precision scaling */
void clip_component(opj_image_comp_t* component, int precision);
void scale_component(opj_image_comp_t* component, int precision);
/* planar / interleaved conversions */
typedef void (* convert_32s_CXPX)(const int* pSrc, int* const* pDst, size_t length);
extern const convert_32s_CXPX convert_32s_CXPX_LUT[5];
typedef void (* convert_32s_PXCX)(int const* const* pSrc, int* pDst, size_t length, int adjust);
extern const convert_32s_PXCX convert_32s_PXCX_LUT[5];
/* bit depth conversions */
typedef void (* convert_XXx32s_C1R)(const unsigned char* pSrc, int* pDst, size_t length);
extern const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9]; /* up to 8bpp */
typedef void (* convert_32sXXx_C1R)(const int* pSrc, unsigned char* pDst, 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);

View File

@@ -0,0 +1,995 @@
/*
* 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_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "openjpeg.h"
#include "convert.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#if defined(_WIN32)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#error unsupported platform
#endif
#endif
typedef struct {
uint16_t bfType; /* 'BM' for Bitmap (19776) */
uint32_t bfSize; /* Size of the file */
uint16_t bfReserved1; /* Reserved : 0 */
uint16_t bfReserved2; /* Reserved : 0 */
uint32_t bfOffBits; /* Offset */
} OPJ_BITMAPFILEHEADER;
typedef struct {
uint32_t biSize; /* Size of the structure in bytes */
uint32_t biWidth; /* Width of the image in pixels */
uint32_t biHeight; /* Heigth of the image in pixels */
uint16_t biPlanes; /* 1 */
uint16_t biBitCount; /* Number of color bits by pixels */
uint32_t biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */
uint32_t biSizeImage; /* Size of the image in bytes */
uint32_t biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */
uint32_t biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */
uint32_t biClrUsed; /* Number of color used in the image (0: ALL) */
uint32_t biClrImportant; /* Number of important color (0: ALL) */
uint32_t biRedMask; /* Red channel bit mask */
uint32_t biGreenMask; /* Green channel bit mask */
uint32_t biBlueMask; /* Blue channel bit mask */
uint32_t biAlphaMask; /* Alpha channel bit mask */
uint32_t biColorSpaceType; /* Color space type */
uint8_t biColorSpaceEP[36]; /* Color space end points */
uint32_t biRedGamma; /* Red channel gamma */
uint32_t biGreenGamma; /* Green channel gamma */
uint32_t biBlueGamma; /* Blue channel gamma */
uint32_t biIntent; /* Intent */
uint32_t biIccProfileData; /* ICC profile data */
uint32_t biIccProfileSize; /* ICC profile size */
uint32_t biReserved; /* Reserved */
} OPJ_BITMAPINFOHEADER;
static void opj_applyLUT8u_8u32s_C1R(
uint8_t const* pSrc, int32_t srcStride,
int32_t* pDst, int32_t dstStride,
uint8_t const* pLUT,
uint32_t width, uint32_t height)
{
uint32_t y;
for (y = height; y != 0U; --y) {
uint32_t x;
for(x = 0; x < width; x++)
{
pDst[x] = (int32_t)pLUT[pSrc[x]];
}
pSrc += srcStride;
pDst += dstStride;
}
}
static void opj_applyLUT8u_8u32s_C1P3R(
uint8_t const* pSrc, int32_t srcStride,
int32_t* const* pDst, int32_t const* pDstStride,
uint8_t const* const* pLUT,
uint32_t width, uint32_t height)
{
uint32_t y;
int32_t* pR = pDst[0];
int32_t* pG = pDst[1];
int32_t* pB = pDst[2];
uint8_t const* pLUT_R = pLUT[0];
uint8_t const* pLUT_G = pLUT[1];
uint8_t const* pLUT_B = pLUT[2];
for (y = height; y != 0U; --y) {
uint32_t x;
for(x = 0; x < width; x++)
{
uint8_t idx = pSrc[x];
pR[x] = (int32_t)pLUT_R[idx];
pG[x] = (int32_t)pLUT_G[idx];
pB[x] = (int32_t)pLUT_B[idx];
}
pSrc += srcStride;
pR += pDstStride[0];
pG += pDstStride[1];
pB += pDstStride[2];
}
}
static void bmp24toimage(const uint8_t* pData, uint32_t stride, opj_image_t* image)
{
int index;
uint32_t width, height;
uint32_t x, y;
const uint8_t *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] = (int32_t)pSrc[3*x+2]; /* R */
image->comps[1].data[index] = (int32_t)pSrc[3*x+1]; /* G */
image->comps[2].data[index] = (int32_t)pSrc[3*x+0]; /* B */
index++;
}
pSrc -= stride;
}
}
static void bmp_mask_get_shift_and_prec(uint32_t mask, uint32_t* shift, uint32_t* prec)
{
uint32_t 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 uint8_t* pData, uint32_t stride, opj_image_t* image, uint32_t redMask, uint32_t greenMask, uint32_t blueMask, uint32_t alphaMask)
{
int index;
uint32_t width, height;
uint32_t x, y;
const uint8_t *pSrc = NULL;
opj_bool hasAlpha = OPJ_FALSE;
uint32_t redShift, redPrec;
uint32_t greenShift, greenPrec;
uint32_t blueShift, bluePrec;
uint32_t 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++)
{
uint32_t value = 0U;
value |= ((uint32_t)pSrc[4*x+0]) << 0;
value |= ((uint32_t)pSrc[4*x+1]) << 8;
value |= ((uint32_t)pSrc[4*x+2]) << 16;
value |= ((uint32_t)pSrc[4*x+3]) << 24;
image->comps[0].data[index] = (int32_t)((value & redMask) >> redShift); /* R */
image->comps[1].data[index] = (int32_t)((value & greenMask) >> greenShift); /* G */
image->comps[2].data[index] = (int32_t)((value & blueMask) >> blueShift); /* B */
if (hasAlpha) {
image->comps[3].data[index] = (int32_t)((value & alphaMask) >> alphaShift); /* A */
}
index++;
}
pSrc -= stride;
}
}
static void bmpmask16toimage(const uint8_t* pData, uint32_t stride, opj_image_t* image, uint32_t redMask, uint32_t greenMask, uint32_t blueMask, uint32_t alphaMask)
{
int index;
uint32_t width, height;
uint32_t x, y;
const uint8_t *pSrc = NULL;
opj_bool hasAlpha = OPJ_FALSE;
uint32_t redShift, redPrec;
uint32_t greenShift, greenPrec;
uint32_t blueShift, bluePrec;
uint32_t 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++)
{
uint32_t value = 0U;
value |= ((uint32_t)pSrc[2*x+0]) << 0;
value |= ((uint32_t)pSrc[2*x+1]) << 8;
image->comps[0].data[index] = (int32_t)((value & redMask) >> redShift); /* R */
image->comps[1].data[index] = (int32_t)((value & greenMask) >> greenShift); /* G */
image->comps[2].data[index] = (int32_t)((value & blueMask) >> blueShift); /* B */
if (hasAlpha) {
image->comps[3].data[index] = (int32_t)((value & alphaMask) >> alphaShift); /* A */
}
index++;
}
pSrc -= stride;
}
}
static opj_image_t* bmp8toimage(const uint8_t* pData, uint32_t stride, opj_image_t* image, uint8_t const* const* pLUT)
{
uint32_t width, height;
const uint8_t *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, -(int32_t)stride, image->comps[0].data, (int32_t)width, pLUT[0], width, height);
}
else {
int32_t* pDst[3];
int32_t pDstStride[3];
pDst[0] = image->comps[0].data; pDst[1] = image->comps[1].data; pDst[2] = image->comps[2].data;
pDstStride[0] = (int32_t)width; pDstStride[1] = (int32_t)width; pDstStride[2] = (int32_t)width;
opj_applyLUT8u_8u32s_C1P3R(pSrc, -(int32_t)stride, pDst, pDstStride, pLUT, width, height);
}
return image;
}
static opj_bool bmp_read_file_header(FILE* IN, OPJ_BITMAPFILEHEADER* header)
{
header->bfType = (uint16_t)getc(IN);
header->bfType |= (uint16_t)((uint32_t)getc(IN) << 8);
if (header->bfType != 19778) {
fprintf(stderr,"Error, not a BMP file!\n");
return OPJ_FALSE;
}
/* FILE HEADER */
/* ------------- */
header->bfSize = (uint32_t)getc(IN);
header->bfSize |= (uint32_t)getc(IN) << 8;
header->bfSize |= (uint32_t)getc(IN) << 16;
header->bfSize |= (uint32_t)getc(IN) << 24;
header->bfReserved1 = (uint16_t)getc(IN);
header->bfReserved1 |= (uint16_t)((uint32_t)getc(IN) << 8);
header->bfReserved2 = (uint16_t)getc(IN);
header->bfReserved2 |= (uint16_t)((uint32_t)getc(IN) << 8);
header->bfOffBits = (uint32_t)getc(IN);
header->bfOffBits |= (uint32_t)getc(IN) << 8;
header->bfOffBits |= (uint32_t)getc(IN) << 16;
header->bfOffBits |= (uint32_t)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 = (uint32_t)getc(IN);
header->biSize |= (uint32_t)getc(IN) << 8;
header->biSize |= (uint32_t)getc(IN) << 16;
header->biSize |= (uint32_t)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 = (uint32_t)getc(IN);
header->biWidth |= (uint32_t)getc(IN) << 8;
header->biWidth |= (uint32_t)getc(IN) << 16;
header->biWidth |= (uint32_t)getc(IN) << 24;
header->biHeight = (uint32_t)getc(IN);
header->biHeight |= (uint32_t)getc(IN) << 8;
header->biHeight |= (uint32_t)getc(IN) << 16;
header->biHeight |= (uint32_t)getc(IN) << 24;
header->biPlanes = (uint16_t)getc(IN);
header->biPlanes |= (uint16_t)((uint32_t)getc(IN) << 8);
header->biBitCount = (uint16_t)getc(IN);
header->biBitCount |= (uint16_t)((uint32_t)getc(IN) << 8);
if(header->biSize >= 40U) {
header->biCompression = (uint32_t)getc(IN);
header->biCompression |= (uint32_t)getc(IN) << 8;
header->biCompression |= (uint32_t)getc(IN) << 16;
header->biCompression |= (uint32_t)getc(IN) << 24;
header->biSizeImage = (uint32_t)getc(IN);
header->biSizeImage |= (uint32_t)getc(IN) << 8;
header->biSizeImage |= (uint32_t)getc(IN) << 16;
header->biSizeImage |= (uint32_t)getc(IN) << 24;
header->biXpelsPerMeter = (uint32_t)getc(IN);
header->biXpelsPerMeter |= (uint32_t)getc(IN) << 8;
header->biXpelsPerMeter |= (uint32_t)getc(IN) << 16;
header->biXpelsPerMeter |= (uint32_t)getc(IN) << 24;
header->biYpelsPerMeter = (uint32_t)getc(IN);
header->biYpelsPerMeter |= (uint32_t)getc(IN) << 8;
header->biYpelsPerMeter |= (uint32_t)getc(IN) << 16;
header->biYpelsPerMeter |= (uint32_t)getc(IN) << 24;
header->biClrUsed = (uint32_t)getc(IN);
header->biClrUsed |= (uint32_t)getc(IN) << 8;
header->biClrUsed |= (uint32_t)getc(IN) << 16;
header->biClrUsed |= (uint32_t)getc(IN) << 24;
header->biClrImportant = (uint32_t)getc(IN);
header->biClrImportant |= (uint32_t)getc(IN) << 8;
header->biClrImportant |= (uint32_t)getc(IN) << 16;
header->biClrImportant |= (uint32_t)getc(IN) << 24;
}
if(header->biSize >= 56U) {
header->biRedMask = (uint32_t)getc(IN);
header->biRedMask |= (uint32_t)getc(IN) << 8;
header->biRedMask |= (uint32_t)getc(IN) << 16;
header->biRedMask |= (uint32_t)getc(IN) << 24;
header->biGreenMask = (uint32_t)getc(IN);
header->biGreenMask |= (uint32_t)getc(IN) << 8;
header->biGreenMask |= (uint32_t)getc(IN) << 16;
header->biGreenMask |= (uint32_t)getc(IN) << 24;
header->biBlueMask = (uint32_t)getc(IN);
header->biBlueMask |= (uint32_t)getc(IN) << 8;
header->biBlueMask |= (uint32_t)getc(IN) << 16;
header->biBlueMask |= (uint32_t)getc(IN) << 24;
header->biAlphaMask = (uint32_t)getc(IN);
header->biAlphaMask |= (uint32_t)getc(IN) << 8;
header->biAlphaMask |= (uint32_t)getc(IN) << 16;
header->biAlphaMask |= (uint32_t)getc(IN) << 24;
}
if(header->biSize >= 108U) {
header->biColorSpaceType = (uint32_t)getc(IN);
header->biColorSpaceType |= (uint32_t)getc(IN) << 8;
header->biColorSpaceType |= (uint32_t)getc(IN) << 16;
header->biColorSpaceType |= (uint32_t)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 = (uint32_t)getc(IN);
header->biRedGamma |= (uint32_t)getc(IN) << 8;
header->biRedGamma |= (uint32_t)getc(IN) << 16;
header->biRedGamma |= (uint32_t)getc(IN) << 24;
header->biGreenGamma = (uint32_t)getc(IN);
header->biGreenGamma |= (uint32_t)getc(IN) << 8;
header->biGreenGamma |= (uint32_t)getc(IN) << 16;
header->biGreenGamma |= (uint32_t)getc(IN) << 24;
header->biBlueGamma = (uint32_t)getc(IN);
header->biBlueGamma |= (uint32_t)getc(IN) << 8;
header->biBlueGamma |= (uint32_t)getc(IN) << 16;
header->biBlueGamma |= (uint32_t)getc(IN) << 24;
}
if(header->biSize >= 124U) {
header->biIntent = (uint32_t)getc(IN);
header->biIntent |= (uint32_t)getc(IN) << 8;
header->biIntent |= (uint32_t)getc(IN) << 16;
header->biIntent |= (uint32_t)getc(IN) << 24;
header->biIccProfileData = (uint32_t)getc(IN);
header->biIccProfileData |= (uint32_t)getc(IN) << 8;
header->biIccProfileData |= (uint32_t)getc(IN) << 16;
header->biIccProfileData |= (uint32_t)getc(IN) << 24;
header->biIccProfileSize = (uint32_t)getc(IN);
header->biIccProfileSize |= (uint32_t)getc(IN) << 8;
header->biIccProfileSize |= (uint32_t)getc(IN) << 16;
header->biIccProfileSize |= (uint32_t)getc(IN) << 24;
header->biReserved = (uint32_t)getc(IN);
header->biReserved |= (uint32_t)getc(IN) << 8;
header->biReserved |= (uint32_t)getc(IN) << 16;
header->biReserved |= (uint32_t)getc(IN) << 24;
}
return OPJ_TRUE;
}
static opj_bool bmp_read_raw_data(FILE* IN, uint8_t* pData, uint32_t stride, uint32_t width, uint32_t height)
{
OPJ_ARG_NOT_USED(width);
if ( fread(pData, sizeof(uint8_t), 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, uint8_t* pData, uint32_t stride, uint32_t width, uint32_t height)
{
uint32_t x, y;
uint8_t *pix;
const uint8_t *beyond;
beyond = pData + stride * height;
pix = pData;
x = y = 0U;
while (y < height)
{
int c = getc(IN);
if (c) {
int j;
uint8_t c1 = (uint8_t)getc(IN);
for (j = 0; (j < c) && (x < width) && ((size_t)pix < (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 += (uint32_t)c;
c = getc(IN);
y += (uint32_t)c;
pix = pData + y * stride + x;
}
else /* 03 .. 255 */
{
int j;
for (j = 0; (j < c) && (x < width) && ((size_t)pix < (size_t)beyond); j++, x++, pix++)
{
uint8_t c1 = (uint8_t)getc(IN);
*pix = c1;
}
if ((uint32_t)c & 1U) { /* skip padding byte */
getc(IN);
}
}
}
}/* while() */
return OPJ_TRUE;
}
static opj_bool bmp_read_rle4_data(FILE* IN, uint8_t* pData, uint32_t stride, uint32_t width, uint32_t height)
{
uint32_t x, y;
uint8_t *pix;
const uint8_t *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;
uint8_t c1 = (uint8_t)getc(IN);
for (j = 0; (j < c) && (x < width) && ((size_t)pix < (size_t)beyond); j++, x++, pix++) {
*pix = (uint8_t)((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 += (uint32_t)c;
c = getc(IN); y += (uint32_t)c;
pix = pData + y * stride + x;
}
else { /* 03 .. 255 : absolute mode */
int j;
uint8_t c1 = 0U;
for (j = 0; (j < c) && (x < width) && ((size_t)pix < (size_t)beyond); j++, x++, pix++) {
if((j&1) == 0) {
c1 = (uint8_t)getc(IN);
}
*pix = (uint8_t)((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 */
uint8_t lut_R[256], lut_G[256], lut_B[256];
uint8_t const* pLUT[3];
opj_image_t * image = NULL;
FILE *IN;
OPJ_BITMAPFILEHEADER File_h;
OPJ_BITMAPINFOHEADER Info_h;
uint32_t i, palette_len, numcmpts = 1U;
opj_bool l_result = OPJ_FALSE;
uint8_t* pData = NULL;
uint32_t 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) {
uint8_t has_color = 0U;
for (i = 0U; i < palette_len; i++) {
lut_B[i] = (uint8_t)getc(IN);
lut_G[i] = (uint8_t)getc(IN);
lut_R[i] = (uint8_t)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 = (uint8_t *) calloc(1, stride * Info_h.biHeight * sizeof(uint8_t));
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 = parameters->subsampling_dx;
cmptparm[i].dy = parameters->subsampling_dy;
cmptparm[i].w = Info_h.biWidth;
cmptparm[i].h = Info_h.biHeight;
}
image = opj_image_create(numcmpts, &cmptparm[0], (numcmpts == 1U) ? CLRSPC_GRAY : 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 = (uint32_t)parameters->image_offset_x0;
image->y0 = (uint32_t)parameters->image_offset_y0;
image->x1 = image->x0 + (Info_h.biWidth - 1U) * (uint32_t)parameters->subsampling_dx + 1U;
image->y1 = image->y0 + (Info_h.biHeight - 1U) * (uint32_t)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",
(uint8_t) (h * w * 3 + 3 * h * (w % 2) + 54) & 0xff,
(uint8_t) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff,
(uint8_t) ((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff,
(uint8_t) ((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", (uint8_t) ((w) & 0xff),
(uint8_t) ((w) >> 8) & 0xff,
(uint8_t) ((w) >> 16) & 0xff,
(uint8_t) ((w) >> 24) & 0xff);
fprintf(fdest, "%c%c%c%c", (uint8_t) ((h) & 0xff),
(uint8_t) ((h) >> 8) & 0xff,
(uint8_t) ((h) >> 16) & 0xff,
(uint8_t) ((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", (uint8_t) (3 * h * w + 3 * h * (w % 2)) & 0xff,
(uint8_t) ((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff,
(uint8_t) ((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff,
(uint8_t) ((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++) {
uint8_t 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 = (uint8_t)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 = (uint8_t)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 = (uint8_t)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", (uint8_t) (h * w + 54 + 1024 + h * (w % 2)) & 0xff,
(uint8_t) ((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff,
(uint8_t) ((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff,
(uint8_t) ((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", (uint8_t) ((w) & 0xff),
(uint8_t) ((w) >> 8) & 0xff,
(uint8_t) ((w) >> 16) & 0xff,
(uint8_t) ((w) >> 24) & 0xff);
fprintf(fdest, "%c%c%c%c", (uint8_t) ((h) & 0xff),
(uint8_t) ((h) >> 8) & 0xff,
(uint8_t) ((h) >> 16) & 0xff,
(uint8_t) ((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", (uint8_t) (h * w + h * (w % 2)) & 0xff,
(uint8_t) ((h * w + h * (w % 2)) >> 8) & 0xff,
(uint8_t) ((h * w + h * (w % 2)) >> 16) & 0xff,
(uint8_t) ((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", (uint8_t)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;
}

View File

@@ -0,0 +1,496 @@
/*
* 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_config.h"
#ifndef HAVE_LIBPNG
# error HAVE_LIBPNG_NOT_DEFINED
#endif /* HAVE_LIBPNG */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <zlib.h>
#include <png.h>
#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 png_byte* pSrc, png_int_32* pDst, size_t length)
{
size_t i;
for (i = 0; i < length; i++) {
png_int_32 val0 = *pSrc++;
png_int_32 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;
png_uint_32 i;
png_uint_32 width, height = 0U;
int color_type;
FILE *reader = NULL;
png_byte** rows = NULL;
png_int_32* row32s = NULL;
/* j2k: */
opj_image_t *image = NULL;
opj_image_cmptparm_t cmptparm[4];
png_uint_32 nr_comp;
png_byte sigbuf[8];
convert_XXx32s_C1R cvtXXTo32s = NULL;
convert_32s_CXPX cvtCxToPx = NULL;
png_int_32* 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 = (png_byte**)calloc(height+1, sizeof(png_byte*));
for(i = 0; i < height; ++i)
rows[i] = (png_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 = (png_uint_32)bit_depth;
/* bits_per_pixel: 8 or 16 */
cmptparm[i].bpp = (png_uint_32)bit_depth;
cmptparm[i].sgnd = 0;
cmptparm[i].dx = (png_uint_32)params->subsampling_dx;
cmptparm[i].dy = (png_uint_32)params->subsampling_dy;
cmptparm[i].w = (png_uint_32)width;
cmptparm[i].h = (png_uint_32)height;
}
image = opj_image_create(nr_comp, &cmptparm[0], (nr_comp > 2U) ? CLRSPC_SRGB : CLRSPC_GRAY);
if(image == NULL) goto fin;
image->x0 = (png_uint_32)params->image_offset_x0;
image->y0 = (png_uint_32)params->image_offset_y0;
image->x1 = (png_uint_32)(image->x0 + (width - 1) * (png_uint_32)params->subsampling_dx + 1 + image->x0);
image->y1 = (png_uint_32)(image->y0 + (height - 1) * (png_uint_32)params->subsampling_dy + 1 + image->y0);
row32s = (png_int_32 *)malloc((size_t)width * nr_comp * sizeof(png_int_32));
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, (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 png_int_32* pSrc, png_byte* pDst, size_t length)
{
size_t i;
for (i = 0; i < length; i++) {
png_uint_32 val = (png_uint_32)pSrc[i];
*pDst++ = (png_byte)(val >> 8);
*pDst++ = (png_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;
png_int_32 const* planes[4];
int i;
png_int_32* 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]), (png_uint_32)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 */
{
size_t rowStride;
png_size_t png_row_size;
png_row_size = png_get_rowbytes(png, info);
rowStride = ((size_t)image->comps[0].w * (size_t)nr_comp * (size_t)prec + 7U) / 8U;
if (rowStride != (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 = (png_int_32*)malloc((size_t)image->comps[0].w * (size_t)nr_comp * sizeof(png_int_32));
if (buffer32s == NULL) {
fprintf(stderr, "Can't allocate memory for interleaved 32s row\n");
goto fin;
}
}
/* convert */
{
size_t width= image->comps[0].w;
int y;
convert_32s_PXCX cvtPxToCx = convert_32s_PXCX_LUT[nr_comp];
convert_32sXXx_C1R cvt32sToPack = NULL;
png_int_32 adjust = image->comps[0].sgnd ? 1 << (prec - 1) : 0;
png_bytep row_buf_cpy = row_buf;
png_int_32* 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 * (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() */

View File

@@ -0,0 +1,633 @@
/*
* 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_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef HAVE_LIBTIFF
# error HAVE_LIBTIFF_NOT_DEFINED
#endif /* HAVE_LIBTIFF */
#include <tiffio.h>
#include "openjpeg.h"
#include "convert.h"
/* -->> -->> -->> -->>
TIFF IMAGE FORMAT
<<-- <<-- <<-- <<-- */
static void tif_32sto10u(const int32* pSrc, uint8* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)3U); i+=4U) {
uint32 src0 = (uint32)pSrc[i+0];
uint32 src1 = (uint32)pSrc[i+1];
uint32 src2 = (uint32)pSrc[i+2];
uint32 src3 = (uint32)pSrc[i+3];
*pDst++ = (uint8)(src0 >> 2);
*pDst++ = (uint8)(((src0 & 0x3U) << 6) | (src1 >> 4));
*pDst++ = (uint8)(((src1 & 0xFU) << 4) | (src2 >> 6));
*pDst++ = (uint8)(((src2 & 0x3FU) << 2) | (src3 >> 8));
*pDst++ = (uint8)(src3);
}
if (length & 3U) {
uint32 src0 = (uint32)pSrc[i+0];
uint32 src1 = 0U;
uint32 src2 = 0U;
length = length & 3U;
if (length > 1U) {
src1 = (uint32)pSrc[i+1];
if (length > 2U) {
src2 = (uint32)pSrc[i+2];
}
}
*pDst++ = (uint8)(src0 >> 2);
*pDst++ = (uint8)(((src0 & 0x3U) << 6) | (src1 >> 4));
if (length > 1U) {
*pDst++ = (uint8)(((src1 & 0xFU) << 4) | (src2 >> 6));
if (length > 2U) {
*pDst++ = (uint8)(((src2 & 0x3FU) << 2));
}
}
}
}
static void tif_32sto12u(const int32* pSrc, uint8* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)1U); i+=2U) {
uint32 src0 = (uint32)pSrc[i+0];
uint32 src1 = (uint32)pSrc[i+1];
*pDst++ = (uint8)(src0 >> 4);
*pDst++ = (uint8)(((src0 & 0xFU) << 4) | (src1 >> 8));
*pDst++ = (uint8)(src1);
}
if (length & 1U) {
uint32 src0 = (uint32)pSrc[i+0];
*pDst++ = (uint8)(src0 >> 4);
*pDst++ = (uint8)(((src0 & 0xFU) << 4));
}
}
static void tif_32sto14u(const int32* pSrc, uint8* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)3U); i+=4U) {
uint32 src0 = (uint32)pSrc[i+0];
uint32 src1 = (uint32)pSrc[i+1];
uint32 src2 = (uint32)pSrc[i+2];
uint32 src3 = (uint32)pSrc[i+3];
*pDst++ = (uint8)(src0 >> 6);
*pDst++ = (uint8)(((src0 & 0x3FU) << 2) | (src1 >> 12));
*pDst++ = (uint8)(src1 >> 4);
*pDst++ = (uint8)(((src1 & 0xFU) << 4) | (src2 >> 10));
*pDst++ = (uint8)(src2 >> 2);
*pDst++ = (uint8)(((src2 & 0x3U) << 6) | (src3 >> 8));
*pDst++ = (uint8)(src3);
}
if (length & 3U) {
uint32 src0 = (uint32)pSrc[i+0];
uint32 src1 = 0U;
uint32 src2 = 0U;
length = length & 3U;
if (length > 1U) {
src1 = (uint32)pSrc[i+1];
if (length > 2U) {
src2 = (uint32)pSrc[i+2];
}
}
*pDst++ = (uint8)(src0 >> 6);
*pDst++ = (uint8)(((src0 & 0x3FU) << 2) | (src1 >> 12));
if (length > 1U) {
*pDst++ = (uint8)(src1 >> 4);
*pDst++ = (uint8)(((src1 & 0xFU) << 4) | (src2 >> 10));
if (length > 2U) {
*pDst++ = (uint8)(src2 >> 2);
*pDst++ = (uint8)(((src2 & 0x3U) << 6));
}
}
}
}
static void tif_32sto16u(const int32* pSrc, uint16* pDst, size_t length)
{
size_t i;
for (i = 0; i < length; ++i) {
pDst[i] = (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;
int32 i, numcomps;
size_t rowStride;
int32* buffer32s = NULL;
int32 const* planes[4];
convert_32s_PXCX cvtPxToCx = NULL;
convert_32sXXx_C1R cvt32sToTif = NULL;
bps = image->comps[0].prec;
planes[0] = image->comps[0].data;
numcomps = image->numcomps;
if (numcomps > 2) {
tiPhoto = PHOTOMETRIC_RGB;
if (numcomps > 4) {
numcomps = 4;
}
} else {
tiPhoto = PHOTOMETRIC_MINISBLACK;
}
for (i = 1; 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 = 0; 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 = ((size_t)width * numcomps * (size_t)bps + 7U) / 8U;
if (rowStride != (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 = (int32 *)malloc((size_t)width * numcomps * sizeof(int32));
if (buffer32s == NULL) {
_TIFFfree(buf);
TIFFClose(tif);
return 1;
}
for (i = 0; i < image->comps[0].h; ++i) {
cvtPxToCx(planes, buffer32s, (size_t)width, adjust);
cvt32sToTif(buffer32s, (uint8 *)buf, (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 uint8* pSrc, int32* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)3U); i+=4U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
uint32 val2 = *pSrc++;
uint32 val3 = *pSrc++;
uint32 val4 = *pSrc++;
pDst[i+0] = (int32)((val0 << 2) | (val1 >> 6));
pDst[i+1] = (int32)(((val1 & 0x3FU) << 4) | (val2 >> 4));
pDst[i+2] = (int32)(((val2 & 0xFU) << 6) | (val3 >> 2));
pDst[i+3] = (int32)(((val3 & 0x3U) << 8) | val4);
}
if (length & 3U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
length = length & 3U;
pDst[i+0] = (int32)((val0 << 2) | (val1 >> 6));
if (length > 1U) {
uint32 val2 = *pSrc++;
pDst[i+1] = (int32)(((val1 & 0x3FU) << 4) | (val2 >> 4));
if (length > 2U) {
uint32 val3 = *pSrc++;
pDst[i+2] = (int32)(((val2 & 0xFU) << 6) | (val3 >> 2));
}
}
}
}
static void tif_12uto32s(const uint8* pSrc, int32* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)1U); i+=2U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
uint32 val2 = *pSrc++;
pDst[i+0] = (int32)((val0 << 4) | (val1 >> 4));
pDst[i+1] = (int32)(((val1 & 0xFU) << 8) | val2);
}
if (length & 1U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
pDst[i+0] = (int32)((val0 << 4) | (val1 >> 4));
}
}
static void tif_14uto32s(const uint8* pSrc, int32* pDst, size_t length)
{
size_t i;
for (i = 0; i < (length & ~(size_t)3U); i+=4U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
uint32 val2 = *pSrc++;
uint32 val3 = *pSrc++;
uint32 val4 = *pSrc++;
uint32 val5 = *pSrc++;
uint32 val6 = *pSrc++;
pDst[i+0] = (int32)((val0 << 6) | (val1 >> 2));
pDst[i+1] = (int32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4));
pDst[i+2] = (int32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6));
pDst[i+3] = (int32)(((val5 & 0x3FU) << 8) | val6);
}
if (length & 3U) {
uint32 val0 = *pSrc++;
uint32 val1 = *pSrc++;
length = length & 3U;
pDst[i+0] = (int32)((val0 << 6) | (val1 >> 2));
if (length > 1U) {
uint32 val2 = *pSrc++;
uint32 val3 = *pSrc++;
pDst[i+1] = (int32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4));
if (length > 2U) {
uint32 val4 = *pSrc++;
uint32 val5 = *pSrc++;
pDst[i+2] = (int32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6));
}
}
}
}
/* seems that libtiff decodes this to machine endianness */
static void tif_16uto32s(const uint16* pSrc, int32* pDst, size_t length)
{
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 = 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 = (parameters->cp_cinema != OFF) ? OPJ_TRUE : OPJ_FALSE;
convert_XXx32s_C1R cvtTifTo32s = NULL;
convert_32s_CXPX cvtCxToPx = NULL;
int32* buffer32s = NULL;
int32* planes[4];
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 = CLRSPC_SRGB;
}
else if (tiPhoto == PHOTOMETRIC_MINISBLACK) /* GRAY(A) */
{
numcomps = 1 + has_alpha;
color_space = 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 = (uint32)subsampling_dx;
cmptparm[j].dy = (uint32)subsampling_dy;
cmptparm[j].w = (uint32)w;
cmptparm[j].h = (uint32)h;
}
image = opj_image_create((uint32)numcomps, &cmptparm[0], color_space);
if(!image)
{
TIFFClose(tif);
return NULL;
}
/* set image offset and reference grid */
image->x0 = (uint32)parameters->image_offset_x0;
image->y0 = (uint32)parameters->image_offset_y0;
image->x1 = !image->x0 ? (uint32)(w - 1) * (uint32)subsampling_dx + 1 :
image->x0 + (uint32)(w - 1) * (uint32)subsampling_dx + 1;
image->y1 = !image->y0 ? (uint32)(h - 1) * (uint32)subsampling_dy + 1 :
image->y0 + (uint32)(h - 1) * (uint32)subsampling_dy + 1;
for(j = 0; j < numcomps; j++)
{
planes[j] = image->comps[j].data;
}
/* image->comps[numcomps - 1].alpha = (uint16)(1 - (numcomps & 1)); */
strip_size = TIFFStripSize(tif);
buf = _TIFFmalloc(strip_size);
if (buf == NULL) {
TIFFClose(tif);
opj_image_destroy(image);
return NULL;
}
rowStride = ((size_t)w * tiSpp * tiBps + 7U) / 8U;
buffer32s = (int32 *)malloc((size_t)w * tiSpp * sizeof(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 uint8 *dat8;
size_t ssize;
ssize = (size_t)TIFFReadEncodedStrip(tif, strip, buf, strip_size);
dat8 = (const uint8*)buf;
while (ssize >= rowStride) {
cvtTifTo32s(dat8, buffer32s, (size_t)w * tiSpp);
cvtCxToPx(buffer32s, planes, (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() */

View File

@@ -82,7 +82,7 @@ typedef struct img_folder{
float *rates;
}img_fol_t;
void encode_help_display(void) {
static void encode_help_display(void) {
fprintf(stdout,"HELP for image_to_j2k\n----\n\n");
fprintf(stdout,"- the -h option displays this help information on screen\n\n");
@@ -321,7 +321,7 @@ void encode_help_display(void) {
fprintf(stdout,"TotalDisto\n\n");
}
OPJ_PROG_ORDER give_progression(char progression[4]) {
static OPJ_PROG_ORDER give_progression(char progression[4]) {
if(strncmp(progression, "LRCP", 4) == 0) {
return LRCP;
}
@@ -341,7 +341,7 @@ OPJ_PROG_ORDER give_progression(char progression[4]) {
return PROG_UNKNOWN;
}
int get_num_images(char *imgdirpath){
static int get_num_images(char *imgdirpath){
DIR *dir;
struct dirent* content;
int num_images = 0;
@@ -360,10 +360,11 @@ int get_num_images(char *imgdirpath){
continue;
num_images++;
}
closedir(dir);
return num_images;
}
int load_images(dircnt_t *dirptr, char *imgdirpath){
static int load_images(dircnt_t *dirptr, char *imgdirpath){
DIR *dir;
struct dirent* content;
int i = 0;
@@ -385,10 +386,11 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){
strcpy(dirptr->filename[i],content->d_name);
i++;
}
closedir(dir);
return 0;
}
int get_file_format(char *filename) {
static int get_file_format(char *filename) {
unsigned int i;
static const char *extension[] = {
"pgx", "pnm", "pgm", "ppm", "pbm", "pam", "bmp", "tif", "raw", "tga", "png", "j2k", "jp2", "j2c", "jpc"
@@ -408,14 +410,13 @@ int get_file_format(char *filename) {
return -1;
}
char * get_file_name(char *name){
static char * get_file_name(char *name){
char *fname;
fname= (char*)malloc(OPJ_PATH_LEN*sizeof(char));
fname= strtok(name,".");
return fname;
}
char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *parameters){
static char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_cparameters_t *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]="";
@@ -458,7 +459,7 @@ static int initialise_4K_poc(opj_poc_t *POC, int numres){
return 2;
}
void cinema_parameters(opj_cparameters_t *parameters){
static void cinema_parameters(opj_cparameters_t *parameters){
parameters->tile_size_on = OPJ_FALSE;
parameters->cp_tdx=1;
parameters->cp_tdy=1;
@@ -491,7 +492,7 @@ void cinema_parameters(opj_cparameters_t *parameters){
}
void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_fol_t *img_fol){
static void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_fol_t *img_fol){
int i;
float temp_rate;
@@ -576,7 +577,7 @@ void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_
/* ------------------------------------------------------------------------------------ */
int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
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) {
int i, j, totlen, c;
opj_option_t long_option[]={
@@ -589,7 +590,10 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
{"OutFor",REQ_ARG, NULL ,'O'},
{"POC",REQ_ARG, NULL ,'P'},
{"ROI",REQ_ARG, NULL ,'R'},
{"jpip",NO_ARG, NULL, 'J'}
{"jpip",NO_ARG, NULL, 'J'},
#ifdef USE_SYSTEM_GETOPT
{0,0,0,0} /* GNU getopt_long requirement */
#endif
};
/* parse the command line */
@@ -599,12 +603,16 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
#endif /* USE_JPWL */
"h";
totlen=sizeof(long_option);
totlen=sizeof(long_option);
img_fol->set_out_format=0;
raw_cp->rawWidth = 0;
do{
#ifdef USE_SYSTEM_GETOPT
c = opj_getopt_long(argc, argv, optlist,long_option,0);
#else
c = opj_getopt_long(argc, argv, optlist,long_option,totlen);
#endif
if (c == -1)
break;
switch (c) {
@@ -1385,10 +1393,10 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
/* ------------------------------------------------------ */
default:
fprintf(stderr, "ERROR -> Command line not valid\n");
return 1;
}
default:
fprintf(stderr, "[WARNING] An invalid option has been ignored\n");
break;
}
}while(c != -1);
/* check for possible errors */
@@ -1466,21 +1474,21 @@ int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters,
/**
sample error callback expecting a FILE* client object
*/
void error_callback(const char *msg, void *client_data) {
static void error_callback(const char *msg, void *client_data) {
FILE *stream = (FILE*)client_data;
fprintf(stream, "[ERROR] %s", msg);
}
/**
sample warning callback expecting a FILE* client object
*/
void warning_callback(const char *msg, void *client_data) {
static void warning_callback(const char *msg, void *client_data) {
FILE *stream = (FILE*)client_data;
fprintf(stream, "[WARNING] %s", msg);
}
/**
sample debug callback expecting a FILE* client object
*/
void info_callback(const char *msg, void *client_data) {
static void info_callback(const char *msg, void *client_data) {
FILE *stream = (FILE*)client_data;
fprintf(stream, "[INFO] %s", msg);
}

View File

@@ -121,6 +121,7 @@ int get_num_images(char *imgdirpath){
continue;
num_images++;
}
closedir(dir);
return num_images;
}
@@ -146,6 +147,7 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){
strcpy(dirptr->filename[i],content->d_name);
i++;
}
closedir(dir);
return 0;
}
@@ -199,15 +201,22 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
int totlen, c;
opj_option_t long_option[]={
{"ImgDir",REQ_ARG, NULL ,'y'},
#ifdef USE_SYSTEM_GETOPT
{0,0,0,0} /* GNU getopt_long requirement */
#endif
};
const char optlist[] = "i:o:h";
OPJ_ARG_NOT_USED(indexfilename);
totlen=sizeof(long_option);
totlen=sizeof(long_option);
img_fol->set_out_format = 0;
do {
#ifdef USE_SYSTEM_GETOPT
c = opj_getopt_long(argc, argv,optlist,long_option,0);
#else
c = opj_getopt_long(argc, argv,optlist,long_option,totlen);
#endif
if (c == -1)
break;
switch (c) {
@@ -258,7 +267,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
/* ----------------------------------------------------- */
default:
fprintf(stderr,"WARNING -> this option is not valid \"-%c %s\"\n",c, opj_optarg);
fprintf(stderr,"[WARNING] An invalid option has been ignored\n");
break;
}
}while(c != -1);
@@ -350,6 +359,11 @@ int main(int argc, char *argv[])
return 1;
}
/* j2k_dump focuses on j2k codestream and skips JP2 boxes */
parameters.flags = 1;
/* j2k_dump shall not actually decode packets (parsing codestream is enough). */
parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS;
/* Initialize reading of directory */
if(img_fol.set_imgdir==1){
num_images=get_num_images(img_fol.imgdirpath);
@@ -445,7 +459,7 @@ int main(int argc, char *argv[])
cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
/* decode the stream and fill the image structure */
if (*indexfilename) /* If need to extract codestream information*/
if (*indexfilename) /* If need to extract codestream information*/
image = opj_decode_with_info(dinfo, cio, &cstr_info);
else
image = opj_decode(dinfo, cio);
@@ -494,7 +508,7 @@ int main(int argc, char *argv[])
cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
/* decode the stream and fill the image structure */
if (*indexfilename) /* If need to extract codestream information*/
if (*indexfilename) /* If need to extract codestream information*/
image = opj_decode_with_info(dinfo, cio, &cstr_info);
else
image = opj_decode(dinfo, cio);

View File

@@ -85,7 +85,41 @@ typedef struct img_folder{
}img_fol_t;
void decode_help_display(void) {
typedef enum opj_prec_mode
{
OPJ_PREC_MODE_CLIP,
OPJ_PREC_MODE_SCALE
} opj_precision_mode;
typedef struct opj_prec
{
int 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;
opj_precision* precision;
int nb_precision;
/* force output colorspace to RGB */
int force_rgb;
/* upsample components according to their dx/dy values */
int upsample;
}opj_decompress_parameters;
static void decode_help_display(void) {
fprintf(stdout,"HELP for j2k_to_image\n----\n\n");
fprintf(stdout,"- the -h option displays this help information on screen\n\n");
@@ -128,6 +162,18 @@ void decode_help_display(void) {
fprintf(stdout," are decoded.\n");
fprintf(stdout," -x \n");
fprintf(stdout," Create an index file *.Idx (-x index_name.Idx) \n");
fprintf(stdout," -p <comp 0 precision>[C|S][,<comp 1 precision>[C|S][,...]]\n");
fprintf(stdout," OPTIONAL\n");
fprintf(stdout," 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");
fprintf(stdout," If there are less values than components, the last value is used for remaining components.\n");
fprintf(stdout," If 'C' is specified (default), values are clipped.\n");
fprintf(stdout," If 'S' is specified, values are scaled.\n");
fprintf(stdout," A 0 value can be specified (meaning original bit depth).\n");
fprintf(stdout," -force-rgb\n");
fprintf(stdout," Force output image colorspace to RGB\n");
fprintf(stdout," -upsample\n");
fprintf(stdout," Downsampled components will be upsampled to image size\n");
fprintf(stdout,"\n");
/* UniPG>> */
#ifdef USE_JPWL
@@ -144,7 +190,112 @@ void decode_help_display(void) {
/* -------------------------------------------------------------------------- */
int get_num_images(char *imgdirpath){
static opj_bool parse_precision(const char* option, opj_decompress_parameters* parameters)
{
const char* l_remaining = option;
opj_bool l_result = OPJ_TRUE;
/* reset */
if (parameters->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 {
int 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 = 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;
}
/* -------------------------------------------------------------------------- */
static int get_num_images(char *imgdirpath){
DIR *dir;
struct dirent* content;
int num_images = 0;
@@ -162,10 +313,11 @@ int get_num_images(char *imgdirpath){
continue;
num_images++;
}
closedir(dir);
return num_images;
}
int load_images(dircnt_t *dirptr, char *imgdirpath){
static int load_images(dircnt_t *dirptr, char *imgdirpath){
DIR *dir;
struct dirent* content;
int i = 0;
@@ -187,10 +339,11 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){
strcpy(dirptr->filename[i],content->d_name);
i++;
}
closedir(dir);
return 0;
}
int get_file_format(char *filename) {
static int get_file_format(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 };
@@ -209,7 +362,7 @@ int get_file_format(char *filename) {
return -1;
}
char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){
static 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]="";
@@ -235,15 +388,20 @@ char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparamet
}
/* -------------------------------------------------------------------------- */
int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) {
static int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol, char *indexfilename) {
/* parse the command line */
int totlen, c;
opj_option_t long_option[]={
{"ImgDir",REQ_ARG, NULL ,'y'},
{"OutFor",REQ_ARG, NULL ,'O'},
{"force-rgb", NO_ARG, NULL, 1},
{"upsample", NO_ARG, NULL, 1},
#ifdef USE_SYSTEM_GETOPT
{0,0,0,0} /* GNU getopt_long requirement */
#endif
};
const char optlist[] = "i:o:r:l:x:"
const char optlist[] = "i:o:r:l:x:p:"
/* UniPG>> */
#ifdef USE_JPWL
@@ -251,13 +409,22 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
#endif /* USE_JPWL */
/* <<UniPG */
"h" ;
long_option[2].flag = &(parameters->force_rgb);
long_option[3].flag = &(parameters->upsample);
totlen=sizeof(long_option);
img_fol->set_out_format = 0;
do {
#ifdef USE_SYSTEM_GETOPT
c = opj_getopt_long(argc, argv,optlist,long_option,0);
#else
c = opj_getopt_long(argc, argv,optlist,long_option,totlen);
#endif
if (c == -1)
break;
switch (c) {
case 0: /* long opt with flag */
break;
case 'i': /* input file */
{
char *infile = opj_optarg;
@@ -344,7 +511,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
case 'r': /* reduce option */
{
sscanf(opj_optarg, "%d", &parameters->cp_reduce);
sscanf(opj_optarg, "%d", &parameters->core.cp_reduce);
}
break;
@@ -353,7 +520,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
case 'l': /* layering option */
{
sscanf(opj_optarg, "%d", &parameters->cp_layer);
sscanf(opj_optarg, "%d", &parameters->core.cp_layer);
}
break;
@@ -380,6 +547,15 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
}
break;
/* ----------------------------------------------------- */
case 'p': /* Force precision */
{
if (!parse_precision(opj_optarg, parameters))
{
return 1;
}
}
break;
/* ----------------------------------------------------- */
/* UniPG>> */
#ifdef USE_JPWL
@@ -454,7 +630,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
/* ----------------------------------------------------- */
default:
fprintf(stderr,"WARNING -> this option is not valid \"-%c %s\"\n",c, opj_optarg);
fprintf(stderr,"[WARNING] An invalid option has been ignored\n");
break;
}
}while(c != -1);
@@ -487,32 +663,283 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i
/* -------------------------------------------------------------------------- */
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;
}
}
}
/* -------------------------------------------------------------------------- */
/**
sample error callback expecting a FILE* client object
*/
void error_callback(const char *msg, void *client_data) {
static void error_callback(const char *msg, void *client_data) {
FILE *stream = (FILE*)client_data;
fprintf(stream, "[ERROR] %s", msg);
}
/**
sample warning callback expecting a FILE* client object
*/
void warning_callback(const char *msg, void *client_data) {
static void warning_callback(const char *msg, void *client_data) {
FILE *stream = (FILE*)client_data;
fprintf(stream, "[WARNING] %s", msg);
}
/**
sample debug callback expecting no client object
*/
void info_callback(const char *msg, void *client_data) {
static void info_callback(const char *msg, void *client_data) {
(void)client_data;
fprintf(stdout, "[INFO] %s", msg);
}
/* -------------------------------------------------------------------------- */
static opj_image_t* convert_gray_to_rgb(opj_image_t* original)
{
int 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 -> j2k_to_image: 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 = 1; compno < original->numcomps; ++compno) {
l_new_components[compno+2].bpp = original->comps[compno].bpp;
l_new_components[compno+2].dx = original->comps[compno].dx;
l_new_components[compno+2].dy = original->comps[compno].dy;
l_new_components[compno+2].h = original->comps[compno].h;
l_new_components[compno+2].w = original->comps[compno].w;
l_new_components[compno+2].prec = original->comps[compno].prec;
l_new_components[compno+2].sgnd = original->comps[compno].sgnd;
l_new_components[compno+2].x0 = original->comps[compno].x0;
l_new_components[compno+2].y0 = original->comps[compno].y0;
}
l_new_image = opj_image_create(original->numcomps + 2, l_new_components, CLRSPC_SRGB);
free(l_new_components);
if (l_new_image == NULL) {
fprintf(stderr, "ERROR -> j2k_to_image: 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].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(int));
memcpy(l_new_image->comps[1].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(int));
memcpy(l_new_image->comps[2].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(int));
for(compno = 1; compno < original->numcomps; ++compno) {
l_new_image->comps[compno+2].factor = original->comps[compno].factor;
l_new_image->comps[compno+2].resno_decoded = original->comps[compno].resno_decoded;
memcpy(l_new_image->comps[compno+2].data, original->comps[compno].data, original->comps[compno].w * original->comps[compno].h * sizeof(int));
}
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;
int compno;
for (compno = 0; compno < original->numcomps; ++compno) {
if (original->comps[compno].factor > 0) {
fprintf(stderr, "ERROR -> j2k_to_image: -upsample not supported with reduction\n");
opj_image_destroy(original);
return NULL;
}
if ((original->comps[compno].dx > 1) || (original->comps[compno].dy > 1)) {
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 -> j2k_to_image: failed to allocate memory for upsampled components!\n");
opj_image_destroy(original);
return NULL;
}
for (compno = 0; 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 > 1) {
l_new_cmp->w = original->x1 - original->x0;
}
if (l_org_cmp->dy > 1) {
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 -> j2k_to_image: 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 = 0; 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->resno_decoded = l_org_cmp->resno_decoded;
if ((l_org_cmp->dx > 1) || (l_org_cmp->dy > 1)) {
const int* l_src = l_org_cmp->data;
int* l_dst = l_new_cmp->data;
int y;
int 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 -> j2k_to_image: Invalid image/component parameters found when upsampling\n");
opj_image_destroy(original);
opj_image_destroy(l_new_image);
return NULL;
}
for (y = 0; y < yoff; ++y) {
memset(l_dst, 0, l_new_cmp->w * sizeof(int));
l_dst += l_new_cmp->w;
}
if(l_new_cmp->h > (l_org_cmp->dy - 1)) { /* check subtraction overflow for really small images */
for (; y < l_new_cmp->h - (l_org_cmp->dy - 1); y += l_org_cmp->dy) {
int x, dy;
int xorg;
xorg = 0;
for (x = 0; x < xoff; ++x) {
l_dst[x] = 0;
}
if (l_new_cmp->w > (l_org_cmp->dx - 1)) { /* check subtraction overflow for really small images */
for (; x < l_new_cmp->w - (l_org_cmp->dx - 1); x += l_org_cmp->dx, ++xorg) {
int dx;
for (dx = 0; 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 = 1; dy < l_org_cmp->dy; ++dy) {
memcpy(l_dst, l_dst - l_new_cmp->w, l_new_cmp->w * sizeof(int));
l_dst += l_new_cmp->w;
}
l_src += l_org_cmp->w;
}
}
if (y < l_new_cmp->h) {
int x;
int xorg;
xorg = 0;
for (x = 0; x < xoff; ++x) {
l_dst[x] = 0;
}
if (l_new_cmp->w > (l_org_cmp->dx - 1)) { /* check subtraction overflow for really small images */
for (; x < l_new_cmp->w - (l_org_cmp->dx - 1); x += l_org_cmp->dx, ++xorg) {
int dx;
for (dx = 0; 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(int));
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(int));
}
}
opj_image_destroy(original);
return l_new_image;
}
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv) {
opj_dparameters_t parameters; /* decompression parameters */
opj_decompress_parameters parameters; /* decompression parameters */
img_fol_t img_fol;
opj_event_mgr_t event_mgr; /* event manager */
opj_image_t *image = NULL;
@@ -534,7 +961,7 @@ int main(int argc, char **argv) {
event_mgr.info_handler = info_callback;
/* set decoding parameters to default values */
opj_set_default_decoder_parameters(&parameters);
set_default_parameters(&parameters);
/* Initialize indexfilename and img_fol */
*indexfilename = 0;
@@ -542,6 +969,7 @@ int main(int argc, char **argv) {
/* parse input and get user encoding parameters */
if(parse_cmdline_decoder(argc, argv, &parameters,&img_fol, indexfilename) == 1) {
destroy_parameters(&parameters);
return 1;
}
@@ -555,6 +983,7 @@ int main(int argc, char **argv) {
dirptr->filename = (char**) malloc(num_images*sizeof(char*));
if(!dirptr->filename_buf){
destroy_parameters(&parameters);
return 1;
}
for(i=0;i<num_images;i++){
@@ -562,10 +991,12 @@ int main(int argc, char **argv) {
}
}
if(load_images(dirptr,img_fol.imgdirpath)==1){
destroy_parameters(&parameters);
return 1;
}
if (num_images==0){
fprintf(stdout,"Folder is empty\n");
destroy_parameters(&parameters);
return 1;
}
}else{
@@ -589,6 +1020,7 @@ int main(int argc, char **argv) {
fsrc = fopen(parameters.infile, "rb");
if (!fsrc) {
fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile);
destroy_parameters(&parameters);
return 1;
}
fseek(fsrc, 0, SEEK_END);
@@ -600,6 +1032,7 @@ int main(int argc, char **argv) {
free(src);
fclose(fsrc);
fprintf(stderr, "\nERROR: fread return a number of element different from the expected.\n");
destroy_parameters(&parameters);
return 1;
}
fclose(fsrc);
@@ -619,7 +1052,7 @@ int main(int argc, char **argv) {
opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
/* setup the decoder decoding parameters using user parameters */
opj_setup_decoder(dinfo, &parameters);
opj_setup_decoder(dinfo, &parameters.core);
/* open a byte stream */
cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
@@ -634,6 +1067,7 @@ int main(int argc, char **argv) {
opj_destroy_decompress(dinfo);
opj_cio_close(cio);
free(src);
destroy_parameters(&parameters);
return 1;
}
@@ -662,7 +1096,7 @@ int main(int argc, char **argv) {
opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
/* setup the decoder decoding parameters using the current image and user parameters */
opj_setup_decoder(dinfo, &parameters);
opj_setup_decoder(dinfo, &parameters.core);
/* open a byte stream */
cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
@@ -677,6 +1111,7 @@ int main(int argc, char **argv) {
opj_destroy_decompress(dinfo);
opj_cio_close(cio);
free(src);
destroy_parameters(&parameters);
return 1;
}
@@ -705,7 +1140,7 @@ int main(int argc, char **argv) {
opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
/* setup the decoder decoding parameters using user parameters */
opj_setup_decoder(dinfo, &parameters);
opj_setup_decoder(dinfo, &parameters.core);
/* open a byte stream */
cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
@@ -720,6 +1155,7 @@ int main(int argc, char **argv) {
opj_destroy_decompress(dinfo);
opj_cio_close(cio);
free(src);
destroy_parameters(&parameters);
return 1;
}
@@ -746,20 +1182,89 @@ int main(int argc, char **argv) {
free(src);
src = NULL;
if(image->color_space == CLRSPC_SYCC)
{
color_sycc_to_rgb(image);
}
if(image->color_space == CLRSPC_SYCC)
{
color_sycc_to_rgb(image);
}
if(image->icc_profile_buf)
{
if(image->icc_profile_buf)
{
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
color_apply_icc_profile(image);
color_apply_icc_profile(image);
#endif
free(image->icc_profile_buf);
image->icc_profile_buf = NULL; image->icc_profile_len = 0;
}
free(image->icc_profile_buf);
image->icc_profile_buf = NULL; image->icc_profile_len = 0;
}
/* Force output precision */
/* ---------------------- */
if (parameters.precision != NULL)
{
int compno;
for (compno = 0; compno < image->numcomps; ++compno)
{
int precno = compno;
int 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 -> j2k_to_image: failed to upsample image components!\n");
destroy_parameters(&parameters);
opj_destroy_decompress(dinfo);
return EXIT_FAILURE;
}
}
/* Force RGB output */
/* ---------------- */
if (parameters.force_rgb)
{
switch (image->color_space) {
case CLRSPC_SRGB:
break;
case CLRSPC_GRAY:
image = convert_gray_to_rgb(image);
break;
default:
fprintf(stderr, "ERROR -> j2k_to_image: don't know how to convert image to RGB colorspace!\n");
opj_image_destroy(image);
image = NULL;
break;
}
if (image == NULL) {
fprintf(stderr, "ERROR -> j2k_to_image: failed to convert to RGB image!\n");
destroy_parameters(&parameters);
opj_destroy_decompress(dinfo);
return EXIT_FAILURE;
}
}
/* create output image */
/* ------------------- */
@@ -845,6 +1350,7 @@ int main(int argc, char **argv) {
opj_image_destroy(image);
}
destroy_parameters(&parameters);
return 0;
}
/*end main*/

View File

@@ -46,21 +46,21 @@
#endif
/*--------------------------------------------------------
Matrix f<EFBFBD>r sYCC, Amendment 1 to IEC 61966-2-1
Matrix for sYCC, Amendment 1 to IEC 61966-2-1
Y : 0.299 0.587 0.114 :R
Cb: -0.1687 -0.3312 0.5 :G
Cr: 0.5 -0.4187 -0.0812 :B
Y : 0.299 0.587 0.114 :R
Cb: -0.1687 -0.3312 0.5 :G
Cr: 0.5 -0.4187 -0.0812 :B
Inverse:
Inverse:
R: 1 -3.68213e-05 1.40199 :Y
G: 1.00003 -0.344125 -0.714128 :Cb - 2^(prec - 1)
B: 0.999823 1.77204 -8.04142e-06 :Cr - 2^(prec - 1)
R: 1 -3.68213e-05 1.40199 :Y
G: 1.00003 -0.344125 -0.714128 :Cb - 2^(prec - 1)
B: 0.999823 1.77204 -8.04142e-06 :Cr - 2^(prec - 1)
-----------------------------------------------------------*/
-----------------------------------------------------------*/
static void sycc_to_rgb(int offset, int upb, int y, int cb, int cr,
int *out_r, int *out_g, int *out_b)
int *out_r, int *out_g, int *out_b)
{
int r, g, b;
@@ -79,28 +79,28 @@ 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 = img->comps[0].prec;
offset = 1<<(i - 1); upb = (1<<i)-1;
upb = (int)img->comps[0].prec;
offset = 1<<(upb - 1); upb = (1<<upb)-1;
maxw = img->comps[0].w; maxh = 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;
cb = img->comps[1].data;
cr = img->comps[2].data;
d0 = r = (int*)malloc(sizeof(int) * max);
d1 = g = (int*)malloc(sizeof(int) * max);
d2 = b = (int*)malloc(sizeof(int) * max);
d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
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;
@@ -111,36 +111,38 @@ 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 = img->comps[0].prec;
offset = 1<<(i - 1); upb = (1<<i)-1;
upb = (int)img->comps[0].prec;
offset = 1<<(upb - 1); upb = (1<<upb)-1;
maxw = img->comps[0].w; maxh = 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;
cb = img->comps[1].data;
cr = img->comps[2].data;
d0 = r = (int*)malloc(sizeof(int) * max);
d1 = g = (int*)malloc(sizeof(int) * max);
d2 = b = (int*)malloc(sizeof(int) * max);
d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
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;
@@ -151,55 +153,75 @@ static void sycc422_to_rgb(opj_image_t *img)
img->comps[2].dx = img->comps[0].dx;
img->comps[1].dy = img->comps[0].dy;
img->comps[2].dy = img->comps[0].dy;
}/* sycc422_to_rgb() */
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 = img->comps[0].prec;
offset = 1<<(i - 1); upb = (1<<i)-1;
upb = (int)img->comps[0].prec;
offset = 1<<(upb - 1); upb = (1<<upb)-1;
maxw = img->comps[0].w; maxh = 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;
cb = img->comps[1].data;
cr = img->comps[2].data;
d0 = r = (int*)malloc(sizeof(int) * max);
d1 = g = (int*)malloc(sizeof(int) * max);
d2 = b = (int*)malloc(sizeof(int) * max);
d0 = r = (int*)malloc(sizeof(int) * (size_t)max);
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;
@@ -216,46 +238,45 @@ 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 = CLRSPC_GRAY;
return;
}
{
img->color_space = CLRSPC_GRAY;
return;
}
if((img->comps[0].dx == 1)
&& (img->comps[1].dx == 2)
&& (img->comps[2].dx == 2)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 2)
&& (img->comps[2].dy == 2))/* horizontal and vertical sub-sample */
{
sycc420_to_rgb(img);
}
&& (img->comps[1].dx == 2)
&& (img->comps[2].dx == 2)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 2)
&& (img->comps[2].dy == 2))/* horizontal and vertical sub-sample */
{
sycc420_to_rgb(img);
}
else
if((img->comps[0].dx == 1)
&& (img->comps[1].dx == 2)
&& (img->comps[2].dx == 2)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 1)
&& (img->comps[2].dy == 1))/* horizontal sub-sample only */
if((img->comps[0].dx == 1)
&& (img->comps[1].dx == 2)
&& (img->comps[2].dx == 2)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 1)
&& (img->comps[2].dy == 1))/* horizontal sub-sample only */
{
sycc422_to_rgb(img);
}
else
if((img->comps[0].dx == 1)
&& (img->comps[1].dx == 1)
&& (img->comps[2].dx == 1)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 1)
&& (img->comps[2].dy == 1))/* no sub-sample */
{
sycc444_to_rgb(img);
}
else
{
fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n",
__FILE__,__LINE__);
return;
}
sycc422_to_rgb(img);
}
else
if((img->comps[0].dx == 1)
&& (img->comps[1].dx == 1)
&& (img->comps[2].dx == 1)
&& (img->comps[0].dy == 1)
&& (img->comps[1].dy == 1)
&& (img->comps[2].dy == 1))/* no sub-sample */
{
sycc444_to_rgb(img);
}
else
{
fprintf(stderr,"%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n", __FILE__,__LINE__);
return;
}
img->color_space = CLRSPC_SRGB;
}/* color_sycc_to_rgb() */
@@ -288,7 +309,12 @@ void color_apply_icc_profile(opj_image_t *image)
OPJ_COLOR_SPACE oldspace;
in_prof =
cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len);
cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len);
#ifdef DEBUG_PROFILE
FILE *icm = fopen("debug.icm","wb");
fwrite( image->icc_profile_buf,1, image->icc_profile_len,icm);
fclose(icm);
#endif
if(in_prof == NULL) return;
@@ -297,162 +323,207 @@ void color_apply_icc_profile(opj_image_t *image)
intent = cmsGetHeaderRenderingIntent(in_prof);
max_w = image->comps[0].w; max_h = image->comps[0].h;
prec = image->comps[0].prec;
max_w = (int)image->comps[0].w;
max_h = (int)image->comps[0].h;
prec = (int)image->comps[0].prec;
oldspace = image->color_space;
if(out_space == cmsSigRgbData) /* enumCS 16 */
{
in_type = TYPE_RGB_16;
out_type = TYPE_RGB_16;
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
{
if( prec <= 8 )
{
in_type = TYPE_RGB_8;
out_type = TYPE_RGB_8;
}
else
{
in_type = TYPE_RGB_16;
out_type = TYPE_RGB_16;
}
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
else if(out_space == cmsSigGrayData) /* enumCS 17 */
{
in_type = TYPE_GRAY_8;
out_type = TYPE_RGB_8;
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
else if(out_space == cmsSigYCbCrData) /* enumCS 18 */
{
in_type = TYPE_YCbCr_16;
out_type = TYPE_RGB_16;
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
else
if(out_space == cmsSigGrayData) /* enumCS 17 */
{
in_type = TYPE_GRAY_8;
out_type = TYPE_RGB_8;
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
else
if(out_space == cmsSigYCbCrData) /* enumCS 18 */
{
in_type = TYPE_YCbCr_16;
out_type = TYPE_RGB_16;
out_prof = cmsCreate_sRGBProfile();
image->color_space = CLRSPC_SRGB;
}
else
{
{
#ifdef DEBUG_PROFILE
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);
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);
#endif
return;
}
return;
}
#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);
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);
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,
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,
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;
(void)in_space;
#endif /* DEBUG_PROFILE */
transform = cmsCreateTransform(in_prof, in_type,
out_prof, out_type, intent, 0);
transform = cmsCreateTransform(in_prof, in_type, out_prof, out_type, intent, 0);
#ifdef HAVE_LIBLCMS2
/* Possible for: LCMS_VERSION >= 2000 :*/
/* Possible for: LCMS_VERSION >= 2000 :*/
cmsCloseProfile(in_prof);
cmsCloseProfile(out_prof);
#endif
if(transform == NULL)
{
{
#ifdef DEBUG_PROFILE
fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. "
"ICC Profile ignored.\n",__FILE__,__LINE__);
fprintf(stderr,"%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. "
"ICC Profile ignored.\n",__FILE__,__LINE__);
#endif
image->color_space = oldspace;
image->color_space = oldspace;
#ifdef HAVE_LIBLCMS1
cmsCloseProfile(in_prof);
cmsCloseProfile(out_prof);
cmsCloseProfile(in_prof);
cmsCloseProfile(out_prof);
#endif
return;
}
return;
}
if(image->numcomps > 2)/* RGB, RGBA */
{
unsigned short *inbuf, *outbuf, *in, *out;
max = max_w * max_h; nr_samples = max * 3 * sizeof(unsigned short);
in = inbuf = (unsigned short*)malloc(nr_samples);
out = outbuf = (unsigned short*)malloc(nr_samples);
{
if( prec <= 8 )
{
unsigned char *inbuf, *outbuf, *in, *out;
max = max_w * max_h;
nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char);
in = inbuf = (unsigned char*)malloc(nr_samples);
out = outbuf = (unsigned char*)malloc(nr_samples);
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
for(i = 0; i < max; ++i)
{
*in++ = (unsigned short)*r++;
*in++ = (unsigned short)*g++;
*in++ = (unsigned short)*b++;
}
for(i = 0; i < max; ++i)
{
*in++ = (unsigned char)*r++;
*in++ = (unsigned char)*g++;
*in++ = (unsigned char)*b++;
}
cmsDoTransform(transform, inbuf, outbuf, max);
cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
for(i = 0; i < max; ++i)
{
*r++ = (int)*out++;
*g++ = (int)*out++;
*b++ = (int)*out++;
}
free(inbuf); free(outbuf);
}
for(i = 0; i < max; ++i)
{
*r++ = (int)*out++;
*g++ = (int)*out++;
*b++ = (int)*out++;
}
free(inbuf); free(outbuf);
}
else
{
unsigned short *inbuf, *outbuf, *in, *out;
max = max_w * max_h;
nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short);
in = inbuf = (unsigned short*)malloc(nr_samples);
out = outbuf = (unsigned short*)malloc(nr_samples);
r = image->comps[0].data;
g = image->comps[1].data;
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);
r = image->comps[0].data;
g = image->comps[1].data;
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;
{
unsigned char *in, *inbuf, *out, *outbuf;
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);
max = max_w * max_h; nr_samples = max * 3 * sizeof(unsigned char);
in = inbuf = (unsigned char*)malloc(nr_samples);
out = outbuf = (unsigned char*)malloc(nr_samples);
image->comps = (opj_image_comp_t*)realloc(image->comps, (image->numcomps+2)*sizeof(opj_image_comp_t));
image->comps = (opj_image_comp_t*)
realloc(image->comps, (image->numcomps+2)*sizeof(opj_image_comp_t));
if(image->numcomps == 2)
image->comps[3] = image->comps[1];
if(image->numcomps == 2)
image->comps[3] = image->comps[1];
image->comps[1] = image->comps[0];
image->comps[2] = image->comps[0];
image->comps[1] = image->comps[0];
image->comps[2] = image->comps[0];
image->comps[1].data = (int*)calloc((size_t)max, sizeof(int));
image->comps[2].data = (int*)calloc((size_t)max, sizeof(int));
image->comps[1].data = (int*)calloc(max, sizeof(int));
image->comps[2].data = (int*)calloc(max, sizeof(int));
image->numcomps += 2;
image->numcomps += 2;
r = image->comps[0].data;
r = image->comps[0].data;
for(i = 0; i < max; ++i)
{
*in++ = (unsigned char)*r++;
}
cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
for(i = 0; i < max; ++i)
{
*in++ = (unsigned char)*r++;
}
cmsDoTransform(transform, inbuf, outbuf, max);
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
r = image->comps[0].data;
g = image->comps[1].data;
b = image->comps[2].data;
for(i = 0; i < max; ++i)
{
*r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++;
}
free(inbuf); free(outbuf);
for(i = 0; i < max; ++i)
{
*r++ = (int)*out++; *g++ = (int)*out++; *b++ = (int)*out++;
}
free(inbuf); free(outbuf);
}/* if(image->numcomps */
}/* if(image->numcomps */
cmsDeleteTransform(transform);

View File

@@ -10,11 +10,7 @@
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -42,6 +38,10 @@ static char sccsid[] = "@(#)opj_getopt.c 8.3 (Berkeley) 4/27/95";
#include <string.h>
#include "opj_getopt.h"
#ifdef USE_SYSTEM_GETOPT
#error
#endif
int opj_opterr = 1, /* if error message should be printed */
opj_optind = 1, /* index into parent argv vector */
opj_optopt, /* character checked for validity */

View File

@@ -1,5 +1,26 @@
/* last review : october 29th, 2002 */
#include "opj_config.h"
#ifdef USE_SYSTEM_GETOPT
#include <getopt.h>
#define opj_opterr opterr
#define opj_optind optind
#define opj_optopt optopt
#define opj_optreset optreset
#define opj_optarg optarg
typedef struct option opj_option_t;
#define NO_ARG no_argument
#define REQ_ARG required_argument
#define OPT_ARG optional_argument
#define opj_getopt getopt
#define opj_getopt_long getopt_long
#else
#ifndef _GETOPT_H_
#define _GETOPT_H_
@@ -9,7 +30,7 @@ typedef struct opj_option
int has_arg;
int *flag;
int val;
}opj_option_t;
} opj_option_t;
#define NO_ARG 0
#define REQ_ARG 1
@@ -27,3 +48,4 @@ extern int opj_getopt_long(int argc, char * const argv[], const char *optstring,
extern void reset_options_reading(void);
#endif /* _GETOPT_H_ */
#endif /* USE_SYSTEM_GETOPT */

View File

@@ -62,7 +62,7 @@ INSTALL(TARGETS openjpip_local
IF(BUILD_JPIP_SERVER)
ADD_LIBRARY(openjpip_server STATIC ${OPENJPIP_SRCS} ${SERVER_SRCS})
TARGET_LINK_LIBRARIES(openjpip_server ${FCGI_LIBRARIES} ${CURL_LIBRARIES} ${CMAKE_THREAD_LIBS})
TARGET_LINK_LIBRARIES(openjpip_server ${FCGI_LIBRARIES} ${CURL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
SET_TARGET_PROPERTIES(openjpip_server
PROPERTIES COMPILE_FLAGS "-DSERVER")
INSTALL(TARGETS openjpip_server

View File

@@ -677,7 +677,7 @@ placeholder_param_t * parse_phld( Byte_t *datastream, Byte8_t metalength)
phld = (placeholder_param_t *)malloc( sizeof(placeholder_param_t));
phld->LBox = big4( datastream);
strcpy( phld->TBox, "phld");
strncpy( phld->TBox, "phld", 4);
phld->Flags = big4( datastream+8);
phld->OrigID = big8( datastream+12);
phld->OrigBHlen = metalength - 20;

View File

@@ -57,6 +57,14 @@ ENDFOREACH(exe)
# Build the two java clients:
FIND_PACKAGE(Java 1.5 COMPONENTS Development) # javac, jar
# User can override this:
if(NOT DEFINED JAVA_SOURCE_VERSION)
set(JAVA_SOURCE_VERSION 1.5)
endif()
if(NOT DEFINED JAVA_TARGET_VERSION)
set(JAVA_TARGET_VERSION 1.5)
endif()
# Only build the java viewer if dev is found:
if(Java_Development_FOUND AND Java_JAVAC_EXECUTABLE)
set(jflags $ENV{JFLAGS})
@@ -70,6 +78,7 @@ if(Java_Development_FOUND AND Java_JAVAC_EXECUTABLE)
ADD_CUSTOM_COMMAND(
OUTPUT ${LIBRARY_OUTPUT_PATH}/opj_viewer.jar
COMMAND ${Java_JAVAC_EXECUTABLE} ${jflags}
-source ${JAVA_SOURCE_VERSION} -target ${JAVA_TARGET_VERSION}
${java1_srcs} -d ${CMAKE_CURRENT_BINARY_DIR}/classes1
COMMAND ${Java_JAR_EXECUTABLE} cfm ${LIBRARY_OUTPUT_PATH}/opj_viewer.jar
${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/dist/manifest.txt -C
@@ -124,6 +133,7 @@ if(Java_Development_FOUND AND Java_JAVAC_EXECUTABLE)
ADD_CUSTOM_COMMAND(
OUTPUT ${LIBRARY_OUTPUT_PATH}/opj_viewer_xerces.jar
COMMAND ${Java_JAVAC_EXECUTABLE} ${jflags}
-source ${JAVA_SOURCE_VERSION} -target ${JAVA_TARGET_VERSION}
-classpath ${APACHE_XERCES_JAR}
${java2_srcs} -d ${CMAKE_CURRENT_BINARY_DIR}/classes2
COMMAND ${Java_JAR_EXECUTABLE} cfm ${LIBRARY_OUTPUT_PATH}/opj_viewer_xerces.jar

View File

@@ -1,6 +1,8 @@
# Makefile for the MJ2 codecs of the OpenJPEG library: frames_to_mj2, mj2_to_frames, extract_j2k_from_mj2 and wrap_j2k_in_mj2
if(NOT USE_SYSTEM_GETOPT)
SET(common_SRCS ${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c)
endif()
# While mj2 executables do not use the API correctly, we do not link with the library but rather compile the sources files.
SET(OPJ_SRCS

View File

@@ -7,7 +7,7 @@
m4_define([OPJ_MAJOR], [1])
m4_define([OPJ_MINOR], [5])
m4_define([OPJ_MICRO], [0])
m4_define([OPJ_MICRO], [2])
m4_define([lt_cur], m4_eval(OPJ_MAJOR + OPJ_MINOR))
m4_define([lt_rev], OPJ_MICRO)
@@ -23,7 +23,6 @@ AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([opj_config.h])
AC_CANONICAL_SYSTEM
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([1.11 foreign dist-bzip2 dist-xz dist-zip])
@@ -466,8 +465,14 @@ AC_HEADER_DIRENT
### Checks for compiler characteristics
AM_PROG_CC_C_O
AC_C_BIGENDIAN
ac_cv_c_big_endian=0
AC_C_BIGENDIAN([ac_cv_c_big_endian=yes], [ac_cv_c_big_endian=no],[])
#
if test "x${ac_cv_c_big_endian}" = "xyes" ; then
AC_DEFINE(OPJ_BIG_ENDIAN, [1], [define to 1 if your machine has BE])
AC_DEFINE(WORDS_BIGENDIAN, [1], [define to 1 if your machine has BE])
fi
#
#OPJ_COMPILER_FLAG([-Wall])
#OPJ_COMPILER_FLAG([-Wextra])
#OPJ_COMPILER_FLAG([-Wshadow])

View File

@@ -147,7 +147,7 @@ HTML_STYLESHEET =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_TIMESTAMP = NO
HTML_ALIGN_MEMBERS = YES
HTML_DYNAMIC_SECTIONS = NO
GENERATE_DOCSET = NO

View File

@@ -148,7 +148,7 @@ HTML_STYLESHEET =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_TIMESTAMP = NO
HTML_ALIGN_MEMBERS = YES
HTML_DYNAMIC_SECTIONS = NO
GENERATE_DOCSET = NO

View File

@@ -45,6 +45,11 @@ dist_man3_MANS = \
man/man3/libopenjpeg.3
install-data-hook:
@echo -e " (MAN)\t$(man1dir)/image_to_j2k.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man1dir)/j2k_dump.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man1dir)/j2k_to_image.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man3dir)/libopenjpeg.3" >> $(top_builddir)/report.txt
if WANT_JPWL
cd $(DESTDIR)$(man1dir) && \
rm -f jpwl_image_to_j2k.1 && \
$(LN_S) image_to_j2k.1 jpwl_image_to_j2k.1
@@ -54,18 +59,17 @@ install-data-hook:
cd $(DESTDIR)$(man3dir) && \
rm -f jpwl_libopenjpeg.3 && \
$(LN_S) libopenjpeg.3 jpwl_libopenjpeg.3
@echo -e " (MAN)\t$(man1dir)/image_to_j2k.1" >> $(top_builddir)/report.txt
@echo -e " (LN)\t$(man1dir)/jpwl_image_to_j2k.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man1dir)/j2k_dump.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man1dir)/j2k_to_image.1" >> $(top_builddir)/report.txt
@echo -e " (LN)\t$(man1dir)//jpwl_j2k_to_image.1" >> $(top_builddir)/report.txt
@echo -e " (MAN)\t$(man3dir)/libopenjpeg.3" >> $(top_builddir)/report.txt
@echo -e " (LN)\t$(man3dir)/jpwl_libopenjpeg.3" >> $(top_builddir)/report.txt
endif
uninstall-hook:
if WANT_JPWL
rm -f $(DESTDIR)$(man1dir)/jpwl_image_to_j2k.1
rm -f $(DESTDIR)$(man1dir)/jpwl_j2k_to_image.1
rm -f $(DESTDIR)$(man3dir)/jpwl_libopenjpeg.3
endif
EXTRA_DIST = \
CMakeLists.txt \

View File

@@ -39,7 +39,9 @@ IF(UNIX)
TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME} m)
ENDIF(UNIX)
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()
# Build the JPWL library ?
IF(BUILD_JPWL)
ADD_SUBDIRECTORY(jpwl)
@@ -62,3 +64,10 @@ INSTALL(FILES openjpeg.h
INSTALL(
FILES ${OPENJPEG_SOURCE_DIR}/doc/man/man3/libopenjpeg.3
DESTINATION ${OPENJPEG_INSTALL_MAN_DIR}/man3)
# internal utilities to generate t1_luts.h
# no need to install:
ADD_EXECUTABLE(t1_generate_luts t1_generate_luts.c)
IF(UNIX)
TARGET_LINK_LIBRARIES(t1_generate_luts m)
ENDIF()

View File

@@ -35,7 +35,6 @@ openjpeg.c \
pi.c \
raw.c \
t1.c \
t1_generate_luts.c \
t2.c \
tcd.c \
tgt.c \

View File

@@ -42,7 +42,7 @@ Write a bit
@param bio BIO handle
@param b Bit to write (0 or 1)
*/
static void bio_putbit(opj_bio_t *bio, int b);
static void bio_putbit(opj_bio_t *bio, unsigned int b);
/**
Read a bit
@param bio BIO handle
@@ -78,7 +78,7 @@ static int bio_byteout(opj_bio_t *bio) {
if (bio->bp >= bio->end) {
return 1;
}
*bio->bp++ = bio->buf >> 8;
*bio->bp++ = (unsigned char)(bio->buf >> 8);
return 0;
}
@@ -92,7 +92,7 @@ static int bio_bytein(opj_bio_t *bio) {
return 0;
}
static void bio_putbit(opj_bio_t *bio, int b) {
static void bio_putbit(opj_bio_t *bio, unsigned int b) {
if (bio->ct == 0) {
bio_byteout(bio);
}
@@ -126,7 +126,7 @@ void bio_destroy(opj_bio_t *bio) {
}
int bio_numbytes(opj_bio_t *bio) {
return (bio->bp - bio->start);
return (int)(bio->bp - bio->start);
}
void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) {

View File

@@ -30,6 +30,7 @@
*/
#include "opj_includes.h"
#include <assert.h>
/* ----------------------------------------------------------------------- */
@@ -106,6 +107,7 @@ int OPJ_CALLCONV cio_tell(opj_cio_t *cio) {
* pos : position, in number of bytes, from the beginning of the stream
*/
void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) {
assert((cio->start + pos) <= cio->end);
cio->bp = cio->start + pos;
}
@@ -113,6 +115,7 @@ void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) {
* Number of bytes left before the end of the stream.
*/
int cio_numbytesleft(opj_cio_t *cio) {
assert((cio->end - cio->bp) >= 0);
return cio->end - cio->bp;
}
@@ -139,6 +142,7 @@ opj_bool cio_byteout(opj_cio_t *cio, unsigned char v) {
* Read a byte.
*/
unsigned char cio_bytein(opj_cio_t *cio) {
assert(cio->bp >= cio->start);
if (cio->bp >= cio->end) {
opj_event_msg(cio->cinfo, EVT_ERROR, "read error: passed the end of the codestream (start = %d, current = %d, end = %d\n", cio->start, cio->bp, cio->end);
return 0;
@@ -173,7 +177,7 @@ unsigned int cio_read(opj_cio_t *cio, int n) {
unsigned int v;
v = 0;
for (i = n - 1; i >= 0; i--) {
v += cio_bytein(cio) << (i << 3);
v += (unsigned int)cio_bytein(cio) << (i << 3);
}
return v;
}
@@ -184,6 +188,10 @@ unsigned int cio_read(opj_cio_t *cio, int n) {
* n : number of bytes to skip
*/
void cio_skip(opj_cio_t *cio, int n) {
assert((cio->bp + n) >= cio->bp);
if (((cio->bp + n) < cio->start) || ((cio->bp + n) > cio->end)) {
assert(0);
}
cio->bp += n;
}

View File

@@ -40,7 +40,7 @@ opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *c
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(1,image->numcomps * sizeof(opj_image_comp_t));
if(!image->comps) {
fprintf(stderr,"Unable to allocate memory for image.\n");
opj_image_destroy(image);

View File

@@ -43,6 +43,26 @@ The functions in INT.H have for goal to realize operations on integers.
/** @name Exported functions (see also openjpeg.h) */
/*@{*/
/* ----------------------------------------------------------------------- */
#include <assert.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#if defined(_WIN32)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#error unsupported platform
#endif
#endif
/**
Get the minimum of two integers
@return Returns a if a < b else b
@@ -84,15 +104,26 @@ Divide an integer and round upwards
@return Returns a divided by b
*/
static INLINE int int_ceildiv(int a, int b) {
return (a + b - 1) / b;
assert(b);
return (a + b - 1) / b;
}
/**
Divide an integer by a power of 2 and round upwards
@return Returns a divided by 2^b
*/
static INLINE int int_ceildivpow2(int a, int b) {
return (a + (1 << b) - 1) >> b;
return (int)((a + ((int64_t)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 int int64_ceildivpow2(int64_t a, int b) {
return (int)((a + ((int64_t)1 << b) - 1) >> b);
}
/**
Divide an integer by a power of 2 and round downwards
@return Returns a divided by 2^b

View File

@@ -32,6 +32,7 @@
*/
#include "opj_includes.h"
#include <assert.h>
/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */
/*@{*/
@@ -246,6 +247,12 @@ Add tile header marker information
@param len length of marker segment
*/
static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len);
/**
Validate encoding parameters and image before actual encoding
@param j2k J2K handle
@param image IMAGE handle
*/
static opj_bool j2k_validate_encode( opj_j2k_t *j2k, opj_image_t *image);
/*@}*/
@@ -404,6 +411,7 @@ static void j2k_write_siz(opj_j2k_t *j2k) {
static void j2k_read_siz(opj_j2k_t *j2k) {
int len, i;
int n_comps;
opj_cio_t *cio = j2k->cio;
opj_image_t *image = j2k->image;
@@ -422,12 +430,36 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n",
"invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n",
image->x0,image->x1,image->y0,image->y1);
j2k->state |= J2K_STATE_ERR;
return;
}
image->numcomps = cio_read(cio, 2); /* Csiz */
n_comps = (len - 36 - 2 ) / 3;
image->numcomps = cio_read(cio, 2); /* Csiz */
if (((len - 36 - 2 ) % 3 != 0)||(n_comps != image->numcomps)) {
opj_event_msg(j2k->cinfo, EVT_ERROR,"invalid SIZ marker value\n");
j2k->state |= J2K_STATE_ERR;
return;
}
/* testcase 4035.pdf.SIGSEGV.d8b.3375 */
if (image->x0 > image->x1 || image->y0 > image->y1) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", image->x1 - image->x0, image->y1 - image->y0);
return;
}
/* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */
if (!(cp->tdx * cp->tdy)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Error with SIZ marker: invalid tile size (tdx: %d, tdy: %d)\n", cp->tdx, cp->tdy);
return;
}
/* testcase 1610.pdf.SIGSEGV.59c.681 */
if (((int64)image->x1) * ((int64)image->y1) != (image->x1 * image->y1)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)\n", image->x1, image->y1);
return;
}
#ifdef USE_JPWL
if (j2k->cp->correct) {
@@ -466,11 +498,19 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
/* update components number in the jpwl_exp_comps filed */
cp->exp_comps = image->numcomps;
}
#else
(void)len;
#endif /* USE_JPWL */
/* prevent division by zero */
if (!(cp->tdx * cp->tdy)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "invalid tile size (tdx: %d, tdy: %d)\n", cp->tdx, cp->tdy);
return;
}
image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t));
for (i = 0; i < image->numcomps; i++) {
int tmp, w, h;
int tmp;
tmp = cio_read(cio, 1); /* Ssiz_i */
image->comps[i].prec = (tmp & 0x7f) + 1;
image->comps[i].sgnd = tmp >> 7;
@@ -506,9 +546,11 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
}
#endif /* USE_JPWL */
/* TODO: unused ? */
w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx);
h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy);
/* prevent division by zero */
if (!(image->comps[i].dx * image->comps[i].dy)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: invalid component size (dx: %d, dy: %d)\n", image->comps[i].dx, image->comps[i].dy);
return;
}
image->comps[i].resno_decoded = 0; /* number of resolution decoded */
image->comps[i].factor = cp->reduce; /* reducing factor per component */
@@ -517,6 +559,15 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx);
cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy);
/* gdal_fuzzer_check_number_of_tiles.jp2 */
if (cp->tw == 0 || cp->th == 0 || cp->tw > 65535 / cp->th) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"Invalid number of tiles : %u x %u (maximum fixed by jpeg2000 norm is 65535 tiles)\n",
cp->tw, cp->th);
return;
}
#ifdef USE_JPWL
if (j2k->cp->correct) {
/* if JPWL is on, we check whether TX errors have damaged
@@ -769,6 +820,7 @@ static void j2k_read_cod(opj_j2k_t *j2k) {
opj_image_t *image = j2k->image;
len = cio_read(cio, 2); /* Lcod */
(void)len;
tcp->csty = cio_read(cio, 1); /* Scod */
tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* SGcod (A) */
tcp->numlayers = cio_read(cio, 2); /* SGcod (B) */
@@ -822,7 +874,14 @@ static void j2k_read_coc(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
len = cio_read(cio, 2); /* Lcoc */
(void)len;
compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */
if (compno >= image->numcomps) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in COC (%d out of a maximum of %d)\n",
compno, image->numcomps);
return;
}
tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */
j2k_read_cox(j2k, compno);
}
@@ -893,6 +952,8 @@ static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) {
opj_event_msg(j2k->cinfo, EVT_WARNING ,
"bad number of subbands in Sqcx (%d) regarding to J2K_MAXBANDS (%d) \n"
"- limiting number of bands to J2K_MAXBANDS and try to move to the next markers\n", numbands, J2K_MAXBANDS);
/* edf_c2_1013627.jp2 */
numbands = 1;
}
#endif /* USE_JPWL */
@@ -1004,9 +1065,16 @@ static void j2k_read_qcc(opj_j2k_t *j2k) {
/* keep your private count of tiles */
backup_compno++;
};
}
#endif /* USE_JPWL */
if ((compno < 0) || (compno >= numcomp)) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in QCC (%d out of a maximum of %d)\n",
compno, j2k->image->numcomps);
return;
}
j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2));
}
@@ -1052,12 +1120,23 @@ static void j2k_read_poc(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lpoc */
numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2));
if( numpchgs >= 32 )
{
/* edf_c2_1103421.jp2 */
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad number of POCS (%d out of a maximum of %d)\n",
numpchgs, 32);
numpchgs = 0;
}
for (i = old_poc; i < numpchgs + old_poc; i++) {
opj_poc_t *poc;
poc = &tcp->pocs[i];
poc->resno0 = cio_read(cio, 1); /* RSpoc_i */
poc->compno0 = cio_read(cio, numcomps <= 256 ? 1 : 2); /* CSpoc_i */
poc->layno1 = cio_read(cio, 2); /* LYEpoc_i */
/* make sure layer end is in acceptable bounds - issue 80*/
poc->layno1 = int_min(poc->layno1, (unsigned int) tcp->numlayers);
poc->resno1 = cio_read(cio, 1); /* REpoc_i */
poc->compno1 = int_min(
cio_read(cio, numcomps <= 256 ? 1 : 2), (unsigned int) numcomps); /* CEpoc_i */
@@ -1074,9 +1153,12 @@ static void j2k_read_crg(opj_j2k_t *j2k) {
int numcomps = j2k->image->numcomps;
len = cio_read(cio, 2); /* Lcrg */
(void)len;
for (i = 0; i < numcomps; i++) {
Xcrg_i = cio_read(cio, 2); /* Xcrg_i */
(void)Xcrg_i;
Ycrg_i = cio_read(cio, 2); /* Ycrg_i */
(void)Ycrg_i;
}
}
@@ -1088,13 +1170,16 @@ static void j2k_read_tlm(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Ltlm */
Ztlm = cio_read(cio, 1); /* Ztlm */
(void)Ztlm;
Stlm = cio_read(cio, 1); /* Stlm */
ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02);
SP = (Stlm >> 6) & 0x01;
tile_tlm = (len - 4) / ((SP + 1) * 2 + ST);
for (i = 0; i < tile_tlm; i++) {
Ttlm_i = cio_read(cio, ST); /* Ttlm_i */
(void)Ttlm_i;
Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */
(void)Ptlm_i;
}
}
@@ -1105,6 +1190,7 @@ static void j2k_read_plm(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lplm */
Zplm = cio_read(cio, 1); /* Zplm */
(void)Zplm;
len -= 3;
while (len > 0) {
Nplm = cio_read(cio, 4); /* Nplm */
@@ -1130,6 +1216,7 @@ static void j2k_read_plt(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lplt */
Zplt = cio_read(cio, 1); /* Zplt */
(void)Zplt;
for (i = len - 3; i > 0; i--) {
add = cio_read(cio, 1);
packet_len = (packet_len << 7) + add; /* Iplt_i */
@@ -1152,6 +1239,7 @@ static void j2k_read_ppm(opj_j2k_t *j2k) {
Z_ppm = cio_read(cio, 1); /* Z_ppm */
len -= 3;
while (len > 0) {
if (cp->ppm_previous == 0) {
N_ppm = cio_read(cio, 4); /* N_ppm */
@@ -1159,9 +1247,16 @@ static void j2k_read_ppm(opj_j2k_t *j2k) {
} else {
N_ppm = cp->ppm_previous;
}
/* issue 362-2863, issue 393 */
if (N_ppm < 0) {
j2k->state = J2K_STATE_ERR;
return;
}
j = cp->ppm_store;
if (Z_ppm == 0) { /* First PPM marker */
cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char));
if (Z_ppm == 0) { /* First PPM marker */
cp->ppm_data = (unsigned char *) opj_malloc(N_ppm * sizeof(unsigned char));
cp->ppm_data_first = cp->ppm_data;
cp->ppm_len = N_ppm;
} else { /* NON-first PPM marker */
@@ -1277,6 +1372,7 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
len = cio_read(cio, 2);
(void)len;
tileno = cio_read(cio, 2);
#ifdef USE_JPWL
@@ -1513,26 +1609,14 @@ static void j2k_read_sod(opj_j2k_t *j2k) {
truncate = 1; /* Case of a truncate codestream */
}
{/* chop padding bytes: */
unsigned char *s, *e;
s = cio_getbp(cio);
e = s + len;
if(len > 8) s = e - 8;
if(e[-2] == 0x00 && e[-1] == 0x00) /* padding bytes */
{
while(e > s)
{
if(e[-2] == 0xff && e[-1] == 0xd9) break;
--len; --e; truncate = 1;
}
}
}
data = j2k->tile_data[curtileno];
data_ptr = data; /* store in case of failure */
data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char));
if( data == NULL ) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not reallocated\n" );
opj_free( data_ptr );
return;
}
data_ptr = data + j2k->tile_len[curtileno];
for (i = 0; i < len; i++) {
@@ -1572,8 +1656,10 @@ static void j2k_read_rgn(opj_j2k_t *j2k) {
int numcomps = j2k->image->numcomps;
len = cio_read(cio, 2); /* Lrgn */
(void)len;
compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */
roisty = cio_read(cio, 1); /* Srgn */
(void)roisty;
#ifdef USE_JPWL
if (j2k->cp->correct) {
@@ -1590,6 +1676,13 @@ static void j2k_read_rgn(opj_j2k_t *j2k) {
};
#endif /* USE_JPWL */
if (compno >= numcomps) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in RGN (%d out of a maximum of %d)\n",
compno, j2k->image->numcomps);
return;
}
tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */
}
@@ -1620,6 +1713,7 @@ static void j2k_read_eoc(opj_j2k_t *j2k) {
{
tileno = j2k->cp->tileno[i];
success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info);
assert( tileno != -1 );
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
tcd_free_decode_tile(tcd, i);
@@ -1636,6 +1730,8 @@ static void j2k_read_eoc(opj_j2k_t *j2k) {
}
/* if packets should not be decoded */
else {
opj_event_msg(j2k->cinfo, EVT_INFO, "Codestream parsing complete.\n");
opj_event_msg(j2k->cinfo, EVT_INFO, "Skipped actual packet decoding.\n");
for (i = 0; i < j2k->cp->tileno_size; i++) {
tileno = j2k->cp->tileno[i];
opj_free(j2k->tile_data[tileno]);
@@ -1799,8 +1895,11 @@ void j2k_destroy_decompress(opj_j2k_t *j2k) {
if(j2k->cp != NULL) {
for (i = 0; i < j2k->cp->tileno_size; i++) {
int tileno = j2k->cp->tileno[i];
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
if( tileno != -1 )
{
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
}
}
}
@@ -1964,6 +2063,11 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
}
if (j2k->state == J2K_STATE_NEOC) {
j2k_read_eoc(j2k);
/* Check one last time for errors during decoding before returning */
if (j2k->state & J2K_STATE_ERR) {
opj_image_destroy(image);
return NULL;
}
}
if (j2k->state != J2K_STATE_MT) {
@@ -2366,6 +2470,9 @@ opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_code
cp = j2k->cp;
/* Parameters validation */
if (!j2k_validate_encode(j2k, image)) return OPJ_FALSE;
/* INDEX >> */
j2k->cstr_info = cstr_info;
if (cstr_info) {
@@ -2614,3 +2721,21 @@ static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsi
marker->len = len;
cstr_info->tile[tileno].marknum++;
}
static opj_bool j2k_validate_encode(opj_j2k_t *j2k, opj_image_t *image) {
int compno;
opj_bool is_valid = OPJ_TRUE;
/* preconditions */
assert(j2k != 00);
assert(image != 00);
/* PARAMETERS checking */
for (compno=0; compno < image->numcomps; compno++) {
is_valid &= (image->comps[compno].dx >= 1 && j2k->image->comps[compno].dx <= 255);
is_valid &= (image->comps[compno].dy >= 1 && j2k->image->comps[compno].dy <= 255);
}
return is_valid;
}

View File

@@ -30,6 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opj_includes.h"
#include <assert.h>
/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */
/*@{*/
@@ -172,6 +173,9 @@ static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_bo
}
else if (box->length == 0) {
box->length = cio_numbytesleft(cio) + 8;
} else if (box->length < 0) {
opj_event_msg(cinfo, EVT_ERROR, "Integer overflow in box->length\n");
return OPJ_FALSE; /* TODO: actually check jp2_read_boxhdr's return value */
}
return OPJ_TRUE;
@@ -518,10 +522,8 @@ static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio,
static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color)
{
opj_jp2_cdef_info_t *info;
int color_space;
unsigned short i, n, cn, typ, asoc, acn;
color_space = image->color_space;
info = color->jp2_cdef->info;
n = color->jp2_cdef->n;
@@ -531,6 +533,7 @@ static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color)
if((asoc = info[i].asoc) == 0) continue;
cn = info[i].cn; typ = info[i].typ; acn = asoc - 1;
(void)typ;
if(cn != acn)
{
@@ -654,6 +657,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n");
return OPJ_FALSE;
}
if (box.length <= 8) return OPJ_FALSE;
cio_skip(cio, box.length - 8);
if(cio->bp >= cio->end) return OPJ_FALSE;
@@ -679,6 +683,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
{
if( !jp2_read_colr(jp2, cio, &box, color))
{
if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
}
@@ -689,6 +694,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
{
if( !jp2_read_cdef(jp2, cio, &box, color))
{
if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
}
@@ -699,6 +705,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
{
if( !jp2_read_pclr(jp2, cio, &box, color))
{
if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
}
@@ -709,12 +716,14 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
{
if( !jp2_read_cmap(jp2, cio, &box, color))
{
if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
}
if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
continue;
}
if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
@@ -728,6 +737,84 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
}/* jp2_read_jp2h() */
static opj_bool opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, opj_common_ptr cinfo)
{
int i;
/* testcase 4149.pdf.SIGSEGV.cf7.3501 */
if (color->jp2_cdef) {
opj_jp2_cdef_info_t *info = color->jp2_cdef->info;
int n = color->jp2_cdef->n;
for (i = 0; i < n; i++) {
if (info[i].cn >= image->numcomps) {
opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, image->numcomps);
return OPJ_FALSE;
}
if (info[i].asoc > 0 && (info[i].asoc - 1) >= image->numcomps) {
opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, image->numcomps);
return OPJ_FALSE;
}
}
}
/* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and
66ea31acbb0f23a2bbc91f64d69a03f5_signal_sigsegv_13937c0_7030_5725.pdf */
if (color->jp2_pclr && color->jp2_pclr->cmap) {
int nr_channels = color->jp2_pclr->nr_channels;
opj_jp2_cmap_comp_t *cmap = color->jp2_pclr->cmap;
opj_bool *pcol_usage, is_sane = OPJ_TRUE;
/* verify that all original components match an existing one */
for (i = 0; i < nr_channels; i++) {
if (cmap[i].cmp >= image->numcomps) {
opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", cmap[i].cmp, image->numcomps);
is_sane = OPJ_FALSE;
}
}
pcol_usage = opj_calloc(nr_channels, sizeof(opj_bool));
if (!pcol_usage) {
opj_event_msg(cinfo, EVT_ERROR, "Unexpected OOM.\n");
return OPJ_FALSE;
}
/* verify that no component is targeted more than once */
for (i = 0; i < nr_channels; i++) {
int pcol = cmap[i].pcol;
assert(cmap[i].mtyp == 0 || cmap[i].mtyp == 1);
if (pcol >= nr_channels) {
opj_event_msg(cinfo, EVT_ERROR, "Invalid component/palette index for direct mapping %d.\n", pcol);
is_sane = OPJ_FALSE;
}
else if (pcol_usage[pcol] && cmap[i].mtyp == 1) {
opj_event_msg(cinfo, EVT_ERROR, "Component %d is mapped twice.\n", pcol);
is_sane = OPJ_FALSE;
}
else if (cmap[i].mtyp == 0 && cmap[i].pcol != 0) {
/* I.5.3.5 PCOL: If the value of the MTYP field for this channel is 0, then
* the value of this field shall be 0. */
opj_event_msg(cinfo, EVT_ERROR, "Direct use at #%d however pcol=%d.\n", i, pcol);
is_sane = OPJ_FALSE;
}
else
pcol_usage[pcol] = OPJ_TRUE;
}
/* verify that all components are targeted at least once */
for (i = 0; i < nr_channels; i++) {
if (!pcol_usage[i] && cmap[i].mtyp != 0) {
opj_event_msg(cinfo, EVT_ERROR, "Component %d doesn't have a mapping.\n", i);
is_sane = OPJ_FALSE;
}
}
opj_free(pcol_usage);
if (!is_sane) {
return OPJ_FALSE;
}
}
return OPJ_TRUE;
}
opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio,
opj_codestream_info_t *cstr_info)
{
@@ -761,6 +848,10 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio,
}
if (!jp2->ignore_pclr_cmap_cdef){
if (!opj_jp2_check_color(image, &color, cinfo)) {
opj_event_msg(cinfo, EVT_ERROR, "Failed to decode PCRL box\n");
return NULL;
}
/* Set Image Color Space */
if (jp2->enumcs == 16)
@@ -856,6 +947,14 @@ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) {
jp2->brand = cio_read(cio, 4); /* BR */
jp2->minversion = cio_read(cio, 4); /* MinV */
jp2->numcl = (box.length - 16) / 4;
/* edf_c2_1673169.jp2 */
if (cio_numbytesleft(cio) < ((int)jp2->numcl * 4)) {
opj_event_msg(cinfo, EVT_ERROR, "Not enough bytes in FTYP Box "
"(expected %d, but only %d left)\n",
((int)jp2->numcl * 4), cio_numbytesleft(cio));
return OPJ_FALSE;
}
jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int));
for (i = 0; i < (int)jp2->numcl; i++) {
@@ -910,12 +1009,14 @@ static opj_bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_
}
do {
if(JP2_JP2C != box.type) {
if (box.length <= 8) return OPJ_FALSE;
cio_skip(cio, box.length - 8);
if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
}
} while(JP2_JP2C != box.type);
*j2k_codestream_offset = cio_tell(cio);
if (box.length <= 8) return OPJ_FALSE;
*j2k_codestream_length = box.length - 8;
return OPJ_TRUE;
@@ -1083,6 +1184,7 @@ void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) {
opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo) {
opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t));
if(jp2) {
memset(jp2, 0, sizeof(opj_jp2_t));
jp2->cinfo = cinfo;
/* create the J2K codec */
jp2->j2k = j2k_create_compress(cinfo);

View File

@@ -26,8 +26,10 @@ ADD_LIBRARY(${OPENJPEG_LIBRARY_NAME}_JPWL ${JPWL_SRCS} ${OPENJPEG_SRCS})
IF(UNIX)
TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME}_JPWL m)
ENDIF(UNIX)
SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME}_JPWL
PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES})
SET_TARGET_PROPERTIES(${OPENJPEG_LIBRARY_NAME}_JPWL PROPERTIES ${OPENJPEG_LIBRARY_PROPERTIES})
IF(${CMAKE_VERSION} VERSION_GREATER "2.8.11")
TARGET_COMPILE_OPTIONS(${OPENJPEG_LIBRARY_NAME}_JPWL PRIVATE ${OPENJPEG_LIBRARY_COMPILE_OPTIONS})
ENDIF()
# Install library
INSTALL(TARGETS ${OPENJPEG_LIBRARY_NAME}_JPWL

View File

@@ -18,7 +18,6 @@ OPJ_SRC = \
../pi.c \
../raw.c \
../t1.c \
../t1_generate_luts.c \
../t2.c \
../tcd.c \
../tgt.c \

View File

@@ -46,6 +46,7 @@
OpenJPEG interface
==========================================================
*/
#include "opj_config.h"
#include "openjpeg.h"
/*
@@ -89,18 +90,17 @@ Most compilers implement their own version of this keyword ...
/* MSVC and Borland C do not have lrintf */
#if defined(_MSC_VER) || defined(__BORLANDC__)
static INLINE long lrintf(float f){
#ifdef _M_X64
return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
#else
int i;
#ifdef _M_IX86
long int i;
_asm{
fld f
fistp i
};
return i;
#endif
#else
return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
#endif /* _M_IX86 */
}
#endif

View File

@@ -340,12 +340,12 @@ static opj_bool pi_next_cprl(opj_pi_iterator_t * pi) {
pi->dx = 0;
pi->dy = 0;
for (resno = 0; resno < comp->numresolutions; resno++) {
int dx, dy;
int64 dx, dy;
res = &comp->resolutions[resno];
dx = comp->dx * (1 << (res->pdx + comp->numresolutions - 1 - resno));
dy = comp->dy * (1 << (res->pdy + comp->numresolutions - 1 - resno));
pi->dx = !pi->dx ? dx : int_min(pi->dx, dx);
pi->dy = !pi->dy ? dy : int_min(pi->dy, dy);
dx = comp->dx * (((int64) 1) << (res->pdx + comp->numresolutions - 1 - resno));
dy = comp->dy * (((int64) 1) << (res->pdy + comp->numresolutions - 1 - resno));
pi->dx = !pi->dx ? dx : pi->dx < dx ? pi->dx : dx;
pi->dy = !pi->dy ? dy : pi->dy < dy ? pi->dy : dy;
}
if (!pi->tp_on){
pi->poc.ty0 = pi->ty0;

View File

@@ -93,8 +93,8 @@ typedef struct opj_pi_iterator {
int numcomps;
/** Components*/
opj_pi_comp_t *comps;
int tx0, ty0, tx1, ty1;
int x, y, dx, dy;
int tx0, ty0, tx1, ty1;
int64 x, y, dx, dy;
} opj_pi_iterator_t;
/** @name Exported functions */

View File

@@ -194,7 +194,7 @@ int main(){
printf("/* This file was automatically generated by t1_generate_luts.c */\n\n");
// lut_ctxno_zc
/* lut_ctxno_zc */
for (j = 0; j < 4; ++j) {
for (i = 0; i < 256; ++i) {
int orient = j;
@@ -215,7 +215,7 @@ int main(){
}
printf("%i\n};\n\n", lut_ctxno_zc[1023]);
// lut_ctxno_sc
/* lut_ctxno_sc */
printf("static char lut_ctxno_sc[256] = {\n ");
for (i = 0; i < 255; ++i) {
printf("0x%x, ", t1_init_ctxno_sc(i << 4));
@@ -224,7 +224,7 @@ int main(){
}
printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4));
// lut_spb
/* lut_spb */
printf("static char lut_spb[256] = {\n ");
for (i = 0; i < 255; ++i) {
printf("%i, ", t1_init_spb(i << 4));

View File

@@ -30,6 +30,7 @@
*/
#include "opj_includes.h"
#include <assert.h>
/** @defgroup T2 T2 - Implementation of a tier-2 coding */
/*@{*/
@@ -340,13 +341,15 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
int precno = pi->precno; /* precinct value */
int layno = pi->layno; /* quality layer value */
opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno];
unsigned char *hd = NULL;
int present;
opj_bio_t *bio = NULL; /* BIO component */
opj_tcd_resolution_t* res;
assert(&tile->comps[compno] != NULL);
res = &tile->comps[compno].resolutions[resno];
if (layno == 0) {
for (bandno = 0; bandno < res->numbands; bandno++) {
opj_tcd_band_t *band = &res->bands[bandno];

View File

@@ -32,6 +32,7 @@
#define _ISOC99_SOURCE /* lrintf is C99 */
#include "opj_includes.h"
#include <assert.h>
void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) {
int tileno, compno, resno, bandno, precno;/*, cblkno;*/
@@ -250,6 +251,8 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
(void)brcbgyend;
(void)brcbgxend;
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -273,10 +276,10 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
band->y1 = int_ceildivpow2(tilec->y1, levelno);
} else {
/* band border (global) */
band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1);
band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1);
band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1);
band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1);
band->x0 = int64_ceildivpow2(tilec->x0 - ((int64_t)x0b << levelno), levelno + 1);
band->y0 = int64_ceildivpow2(tilec->y0 - ((int64_t)y0b << levelno), levelno + 1);
band->x1 = int64_ceildivpow2(tilec->x1 - ((int64_t)x0b << levelno), levelno + 1);
band->y1 = int64_ceildivpow2(tilec->y1 - ((int64_t)y0b << levelno), levelno + 1);
}
ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1];
@@ -512,6 +515,8 @@ void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int cur
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
(void)brcbgyend;
(void)brcbgxend;
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -760,6 +765,8 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
(void)brcbgyend;
(void)brcbgxend;
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -782,10 +789,10 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
band->y1 = int_ceildivpow2(tilec->y1, levelno);
} else {
/* band border (global) */
band->x0 = int_ceildivpow2(tilec->x0 - (1 << levelno) * x0b, levelno + 1);
band->y0 = int_ceildivpow2(tilec->y0 - (1 << levelno) * y0b, levelno + 1);
band->x1 = int_ceildivpow2(tilec->x1 - (1 << levelno) * x0b, levelno + 1);
band->y1 = int_ceildivpow2(tilec->y1 - (1 << levelno) * y0b, levelno + 1);
band->x0 = int64_ceildivpow2(tilec->x0 - ((int64_t)x0b << levelno), levelno + 1);
band->y0 = int64_ceildivpow2(tilec->y0 - ((int64_t)y0b << levelno), levelno + 1);
band->x1 = int64_ceildivpow2(tilec->x1 - ((int64_t)x0b << levelno), levelno + 1);
band->y1 = int64_ceildivpow2(tilec->y1 - ((int64_t)y0b << levelno), levelno + 1);
}
ss = &tccp->stepsizes[resno == 0 ? 0 : 3 * (resno - 1) + bandno + 1];
@@ -981,7 +988,7 @@ void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) {
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;
}
layer->numpasses = n - cblk->numpassesinlayers;
@@ -1381,6 +1388,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");
return OPJ_FALSE;
}
/*------------------TIER1-----------------*/
@@ -1401,6 +1409,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
if (tilec->data == NULL)
{
opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
t1_destroy(t1);
return OPJ_FALSE;
}
@@ -1424,10 +1433,12 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
return OPJ_FALSE;
}
else {
tcd->image->comps[compno].resno_decoded =
tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
tcd->image->comps[compno].resno_decoded = tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
}
}
else {
tcd->image->comps[compno].resno_decoded = tile->comps[compno].numresolutions - 1;
}
numres2decode = tcd->image->comps[compno].resno_decoded + 1;
if(numres2decode > 0){
@@ -1447,6 +1458,13 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0);
if (tile->numcomps >= 3 ){
/* testcase 1336.pdf.asan.47.376 */
if ((tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0) < n ||
( tile->comps[1].x1 - tile->comps[1].x0) * (tile->comps[1].y1 - tile->comps[1].y0) < n ||
( tile->comps[2].x1 - tile->comps[2].x0) * (tile->comps[2].y1 - tile->comps[2].y0) < n) {
opj_event_msg(tcd->cinfo, EVT_ERROR, "Tiles don't all have the same dimension. Skip the MCT step.\n");
return OPJ_FALSE;
}
if (tcd->tcp->tccps[0].qmfbid == 1) {
mct_decode(
tile->comps[0].data,
@@ -1478,10 +1496,19 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
int tw = tilec->x1 - tilec->x0;
int w = imagec->w;
int i, j;
int offset_x = int_ceildivpow2(imagec->x0, imagec->factor);
int offset_y = int_ceildivpow2(imagec->y0, imagec->factor);
/* NR-DEC-2977.pdf.asan.67.2198.jp2-52-decode */
if( res->x0 - offset_x < 0 || res->x1 - offset_x < 0
|| res->y0 - offset_y < 0 || res->y1 - offset_y < 0 )
{
opj_event_msg(tcd->cinfo, EVT_ERROR, "Impossible offsets %d / %d\n", offset_x, offset_y);
return OPJ_FALSE;
}
assert( 0 <= res->x0 - offset_x && 0 <= res->x1 - offset_x );
assert( 0 <= res->y0 - offset_y && 0 <= res->y1 - offset_y );
int i, j;
if(!imagec->data){
imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int));
}
@@ -1495,6 +1522,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
for(i = res->x0; i < res->x1; ++i) {
int v = tilec->data[i - res->x0 + (j - res->y0) * tw];
v += adjust;
/*assert( (i - offset_x) + (j - offset_y) * w >= 0 );*/
imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max);
}
}
@@ -1504,6 +1532,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw];
int v = lrintf(tmp);
v += adjust;
/*assert( (i - offset_x) + (j - offset_y) * w >= 0 );*/
imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max);
}
}

View File

@@ -21,16 +21,28 @@ __opj_func=$4
__opj_have_dep="no"
save_CPPFLAGS=${CPPFLAGS}
save_LDFLAGS=${LDFLAGS}
save_LIBS=${LIBS}
if test "x${__opj_prefix}" = "x" ; then
if test "x$UP[_CFLAGS]" != "x"; then
CPPFLAGS="${CPPFLAGS} $UP[_CFLAGS]"
LDFLAGS="${LDFLAGS} $UP[_LIBS]"
else
CPPFLAGS="${CPPFLAGS} -I${__opj_prefix}/include"
LDFLAGS="${LDFLAGS} -L${__opj_prefix}/lib"
LIBS="${LIBS} -l${__opj_lib}"
if test "x${__opj_prefix}" != "x" ; then
__opj_CPPFLAGS="-I${__opj_prefix}/include"
else
__opj_CPPFLAGS=""
fi
CPPFLAGS="${CPPFLAGS} ${__opj_CPPFLAGS}"
fi
if test "x$UP[_LIBS]" != "x"; then
LIBS="${LIBS} $UP[_LIBS]"
else
if test "x${__opj_prefix}" != "x" ; then
__opj_LIBS="-L${__opj_prefix}/lib -l${__opj_lib}"
else
__opj_LIBS="-l${__opj_lib}"
fi
LIBS="${LIBS} ${__opj_LIBS}"
fi
AC_LINK_IFELSE(
@@ -45,7 +57,6 @@ ${__opj_func}();
[__opj_have_dep="no"])
CPPFLAGS=${save_CPPFLAGS}
LDFLAGS=${save_LDFLAGS}
LIBS=${save_LIBS}
if test "x${__opj_prefix}" = "x" ; then
@@ -55,12 +66,12 @@ else
fi
AC_MSG_RESULT([${__opj_have_dep}])
if test "x${__opj_have_dep}" = "xyes" && ! test "x${__opj_prefix}" = "x"; then
if test "x${__opj_have_dep}" = "xyes"; then
if test "x${UP[]_CFLAGS}" = "x" ; then
UP[]_CFLAGS="-I${__opj_prefix}/include"
UP[]_CFLAGS="${__opj_CPPFLAGS}"
fi
if test "x${UP[]_LIBS}" = "x" ; then
UP[]_LIBS="-L${__opj_prefix}/lib -l${__opj_lib}"
UP[]_LIBS="${__opj_LIBS}"
fi
fi

View File

@@ -19,6 +19,7 @@
#cmakedefine HAVE_LIBLCMS2
#cmakedefine HAVE_LCMS1_H
#cmakedefine HAVE_LCMS2_H
#cmakedefine USE_SYSTEM_GETOPT
/* Byte order. */
/* All compilers that support Mac OS X define either __BIG_ENDIAN__ or

View File

@@ -1,5 +1,5 @@
# Tests
INCLUDE_DIRECTORIES(
include_directories(
${OPENJPEG_SOURCE_DIR}/libopenjpeg
${OPENJPEG_SOURCE_DIR}/applications/codec
${OPENJPEG_SOURCE_DIR}/applications/common
@@ -9,49 +9,73 @@ INCLUDE_DIRECTORIES(
)
# First thing define the common source:
SET(comparePGXimages_SRCS comparePGXimages.c
set(compare_images_SRCS compare_images.c
${OPENJPEG_SOURCE_DIR}/applications/codec/convert.c
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
${OPENJPEG_SOURCE_DIR}/applications/codec/converttif.c
# ${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
SET(compare_dump_files_SRCS compare_dump_files.c
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c)
if(NOT USE_SYSTEM_GETOPT)
list(APPEND compare_images_SRCS
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
endif()
SET(compareRAWimages_SRCS compareRAWimages.c
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c)
set(compare_dump_files_SRCS compare_dump_files.c
#${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
ADD_EXECUTABLE(comparePGXimages ${comparePGXimages_SRCS})
TARGET_LINK_LIBRARIES(comparePGXimages
if(NOT USE_SYSTEM_GETOPT)
list(APPEND compare_dump_files_SRCS
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
endif()
set(compare_raw_files_SRCS compare_raw_files.c
#${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
if(NOT USE_SYSTEM_GETOPT)
list(APPEND compare_raw_files_SRCS
${OPENJPEG_SOURCE_DIR}/applications/common/opj_getopt.c
)
endif()
add_executable(compare_images ${compare_images_SRCS})
target_link_libraries(compare_images
${OPENJPEG_LIBRARY_NAME}
${PNG_LIBNAME} ${TIFF_LIBNAME}
)
# To support universal exe:
IF(ZLIB_FOUND AND APPLE)
TARGET_LINK_LIBRARIES(comparePGXimages z)
ELSe(ZLIB_FOUND AND APPLE)
TARGET_LINK_LIBRARIES(comparePGXimages ${Z_LIBNAME})
ENDIF(ZLIB_FOUND AND APPLE)
if(ZLIB_FOUND AND APPLE)
target_link_libraries(compare_images z)
else(ZLIB_FOUND AND APPLE)
target_link_libraries(compare_images ${Z_LIBNAME})
endif()
ADD_EXECUTABLE(compare_dump_files ${compare_dump_files_SRCS})
add_executable(compare_dump_files ${compare_dump_files_SRCS})
ADD_EXECUTABLE(compareRAWimages ${compareRAWimages_SRCS})
add_executable(compare_raw_files ${compare_raw_files_SRCS})
# No image send to the dashboard if lib PNG is not available.
IF(NOT HAVE_LIBPNG)
MESSAGE(WARNING "Lib PNG seems to be not available: if you want run the non-regression tests with images reported to the dashboard, you need it (try BUILD_THIRDPARTY)")
ENDIF(NOT HAVE_LIBPNG)
if(NOT HAVE_LIBPNG)
message(WARNING "Lib PNG seems to be not available: if you want run the non-regression tests with images reported to the dashboard, you need it (try BUILD_THIRDPARTY)")
endif()
ADD_SUBDIRECTORY(conformance)
ADD_SUBDIRECTORY(nonregression)
ADD_SUBDIRECTORY(unit)
add_subdirectory(conformance)
add_subdirectory(nonregression)
add_subdirectory(unit)
IF(BUILD_JPIP)
IF(JPIP_SERVER)
#SET(s "http://jpip.example.com/myFCGI?target=16.jp2&fsiz=170,170&cnew=http&type=jpp-stream")
SET(s "${JPIP_SERVER}?target=16.jp2&fsiz=170,170&cnew=http&type=jpp-stream")
SET(p "${CMAKE_CURRENT_BINARY_DIR}/jpip.dat")
SET(md5 "62b00c620fb0a600c5ffd413cada4674")
ADD_TEST(TestJPIP1 ${CMAKE_COMMAND} -DD_URL:STRING=${s} -DD_FILE:PATH=${p}
-DEXPECTED_MD5=${md5} -P ${PROJECT_SOURCE_DIR}/CMake/JPIPTestDriver.cmake)
ENDIF(JPIP_SERVER)
ENDIF(BUILD_JPIP)
if(BUILD_JPIP)
if(JPIP_SERVER)
#set(s "http://jpip.example.com/myFCGI?target=16.jp2&fsiz=170,170&cnew=http&type=jpp-stream")
set(s "${JPIP_SERVER}?target=16.jp2&fsiz=170,170&cnew=http&type=jpp-stream")
set(p "${CMAKE_CURRENT_BINARY_DIR}/jpip.dat")
set(md5 "d41d8cd98f00b204e9800998ecf8427e")
add_test(NAME TestJPIP1 COMMAND ${CMAKE_COMMAND} -DD_URL:STRING=${s} -DD_FILE:PATH=${p}
-DEXPECTED_MD5=${md5} -P ${PROJECT_SOURCE_DIR}/cmake/JPIPTestDriver.cmake)
endif()
endif()
add_executable(ppm2rgb3 ppm2rgb3.c)
#add_executable(pdf2jp2 pdf2jp2.c)

View File

@@ -1,236 +0,0 @@
/*
* Copyright (c) 2011, Mickael Savinaud, Communications & Systemes <mickael.savinaud@c-s.fr>
* 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.
*/
/*
* compareRAWimages.c
*
* Created on: 31 August 2011
* Author: mickael
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "opj_getopt.h"
void compareRAWimages_help_display(void);
typedef struct test_cmp_parameters
{
/** */
char* base_filename;
/** */
char* test_filename;
} test_cmp_parameters;
/*******************************************************************************
* Command line help function
*******************************************************************************/
void compareRAWimages_help_display(void) {
fprintf(stdout,"\nList of parameters for the comparePGX function \n");
fprintf(stdout,"\n");
fprintf(stdout," -b \t REQUIRED \t filename to the reference/baseline RAW image \n");
fprintf(stdout," -t \t REQUIRED \t filename to the test RAW image\n");
fprintf(stdout,"\n");
}
/*******************************************************************************
* Parse command line
*******************************************************************************/
int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
{
int sizemembasefile, sizememtestfile;
int index;
const char optlist[] = "b:t:";
int c;
/* Init parameters*/
param->base_filename = NULL;
param->test_filename = NULL;
opj_opterr = 0;
while ((c = opj_getopt(argc, argv, optlist)) != -1)
switch (c)
{
case 'b':
sizemembasefile = (int)strlen(opj_optarg)+1;
param->base_filename = (char*) malloc(sizemembasefile);
param->base_filename[0] = '\0';
strncpy(param->base_filename, opj_optarg, strlen(opj_optarg));
param->base_filename[strlen(opj_optarg)] = '\0';
/*printf("param->base_filename = %s [%d / %d]\n", param->base_filename, strlen(param->base_filename), sizemembasefile );*/
break;
case 't':
sizememtestfile = (int) strlen(opj_optarg) + 1;
param->test_filename = (char*) malloc(sizememtestfile);
param->test_filename[0] = '\0';
strncpy(param->test_filename, opj_optarg, strlen(opj_optarg));
param->test_filename[strlen(opj_optarg)] = '\0';
/*printf("param->test_filename = %s [%d / %d]\n", param->test_filename, strlen(param->test_filename), sizememtestfile);*/
break;
case '?':
if ((opj_optopt == 'b') || (opj_optopt == 't'))
fprintf(stderr, "Option -%c requires an argument.\n", opj_optopt);
else
if (isprint(opj_optopt)) fprintf(stderr, "Unknown option `-%c'.\n", opj_optopt);
else fprintf(stderr, "Unknown option character `\\x%x'.\n", opj_optopt);
return 1;
default:
fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c, opj_optarg);
break;
}
if (opj_optind != argc) {
for (index = opj_optind; index < argc; index++)
fprintf(stderr,"Non-option argument %s\n", argv[index]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/*******************************************************************************
* MAIN
*******************************************************************************/
int main(int argc, char **argv)
{
test_cmp_parameters inParam;
FILE *file_test=NULL, *file_base=NULL;
unsigned char equal = 1;
/* Get parameters from command line*/
if (parse_cmdline_cmp(argc, argv, &inParam) == EXIT_FAILURE)
{
compareRAWimages_help_display();
/* Free Memory */
if (inParam.base_filename){
free(inParam.base_filename);
inParam.base_filename = NULL;
}
if (inParam.test_filename){
free(inParam.test_filename);
inParam.test_filename = NULL;
}
return EXIT_FAILURE;
}
file_test = fopen(inParam.test_filename, "rb");
if (!file_test) {
fprintf(stderr, "Failed to open %s for reading !!\n", inParam.test_filename);
/* Free Memory */
if (inParam.base_filename){
free(inParam.base_filename);
inParam.base_filename = NULL;
}
if (inParam.test_filename){
free(inParam.test_filename);
inParam.test_filename = NULL;
}
return EXIT_FAILURE;
}
file_base = fopen(inParam.base_filename, "rb");
if (!file_base) {
fprintf(stderr, "Failed to open %s for reading !!\n", inParam.base_filename);
/* Free Memory */
if (inParam.base_filename){
free(inParam.base_filename);
inParam.base_filename = NULL;
}
if (inParam.test_filename){
free(inParam.test_filename);
inParam.test_filename = NULL;
}
fclose(file_test);
return EXIT_FAILURE;
}
/* Read simultaneously the two files*/
while (equal)
{
unsigned char value_test = 0;
unsigned char eof_test = 0;
unsigned char value_base = 0;
unsigned char eof_base = 0;
/* Read one byte*/
if (!fread(&value_test, 1, 1, file_test)) {
eof_test = 1;
}
/* Read one byte*/
if (!fread(&value_base, 1, 1, file_base)) {
eof_base = 1;;
}
/* End of file reached by the two files?*/
if (eof_test && eof_base)
break;
/* 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.\n");
equal = 0;
}
}
/* Free Memory */
if (inParam.base_filename){
free(inParam.base_filename);
inParam.base_filename = NULL;
}
if (inParam.test_filename){
free(inParam.test_filename);
inParam.test_filename = NULL;
}
fclose(file_test);
fclose(file_base);
if (equal)
{
fprintf(stdout,"---- TEST SUCCEED: Files are equal ----\n");
return EXIT_SUCCESS;
}
else
return EXIT_FAILURE;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Mickael Savinaud, Communications & Systemes <mickael.savinaud@c-s.fr>
* Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,13 +29,13 @@
*
* Created on: 25 juil. 2011
* Author: mickael
* BASELINE MUST BE GENERATED BY UNIX PLATFORM REGARDING TO THE CRLF PROBLEM
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "opj_getopt.h"
@@ -50,7 +50,7 @@ typedef struct test_cmp_parameters
/*******************************************************************************
* Command line help function
*******************************************************************************/
void compare_dump_files_help_display(void) {
static void compare_dump_files_help_display(void) {
fprintf(stdout,"\nList of parameters for the compare_dump_files function \n");
fprintf(stdout,"\n");
fprintf(stdout," -b \t REQUIRED \t filename to the reference/baseline dump file \n");
@@ -60,9 +60,9 @@ void compare_dump_files_help_display(void) {
/*******************************************************************************
* Parse command line
*******************************************************************************/
int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
static int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
{
int sizemembasefile, sizememtestfile;
size_t sizemembasefile, sizememtestfile;
int index;
const char optlist[] = "b:t:";
int c;
@@ -76,43 +76,40 @@ int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
while ((c = opj_getopt(argc, argv, optlist)) != -1)
switch (c)
{
case 'b':
sizemembasefile = (int)strlen(opj_optarg)+1;
param->base_filename = (char*) malloc(sizemembasefile);
param->base_filename[0] = '\0';
strncpy(param->base_filename, opj_optarg, strlen(opj_optarg));
param->base_filename[strlen(opj_optarg)] = '\0';
/*printf("param->base_filename = %s [%d / %d]\n", param->base_filename, strlen(param->base_filename), sizemembasefile );*/
break;
case 't':
sizememtestfile = (int) strlen(opj_optarg) + 1;
param->test_filename = (char*) malloc(sizememtestfile);
param->test_filename[0] = '\0';
strncpy(param->test_filename, opj_optarg, strlen(opj_optarg));
param->test_filename[strlen(opj_optarg)] = '\0';
/*printf("param->test_filename = %s [%d / %d]\n", param->test_filename, strlen(param->test_filename), sizememtestfile);*/
break;
case '?':
if ( (opj_optopt == 'b') || (opj_optopt == 't') )
fprintf(stderr, "Option -%c requires an argument.\n", opj_optopt);
else
if (isprint(opj_optopt)) fprintf(stderr, "Unknown option `-%c'.\n", opj_optopt);
else fprintf(stderr, "Unknown option character `\\x%x'.\n", opj_optopt);
return 1;
default:
fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c, opj_optarg);
break;
case 'b':
sizemembasefile = strlen(opj_optarg) + 1;
param->base_filename = (char*) malloc(sizemembasefile);
strcpy(param->base_filename, opj_optarg);
/*printf("param->base_filename = %s [%d / %d]\n", param->base_filename, strlen(param->base_filename), sizemembasefile );*/
break;
case 't':
sizememtestfile = strlen(opj_optarg) + 1;
param->test_filename = (char*) malloc(sizememtestfile);
strcpy(param->test_filename, opj_optarg);
/*printf("param->test_filename = %s [%d / %d]\n", param->test_filename, strlen(param->test_filename), sizememtestfile);*/
break;
case '?':
if ( (opj_optopt == 'b') || (opj_optopt == 't') )
fprintf(stderr, "Option -%c requires an argument.\n", opj_optopt);
else
if (isprint(opj_optopt)) fprintf(stderr, "Unknown option `-%c'.\n", opj_optopt);
else fprintf(stderr, "Unknown option character `\\x%x'.\n", opj_optopt);
return 1;
default:
fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c, opj_optarg);
break;
}
if (opj_optind != argc)
{
for (index = opj_optind; index < argc; index++)
fprintf(stderr,"Non-option argument %s\n", argv[index]);
return EXIT_FAILURE;
return 1;
}
return EXIT_SUCCESS;
return 0;
}
/*******************************************************************************
* MAIN
*******************************************************************************/
@@ -120,33 +117,30 @@ int main(int argc, char **argv)
{
test_cmp_parameters inParam;
FILE *fbase=NULL, *ftest=NULL;
int chbase, chtest;
int same = 1;
unsigned long l=1, pos;
int same = 0;
char lbase[256];
char strbase[256];
char ltest[256];
char strtest[256];
if( parse_cmdline_cmp(argc, argv, &inParam) == EXIT_FAILURE )
if( parse_cmdline_cmp(argc, argv, &inParam) == 1 )
{
compare_dump_files_help_display();
if (!inParam.base_filename) free(inParam.base_filename);
if (!inParam.test_filename) free(inParam.test_filename);
return EXIT_FAILURE;
goto cleanup;
}
/* Display Parameters*/
printf("******Parameters********* \n");
printf(" base_filename = %s\n"
" test_filename = %s\n",
inParam.base_filename, inParam.test_filename);
" test_filename = %s\n",
inParam.base_filename, inParam.test_filename);
printf("************************* \n");
/* open base file */
printf("Try to open: %s for reading ... ", inParam.base_filename);
if((fbase = fopen(inParam.base_filename, "rb"))==NULL)
{
printf("Failed.\n");
free(inParam.base_filename);
free(inParam.test_filename);
return EXIT_FAILURE;
goto cleanup;
}
printf("Ok.\n");
@@ -154,105 +148,37 @@ int main(int argc, char **argv)
printf("Try to open: %s for reading ... ", inParam.test_filename);
if((ftest = fopen(inParam.test_filename, "rb"))==NULL)
{
printf("Failed.\n");
fclose(fbase);
free(inParam.base_filename);
free(inParam.test_filename);
return EXIT_FAILURE;
goto cleanup;
}
printf("Ok.\n");
pos=ftell(fbase);
while(!feof(fbase))
while (fgets(lbase, sizeof(lbase), fbase) && fgets(ltest,sizeof(ltest),ftest))
{
chbase = fgetc(fbase);
if(ferror(fbase))
int nbase = sscanf(lbase, "%255[^\r\n]", strbase);
int ntest = sscanf(ltest, "%255[^\r\n]", strtest);
assert( nbase != 255 && ntest != 255 );
if( nbase != 1 || ntest != 1 )
{
printf("Error reading base file.\n");
return EXIT_FAILURE;
fprintf(stderr, "could not parse line from files\n" );
goto cleanup;
}
chtest = fgetc(ftest);
if(ferror(ftest))
if( strcmp( strbase, strtest ) != 0 )
{
printf("Error reading test file.\n");
return EXIT_FAILURE;
}
/* CRLF problem (Baseline must be always generated by unix platform)*/
if (chbase == '\n' && chtest == '\r')
if (fgetc(ftest) == '\n')
chtest = '\n';
if(chbase != chtest)
{
size_t nbytes = 2048;
int CRLF_shift=1;
char *strbase, *strtest, *strbase_d, *strtest_d;
printf("Files differ at line %lu:\n", l);
fseek(fbase,pos,SEEK_SET);
/* Take into account CRLF characters when we write \n into
// dump file when we used WIN platform*/
#ifdef _WIN32
CRLF_shift = 2;
fseek(ftest,pos + l - 1,SEEK_SET);
#else
fseek(ftest,pos,SEEK_SET);
#endif
strbase = (char *) malloc(nbytes + 1);
strtest = (char *) malloc(nbytes + 1);
if (fgets(strbase, nbytes, fbase) == NULL)
fprintf(stderr,"\nWARNING: fgets return a NULL value");
else
{
if (fgets(strtest, nbytes, ftest) == NULL)
fprintf(stderr,"\nWARNING: fgets return a NULL value");
else
{
strbase_d = (char *) malloc(strlen(strbase)+1);
strtest_d = (char *) malloc(strlen(strtest)+1);
strncpy(strbase_d, strbase, strlen(strbase)-1);
strncpy(strtest_d, strtest, strlen(strtest)-CRLF_shift);
strbase_d[strlen(strbase)-1] = '\0';
strtest_d[strlen(strtest)-CRLF_shift] = '\0';
printf("<%s> vs. <%s>\n", strbase_d, strtest_d);
free(strbase_d);free(strtest_d);
}
}
free(strbase);free(strtest);
same = 0;
break;
}
else
{
if (chbase == '\n')
{
l++;
pos = ftell(fbase);
}
fprintf(stderr,"<%s> vs. <%s>\n", strbase, strtest);
goto cleanup;
}
}
same = 1;
printf("\n***** TEST SUCCEED: Files are the same. *****\n");
cleanup:
/*Close File*/
fclose(fbase);
fclose(ftest);
if(fbase) fclose(fbase);
if(ftest) fclose(ftest);
/* Free memory*/
free(inParam.base_filename);
free(inParam.test_filename);
if(same)
{
printf("\n***** TEST SUCCEED: Files are the same. *****\n");
return EXIT_SUCCESS;
}
else return EXIT_FAILURE;
return same ? EXIT_SUCCESS : EXIT_FAILURE;
}

File diff suppressed because it is too large Load Diff

193
tests/compare_raw_files.c Normal file
View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
* 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.
*/
/*
* compare_raw_files.c
*
* Created on: 31 August 2011
* Author: mickael
*
* This is equivalent to the UNIX `cmp` command
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "opj_getopt.h"
typedef struct test_cmp_parameters
{
/** */
char* base_filename;
/** */
char* test_filename;
} test_cmp_parameters;
/*******************************************************************************
* Command line help function
*******************************************************************************/
static void compare_raw_files_help_display(void) {
fprintf(stdout,"\nList of parameters for the compare_raw_files function \n");
fprintf(stdout,"\n");
fprintf(stdout," -b \t REQUIRED \t filename to the reference/baseline RAW image \n");
fprintf(stdout," -t \t REQUIRED \t filename to the test RAW image\n");
fprintf(stdout,"\n");
}
/*******************************************************************************
* Parse command line
*******************************************************************************/
static int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
{
size_t sizemembasefile, sizememtestfile;
int index;
const char optlist[] = "b:t:";
int c;
/* Init parameters*/
param->base_filename = NULL;
param->test_filename = NULL;
opj_opterr = 0;
while ((c = opj_getopt(argc, argv, optlist)) != -1)
switch (c)
{
case 'b':
sizemembasefile = strlen(opj_optarg)+1;
free(param->base_filename); /* handle dup option */
param->base_filename = (char*) malloc(sizemembasefile);
strcpy(param->base_filename, opj_optarg);
/*printf("param->base_filename = %s [%d / %d]\n", param->base_filename, strlen(param->base_filename), sizemembasefile );*/
break;
case 't':
sizememtestfile = strlen(opj_optarg) + 1;
free(param->test_filename); /* handle dup option */
param->test_filename = (char*) malloc(sizememtestfile);
strcpy(param->test_filename, opj_optarg);
/*printf("param->test_filename = %s [%d / %d]\n", param->test_filename, strlen(param->test_filename), sizememtestfile);*/
break;
case '?':
if ((opj_optopt == 'b') || (opj_optopt == 't'))
fprintf(stderr, "Option -%c requires an argument.\n", opj_optopt);
else
if (isprint(opj_optopt)) fprintf(stderr, "Unknown option `-%c'.\n", opj_optopt);
else fprintf(stderr, "Unknown option character `\\x%x'.\n", opj_optopt);
return 1;
default:
fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c, opj_optarg);
break;
}
if (opj_optind != argc) {
for (index = opj_optind; index < argc; index++)
fprintf(stderr,"Non-option argument %s\n", argv[index]);
return 1;
}
return 0;
}
/*******************************************************************************
* MAIN
*******************************************************************************/
int main(int argc, char **argv)
{
int pos = 0;
test_cmp_parameters inParam;
FILE *file_test=NULL, *file_base=NULL;
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) {
fprintf(stderr, "Failed to open %s for reading !!\n", inParam.test_filename);
goto cleanup;
}
file_base = fopen(inParam.base_filename, "rb");
if (!file_base) {
fprintf(stderr, "Failed to open %s for reading !!\n", inParam.base_filename);
goto cleanup;
}
/* Read simultaneously the two files*/
equal = 1U;
while (equal)
{
unsigned char value_test = 0;
unsigned char eof_test = 0;
unsigned char value_base = 0;
unsigned char eof_base = 0;
/* Read one byte*/
if (!fread(&value_test, 1, 1, file_test)) {
eof_test = 1;
}
/* Read one byte*/
if (!fread(&value_base, 1, 1, file_base)) {
eof_base = 1;
}
/* End of file reached by the two files?*/
if (eof_test && eof_base)
break;
/* 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++;
}
if(equal) fprintf(stdout,"---- TEST SUCCEED: Files are equal ----\n");
cleanup:
if(file_test) fclose(file_test);
if(file_base) fclose(file_base);
/* Free Memory */
free(inParam.base_filename);
free(inParam.test_filename);
return equal ? EXIT_SUCCESS : EXIT_FAILURE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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)
@@ -8,19 +10,130 @@ SET(INPUT_NR ${OPJ_DATA_ROOT}/input/nonregression)
SET(INPUT_NR_PATH ${INPUT_NR})
SET(TEMP_PATH ${TEMP})
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
# GENERATION OF THE TEST SUITE (DUMP)
# Dump all files with the selected extension inside the input directory
# technically j2k_dump should simply parse these one, since syntax is ok.
set(BLACKLIST_JPEG2000_TMP
2539.pdf.SIGFPE.706.1712.jp2
0290cb77c5df21828fa74cf2ab2c84d8.SIGFPE.d25.31.jp2
26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2
4035.pdf.SIGSEGV.d8b.3375.jp2
3635.pdf.asan.77.2930.jp2
issue165.jp2
#edf_c2_1103421.jp2
edf_c2_1178956.jp2
edf_c2_1000290.jp2
#edf_c2_1000691.jp2 # ok
#edf_c2_20.jp2 #looks ok as per kdu_jp2info
edf_c2_1377017.jp2
edf_c2_1002767.jp2
#edf_c2_10025.jp2
edf_c2_1000234.jp2
edf_c2_225881.jp2
edf_c2_1000671.jp2
#edf_c2_1013627.jp2 # weird box, but kdu_jp2info ok
edf_c2_1015644.jp2
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}
broken1.jp2
broken2.jp2
broken3.jp2
broken4.jp2
gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2
gdal_fuzzer_check_comp_dx_dy.jp2
gdal_fuzzer_check_number_of_tiles.jp2
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
"${INPUT_NR}/*.j2k"
"${INPUT_NR}/*.j2c"
"${INPUT_NR}/*.jp2"
"${INPUT_NR}/*.jpc"
#"${INPUT_NR}/*.jpx"
)
foreach(INPUT_FILENAME ${OPJ_DATA_NR_LIST})
get_filename_component(INPUT_FILENAME_NAME ${INPUT_FILENAME} NAME)
#get_filename_component(INPUT_FILENAME_NAME_WE ${INPUT_FILENAME_NAME} NAME_WE)
# cannot use longest extension function, since some name contains multiples
# dots. Instead write out own shortest extension function:
string(FIND ${INPUT_FILENAME_NAME} "." SHORTEST_EXT_POS REVERSE)
string(SUBSTRING ${INPUT_FILENAME_NAME} 0 ${SHORTEST_EXT_POS} INPUT_FILENAME_NAME_WE)
string(REGEX MATCH ${INPUT_FILENAME_NAME} bad_jpeg2000 ${BLACKLIST_JPEG2000})
# Dump the input image
add_test(NAME NR-${INPUT_FILENAME_NAME}-dump
COMMAND j2k_dump
-i ${INPUT_FILENAME}
-o ${TEMP}/${INPUT_FILENAME_NAME}.txt
)
if(bad_jpeg2000)
set_tests_properties(NR-${INPUT_FILENAME_NAME}-dump
PROPERTIES WILL_FAIL TRUE)
else()
# Compare the dump output with the baseline
add_test(NAME NR-${INPUT_FILENAME_NAME}-compare_dump2base
COMMAND compare_dump_files
-b ${BASELINE_NR}/opj_${INPUT_FILENAME_NAME_WE}.txt
-t ${TEMP}/${INPUT_FILENAME_NAME}.txt
)
set_tests_properties(NR-${INPUT_FILENAME_NAME}-compare_dump2base
PROPERTIES DEPENDS
NR-${INPUT_FILENAME_NAME}-dump)
endif()
endforeach()
#########################################################################
# GENERATION OF THE TEST SUITE (DECODE AND ENCODE)
# Read one and more input file(s) (located in ${OPJ_DATA_ROOT}/input/nonregression)
# to know which files processed and with which options.
# Configure the test suite file:
CONFIGURE_FILE("test_suite.ctest.in"
"${CMAKE_CURRENT_BINARY_DIR}/test_suite.ctest"
@ONLY)
"${CMAKE_CURRENT_BINARY_DIR}/test_suite.ctest"
@ONLY)
# Read the file into a list
FILE(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/test_suite.ctest OPJ_TEST_CMD_LINE_LIST)
@@ -32,14 +145,15 @@ IF (TEST_SUITE_FILES)
# Avoid to process the official test suite
SET(FILE_ALREADY_READ 0)
STRING(REGEX MATCH "test_suite.ctest.in$" FILE_ALREADY_READ ${TEST_SUITE_FILE})
get_filename_component(TEST_SUITE_FILENAME ${TEST_SUITE_FILE} NAME)
string(REGEX MATCH "^test_suite.ctest.in$" FILE_ALREADY_READ ${TEST_SUITE_FILENAME})
IF(NOT FILE_ALREADY_READ)
# Configure the additional test suite file:
GET_FILENAME_COMPONENT(TEST_SUITE_FILE_SUB ${TEST_SUITE_FILE} NAME_WE)
CONFIGURE_FILE("${TEST_SUITE_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/${TEST_SUITE_FILE_SUB}.ctest"
@ONLY)
"${CMAKE_CURRENT_BINARY_DIR}/${TEST_SUITE_FILE_SUB}.ctest"
@ONLY)
# Read the additional file into a list
FILE(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/${TEST_SUITE_FILE_SUB}.ctest OPJ_TEST_CMD_LINE_LIST_TEMP)
# Append the list of command
@@ -56,6 +170,7 @@ ELSE(TEST_SUITE_FILES)
ENDIF(TEST_SUITE_FILES)
set(nonregression_filenames_used)
# Parse the command line found in the file(s)
SET(IT_TEST_ENC 0)
SET(IT_TEST_DEC 0)
@@ -68,9 +183,12 @@ FOREACH(OPJ_TEST_CMD_LINE ${OPJ_TEST_CMD_LINE_LIST})
# Check if the first argument begin by the comment sign
LIST(GET CMD_ARG_LIST 0 EXE_NAME)
STRING(REGEX MATCH "^#" IGNORE_LINE_FOUND ${EXE_NAME})
IF(IGNORE_LINE_FOUND)
if(EXE_NAME)
STRING(REGEX MATCH "^#" IGNORE_LINE_FOUND ${EXE_NAME})
endif()
IF(IGNORE_LINE_FOUND OR NOT EXE_NAME)
#MESSAGE( STATUS "Current line is ignored: ${OPJ_TEST_CMD_LINE}")
@@ -163,120 +281,164 @@ FOREACH(OPJ_TEST_CMD_LINE ${OPJ_TEST_CMD_LINE_LIST})
# ENCODER TEST SUITE
IF(ENC_TEST_FOUND)
math(EXPR IT_TEST_ENC "${IT_TEST_ENC}+1" )
math(EXPR IT_TEST_ENC "${IT_TEST_ENC}+1" )
# Encode an image into the jpeg2000 format
ADD_TEST(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode
${EXECUTABLE_OUTPUT_PATH}/image_to_j2k
${CMD_ARG_LIST_2}
# Encode an image into the jpeg2000 format
ADD_TEST(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode
COMMAND image_to_j2k
${CMD_ARG_LIST_2}
)
IF(FAILED_TEST_FOUND)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode PROPERTIES WILL_FAIL TRUE)
ELSE(FAILED_TEST_FOUND)
IF(FAILED_TEST_FOUND)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode PROPERTIES WILL_FAIL TRUE)
ELSE(FAILED_TEST_FOUND)
# Dump the encoding file
ADD_TEST(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump
${EXECUTABLE_OUTPUT_PATH}/j2k_dump
# Dump the encoding file
ADD_TEST(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump
COMMAND j2k_dump
-i ${OUTPUT_FILENAME}
-o ${OUTPUT_FILENAME}-ENC-${IT_TEST_ENC}.txt
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode)
# Compare the dump file with the baseline
ADD_TEST(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dump2base
COMMAND compare_dump_files
-b ${BASELINE_NR}/opj_${OUTPUT_FILENAME_NAME_WE}-ENC-${IT_TEST_ENC}.txt
-t ${OUTPUT_FILENAME}-ENC-${IT_TEST_ENC}.txt
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dump2base
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump)
# Decode the encoding file with kakadu expand command
IF (KDU_EXPAND_EXECUTABLE)
ADD_TEST(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref
COMMAND ${KDU_EXPAND_EXECUTABLE}
-i ${OUTPUT_FILENAME}
-o ${OUTPUT_FILENAME}-ENC-${IT_TEST_ENC}.txt
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode)
# Compare the dump file with the baseline
ADD_TEST(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dump2base
${EXECUTABLE_OUTPUT_PATH}/compare_dump_files
-b ${BASELINE_NR}/opj_${OUTPUT_FILENAME_NAME_WE}-ENC-${IT_TEST_ENC}.txt
-t ${OUTPUT_FILENAME}-ENC-${IT_TEST_ENC}.txt
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dump2base
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-dump)
# Decode the encoding file with kakadu expand command
IF (KDU_EXPAND_EXECUTABLE)
ADD_TEST(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref
${KDU_EXPAND_EXECUTABLE}
-i ${OUTPUT_FILENAME}
-o ${OUTPUT_FILENAME}.raw
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode)
# Compare the decoding file with baseline generated from the kdu_expand and baseline.j2k
ADD_TEST(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dec-ref-out2base
${EXECUTABLE_OUTPUT_PATH}/compareRAWimages
-b ${BASELINE_NR}/opj_${OUTPUT_FILENAME_NAME_WE}-ENC-${IT_TEST_ENC}.raw
-t ${OUTPUT_FILENAME}.raw
-o ${OUTPUT_FILENAME}.raw
)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dec-ref-out2base
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref)
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-decode-ref
PROPERTIES DEPENDS
NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-encode)
ENDIF()
ENDIF(FAILED_TEST_FOUND)
# Compare the decoding file with baseline generated from the kdu_expand and baseline.j2k
ADD_TEST(NAME NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dec-ref-out2base
COMMAND compare_raw_files
-b ${BASELINE_NR}/opj_${OUTPUT_FILENAME_NAME_WE}-ENC-${IT_TEST_ENC}.raw
-t ${OUTPUT_FILENAME}.raw
)
# DECODER TEST SUITE
SET_TESTS_PROPERTIES(NR-ENC-${INPUT_FILENAME_NAME}-${IT_TEST_ENC}-compare_dec-ref-out2base
PROPERTIES DEPENDS
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 "<isValidJP2>True</isValidJP2>"
)
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 j2k_to_image -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
ELSE(ENC_TEST_FOUND)
string(FIND ${INPUT_FILENAME} "nonregression" nr_pos)
if(${nr_pos} GREATER 0)
list(APPEND nonregression_filenames_used ${INPUT_FILENAME_NAME})
endif()
math(EXPR IT_TEST_DEC "${IT_TEST_DEC}+1" )
# Decode the input image
ADD_TEST(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode
${EXECUTABLE_OUTPUT_PATH}/j2k_to_image
ADD_TEST(NAME NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode
COMMAND j2k_to_image
${CMD_ARG_LIST_2}
)
)
IF(FAILED_TEST_FOUND)
SET_TESTS_PROPERTIES(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode PROPERTIES WILL_FAIL TRUE)
ELSE(FAILED_TEST_FOUND)
# if not failed, check against registered md5:
add_test(NAME NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode-md5 COMMAND ${CMAKE_COMMAND}
-DREFFILE:STRING=${CMAKE_CURRENT_SOURCE_DIR}/md5refs.txt
-DOUTFILENAME:STRING=${OUTPUT_FILENAME}
-P ${CMAKE_CURRENT_SOURCE_DIR}/checkmd5refs.cmake)
# FIXME: add a compare2base function base on raw which
# can output png diff files if necesary
# ADD_TEST(NR-${filename}-compare2base
# ${EXECUTABLE_OUTPUT_PATH}/comparePGXimages
# -b ${BASELINE_NR}/opj_${filenameRef}
# -t ${TEMP}/${filename}.pgx
# -n ${nbComponents}
# -d
# -s b_t_
# )
set_tests_properties(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode-md5
PROPERTIES DEPENDS NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-decode
)
# FIXME: add a compare2base function base on raw which
# can output png diff files if necesary
# add_test(NR-${filename}-compare2base
# ${EXECUTABLE_OUTPUT_PATH}/compare_images
# -b ${BASELINE_NR}/opj_${filenameRef}
# -t ${TEMP}/${filename}.pgx
# -n ${nbComponents}
# -d
# -s b_t_
# )
#
# SET_TESTS_PROPERTIES(NR-${filename}-compare2base
# PROPERTIES DEPENDS
# NR-${filename}-decode)
# PROPERTIES DEPENDS
# NR-${filename}-decode)
# Dump the input image
ADD_TEST(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-dump
${EXECUTABLE_OUTPUT_PATH}/j2k_dump
-i ${INPUT_FILENAME}
-o ${TEMP}/${INPUT_FILENAME_NAME}.txt
)
ENDIF()
# Compare the dump output with the baseline
ADD_TEST(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-compare_dump2base
${EXECUTABLE_OUTPUT_PATH}/compare_dump_files
-b ${BASELINE_NR}/opj_${INPUT_FILENAME_NAME_WE}.txt
-t ${TEMP}/${INPUT_FILENAME_NAME}.txt
)
ENDIF()
SET_TESTS_PROPERTIES(NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-compare_dump2base
PROPERTIES DEPENDS
NR-DEC-${INPUT_FILENAME_NAME}-${IT_TEST_DEC}-dump)
ENDIF()
ENDFOREACH()
ENDIF(FAILED_TEST_FOUND)
ENDIF(ENC_TEST_FOUND)
ENDIF(IGNORE_LINE_FOUND)
ENDFOREACH(OPJ_TEST_CMD_LINE)
set(existing_filenames)
foreach(f ${OPJ_DATA_NR_LIST})
get_filename_component(ff ${f} NAME)
list(APPEND existing_filenames ${ff})
endforeach()
if(existing_filenames)
list(REMOVE_ITEM existing_filenames ${nonregression_filenames_used})
endif()
# keep track of new addition:
# if we reach here, then a J2K files was added but no test is present in
# test_suite.ctest.in:
foreach(found_but_no_test ${existing_filenames})
add_test(NAME Found-But-No-Test-${found_but_no_test} COMMAND ${CMAKE_COMMAND} -E echo "${found_but_no_test}")
set_tests_properties(Found-But-No-Test-${found_but_no_test} PROPERTIES WILL_FAIL TRUE)
endforeach()

View File

@@ -0,0 +1,56 @@
# Copyright (c) 2014 Mathieu Malaterre <mathieu.malaterre@voxxl.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# check md5 refs
#
# This script will be used to make sure we never introduce a regression on any
# of the nonregression file.
#
# The approach is relatively simple, we compute a md5sum for each of the decode
# file. Anytime the md5sum is different from the reference one, we assume
# something went wrong and simply fails. of course if could happen during the
# course of openjpeg development that the internals are changed that impact the
# decoding process that the output would be bitwise different (while PSNR would
# be kept identical).
# Another more conventional approach is to store the generated output from
# openjpeg however storing the full generated output is generally useless since
# we do not really care about the exact pixel value, we simply need to known
# when a code change impact output generation. furthermore storing the
# complete generated output file, tends to make the svn:/openjpeg-data really
# big.
# This script expect two inputs
# REFFILE: Path to the md5sum.txt file
# OUTFILENAME: The name of the generated file we want to check The script will
# check whether a PGX or a PNG file was generated in the test suite (computed
# from OUTFILENAME)
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" "Temporary/${OUTFILENAME_NAME_WE}*.tif")
if(NOT globfiles)
message(SEND_ERROR "Could not find output PGX files: ${OUTFILENAME_NAME_WE}")
endif()
# REFFILE follow what `md5sum -c` would expect as input:
file(READ ${REFFILE} variable)
foreach(pgxfullpath ${globfiles})
file(MD5 ${pgxfullpath} output)
get_filename_component(pgxfile ${pgxfullpath} NAME)
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}]")
else()
message(SEND_ERROR "not equal: [${output_var}] vs [${output}]")
endif()
endforeach()

View File

@@ -0,0 +1,277 @@
6f22c9a9bd474202ac6cd3a066e15200 _00042.j2k_0.pgx
a3a0606dfa0779d657c6a923b90e4678 _00042.j2k_1.pgx
106954dc468dfe0884d02268e91f9f5b _00042.j2k_2.pgx
8889def55f1e18dae6002b9b3a6dd152 123.j2c_0.pgx
4a0daf7a9065101379eaebc28e436b1e Bretagne2.j2k_0.pgx
07578fc7bf81d3da694de8ae27308b82 Bretagne2.j2k_1.pgx
3690c42f83bad42f4abea48525d45e0e Bretagne2.j2k_2.pgx
8889def55f1e18dae6002b9b3a6dd152 bug.j2c_0.pgx
22c8d33a956ba83079d1102457bc77a1 buxI.j2k_0.pgx
b8f473c07ba5ebfc195bdd53c3b3b97f buxR.j2k_0.pgx
05c062aca83d13b8095460f38a690a08 Cannotreaddatawithnosizeknown.j2k_0.pgx
6276da0ec5fac44d683d3468b290331d cthead1.j2k_0.pgx
8afcac9a696cc8d753b0eb9f4ae692ff CT_Phillips_JPEG2K_Decompr_Problem.j2k_0.pgx
04d35ab6160c9029549f72358df984da file409752.jp2_0.pgx
2813bd6fdc2c306b91b3da3688b8bf49 file409752.jp2_1.pgx
e273e2aaea4a4fc1b2cf7c09c53c3cc6 file409752.jp2_2.pgx
05c062aca83d13b8095460f38a690a08 illegalcolortransform.j2k_0.pgx
cb28787aa7c223f03e6acad71e244108 issue104_jpxstream.jp2_0.pgx
cb28787aa7c223f03e6acad71e244108 issue104_jpxstream.jp2_1.pgx
cb28787aa7c223f03e6acad71e244108 issue104_jpxstream.jp2_2.pgx
c74edbb49e132b2cfc1eaf7908197b17 issue134.jp2_0.pgx
16fe8ed450da10a6aaae4cf6f467fc21 issue134.jp2_1.pgx
c6091c07bf0ff221008dfb60d893cdff issue134.jp2_2.pgx
cccccccccccccccccccccccccccccccc issue135.j2k_0.pgx
cccccccccccccccccccccccccccccccc issue135.j2k_1.pgx
cccccccccccccccccccccccccccccccc issue135.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
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
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
66b60e866991e03f9a2de18e80d3102b kakadu_v4-4_openjpegv2_broken.j2k_0.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
29131264861b4ee21011149b27e4d488 mem-b2ace68c-1381.jp2_0.pgx
29131264861b4ee21011149b27e4d488 mem-b2ace68c-1381.jp2_1.pgx
29131264861b4ee21011149b27e4d488 mem-b2ace68c-1381.jp2_2.pgx
df568fe0529219cc2c8f215e236f4b3d mem-b2ace68c-1381.jp2_3.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_0.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_1.pgx
41ec1a0228c703b10f95388c1160753b mem-b2b86b74-2753.jp2_2.pgx
97557ab9e38a7aff621e583fbb66b099 merged.jp2_0.pgx
386fbdcd294429733e3272d62ed5a15a merged.jp2_1.pgx
d3907bbd67be1dae31b4377fa4dc0373 merged.jp2_2.pgx
de8bba9ac366eeb2f170f0cf3605cf12 movie_00000.j2k_0.pgx
334bac3285f7138e9dd29d59bdcb22ff movie_00000.j2k_1.pgx
5511d2c96d1d1f2062491e00d5234506 movie_00000.j2k_2.pgx
de8bba9ac366eeb2f170f0cf3605cf12 movie_00001.j2k_0.pgx
334bac3285f7138e9dd29d59bdcb22ff movie_00001.j2k_1.pgx
5511d2c96d1d1f2062491e00d5234506 movie_00001.j2k_2.pgx
de8bba9ac366eeb2f170f0cf3605cf12 movie_00002.j2k_0.pgx
334bac3285f7138e9dd29d59bdcb22ff movie_00002.j2k_1.pgx
5511d2c96d1d1f2062491e00d5234506 movie_00002.j2k_2.pgx
951a55623a92e97a064a350f11c2637d orb-blue10-lin-j2k.j2k_0.pgx
5033aaf699dfa3dfe041af33c9ad688d orb-blue10-lin-j2k.j2k_1.pgx
dbe33d72484caedf9c2cc18fd670884c orb-blue10-lin-j2k.j2k_2.pgx
0fec67d9546171699958c6682e725b79 orb-blue10-lin-j2k.j2k_3.pgx
84462261381b6732ec4f2addb0070d24 orb-blue10-lin-jp2.jp2_0.pgx
6129edf57e5db2344fcde5ce99ae8732 orb-blue10-lin-jp2.jp2_1.pgx
fdad26b1e078aa32bd4b77a5f44da43c orb-blue10-lin-jp2.jp2_2.pgx
0fec67d9546171699958c6682e725b79 orb-blue10-lin-jp2.jp2_3.pgx
671feee525e2485060536edbf21380f1 orb-blue10-win-j2k.j2k_0.pgx
912cdee24dd360b7999f7ee4a51083b4 orb-blue10-win-j2k.j2k_1.pgx
64833b4b7557936b9233087e92f8ae28 orb-blue10-win-j2k.j2k_2.pgx
789a299a1523b2d9d3f561d12a2da817 orb-blue10-win-j2k.j2k_3.pgx
671feee525e2485060536edbf21380f1 orb-blue10-win-jp2.jp2_0.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
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
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

View File

@@ -29,18 +29,129 @@ image_to_j2k -i @INPUT_NR_PATH@/Bretagne2.ppm -o @TEMP_PATH@/Bretagne2_4.j2k -d
image_to_j2k -i @INPUT_NR_PATH@/Cevennes1.bmp -o @TEMP_PATH@/Cevennes1.j2k -r 10
image_to_j2k -i @INPUT_NR_PATH@/Cevennes2.ppm -o @TEMP_PATH@/Cevennes2.jp2 -r 50
image_to_j2k -i @INPUT_NR_PATH@/Rome.bmp -o @TEMP_PATH@/Rome.jp2 -q 30,35,50 -p LRCP -n 3
image_to_j2k -i @INPUT_NR_PATH@/X_4_2K_24_185_CBR_WB_000.tif -o @TEMP_PATH@/X_4_2K_24_185_CBR_WB_000.j2k -cinema2K 24
image_to_j2k -i @INPUT_NR_PATH@/X_5_2K_24_235_CBR_STEM24_000.tif -o @TEMP_PATH@/X_5_2K_24_235_CBR_STEM24_000.j2k -cinema2K 24
image_to_j2k -i @INPUT_NR_PATH@/X_6_2K_24_FULL_CBR_CIRCLE_000.tif -o @TEMP_PATH@/X_6_2K_24_FULL_CBR_CIRCLE_000.j2k -cinema2K 24
# related to issue 5
image_to_j2k -i @INPUT_NR_PATH@/random-issue-0005.tif -o @TEMP_PATH@/random-issue-0005.tif.j2k
# related to issue 62
image_to_j2k -i @INPUT_NR_PATH@/tmp-issue-0062.raw -o @TEMP_PATH@/tmp-issue-0062-u.raw.j2k -F 512,512,1,16,u
image_to_j2k -i @INPUT_NR_PATH@/tmp-issue-0062.raw -o @TEMP_PATH@/tmp-issue-0062-s.raw.j2k -F 512,512,1,16,s
image_to_j2k -i @INPUT_NR_PATH@/X_4_2K_24_185_CBR_WB_000.tif -o @TEMP_PATH@/X_4_2K_24_185_CBR_WB_000_C2K_24.j2k -cinema2K 24
image_to_j2k -i @INPUT_NR_PATH@/X_5_2K_24_235_CBR_STEM24_000.tif -o @TEMP_PATH@/X_5_2K_24_235_CBR_STEM24_000_C2K_24.j2k -cinema2K 24
image_to_j2k -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_24.j2k -cinema2K 24
image_to_j2k -i @INPUT_NR_PATH@/X_4_2K_24_185_CBR_WB_000.tif -o @TEMP_PATH@/X_4_2K_24_185_CBR_WB_000_C2K_48.j2k -cinema2K 48
image_to_j2k -i @INPUT_NR_PATH@/X_5_2K_24_235_CBR_STEM24_000.tif -o @TEMP_PATH@/X_5_2K_24_235_CBR_STEM24_000_C2K_48.j2k -cinema2K 48
image_to_j2k -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
#not implemented in 1.5
!image_to_j2k -i @INPUT_NR_PATH@/ElephantDream_4K.tif -o @TEMP_PATH@/ElephantDream_4K_C4K.j2k -cinema4K
# issue 141
image_to_j2k -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141.rawl.j2k -F 2048,32,1,16,u
image_to_j2k -i @INPUT_NR_PATH@/issue141.rawl -o @TEMP_PATH@/issue141-I.rawl.j2k -F 2048,32,1,16,u -I
# issue 46:
image_to_j2k -i @INPUT_NR_PATH@/Bretagne2.ppm -o @TEMP_PATH@/Bretagne2_5.j2k -c [64,64]
# issue 316
image_to_j2k -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
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn6a08.png -o @TEMP_PATH@/basn6a08.png.jp2 -n 6
# issue 322 limited tif support
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-01.tif -o @TEMP_PATH@/flower-minisblack-01.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-02.tif -o @TEMP_PATH@/flower-minisblack-02.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-04.tif -o @TEMP_PATH@/flower-minisblack-04.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-06.tif -o @TEMP_PATH@/flower-minisblack-06.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-08.tif -o @TEMP_PATH@/flower-minisblack-08.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-10.tif -o @TEMP_PATH@/flower-minisblack-10.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-12.tif -o @TEMP_PATH@/flower-minisblack-12.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-14.tif -o @TEMP_PATH@/flower-minisblack-14.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-minisblack-16.tif -o @TEMP_PATH@/flower-minisblack-16.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-02.tif -o @TEMP_PATH@/flower-rgb-contig-02.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-04.tif -o @TEMP_PATH@/flower-rgb-contig-04.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-08.tif -o @TEMP_PATH@/flower-rgb-contig-08.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-10.tif -o @TEMP_PATH@/flower-rgb-contig-10.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-12.tif -o @TEMP_PATH@/flower-rgb-contig-12.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-14.tif -o @TEMP_PATH@/flower-rgb-contig-14.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-contig-16.tif -o @TEMP_PATH@/flower-rgb-contig-16.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-02.tif -o @TEMP_PATH@/flower-rgb-planar-02.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-04.tif -o @TEMP_PATH@/flower-rgb-planar-04.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-08.tif -o @TEMP_PATH@/flower-rgb-planar-08.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-10.tif -o @TEMP_PATH@/flower-rgb-planar-10.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-12.tif -o @TEMP_PATH@/flower-rgb-planar-12.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-14.tif -o @TEMP_PATH@/flower-rgb-planar-14.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/flower-rgb-planar-16.tif -o @TEMP_PATH@/flower-rgb-planar-16.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/basn6a08.tif -o @TEMP_PATH@/basn6a08.tif.jp2
image_to_j2k -i @INPUT_NR_PATH@/basn4a08.tif -o @TEMP_PATH@/basn4a08.tif.jp2
# issue 203 BMP Files not handled properly
image_to_j2k -i @INPUT_NR_PATH@/issue203-8bpp-width1.bmp -o @TEMP_PATH@/issue203-8bpp-width1.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-rle8.bmp -o @TEMP_PATH@/issue203-rle8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-y8.bmp -o @TEMP_PATH@/issue203-32x32-y8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-33x33-y8.bmp -o @TEMP_PATH@/issue203-33x33-y8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-34x34-y8.bmp -o @TEMP_PATH@/issue203-34x34-y8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-35x35-y8.bmp -o @TEMP_PATH@/issue203-35x35-y8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgr.bmp -o @TEMP_PATH@/issue203-32x32-bgr.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-33x33-bgr.bmp -o @TEMP_PATH@/issue203-33x33-bgr.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-34x34-bgr.bmp -o @TEMP_PATH@/issue203-34x34-bgr.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-35x35-bgr.bmp -o @TEMP_PATH@/issue203-35x35-bgr.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-y-rle8.bmp -o @TEMP_PATH@/issue203-32x32-y-rle8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgr-rle8.bmp -o @TEMP_PATH@/issue203-32x32-bgr-rle8.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-y-rle4.bmp -o @TEMP_PATH@/issue203-32x32-y-rle4.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgr-rle4.bmp -o @TEMP_PATH@/issue203-32x32-bgr-rle4.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgra.bmp -o @TEMP_PATH@/issue203-32x32-bgra.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgrx.bmp -o @TEMP_PATH@/issue203-32x32-bgrx.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgr16.bmp -o @TEMP_PATH@/issue203-32x32-bgr16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-33x33-bgr16.bmp -o @TEMP_PATH@/issue203-33x33-bgr16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgra16.bmp -o @TEMP_PATH@/issue203-32x32-bgra16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-33x33-bgra16.bmp -o @TEMP_PATH@/issue203-33x33-bgra16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-32x32-bgrx16.bmp -o @TEMP_PATH@/issue203-32x32-bgrx16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-33x33-bgrx16.bmp -o @TEMP_PATH@/issue203-33x33-bgrx16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-127x64-bgr16.bmp -o @TEMP_PATH@/issue203-127x64-bgr16.bmp.jp2
image_to_j2k -i @INPUT_NR_PATH@/issue203-127x64-bgrx.bmp -o @TEMP_PATH@/issue203-127x64-bgrx.bmp.jp2
# issue 571 Lossless is not lossless on linux x86
image_to_j2k -i @INPUT_NR_PATH@/issue571.tif -o @TEMP_PATH@/issue571.tif.j2k
# issue 536 (PNG images are always read as RGB(A) images) + issue 264 (convert.c is unmaintainable)
# Test all images from pngsuite
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn0g01.png -o @TEMP_PATH@/basn0g01.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn0g02.png -o @TEMP_PATH@/basn0g02.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn0g04.png -o @TEMP_PATH@/basn0g04.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn0g08.png -o @TEMP_PATH@/basn0g08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn0g16.png -o @TEMP_PATH@/basn0g16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn2c08.png -o @TEMP_PATH@/basn2c08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn2c16.png -o @TEMP_PATH@/basn2c16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn3p01.png -o @TEMP_PATH@/basn3p01.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn3p02.png -o @TEMP_PATH@/basn3p02.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn3p04.png -o @TEMP_PATH@/basn3p04.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn3p08.png -o @TEMP_PATH@/basn3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn4a08.png -o @TEMP_PATH@/basn4a08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn4a16.png -o @TEMP_PATH@/basn4a16.png.jp2
# already done image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn6a08.png -o @TEMP_PATH@/basn6a08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/basn6a16.png -o @TEMP_PATH@/basn6a16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbbn0g01.png -o @TEMP_PATH@/ftbbn0g01.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbbn0g02.png -o @TEMP_PATH@/ftbbn0g02.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbbn0g04.png -o @TEMP_PATH@/ftbbn0g04.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbbn2c16.png -o @TEMP_PATH@/ftbbn2c16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbbn3p08.png -o @TEMP_PATH@/ftbbn3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbgn2c16.png -o @TEMP_PATH@/ftbgn2c16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbgn3p08.png -o @TEMP_PATH@/ftbgn3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbrn2c08.png -o @TEMP_PATH@/ftbrn2c08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbwn0g16.png -o @TEMP_PATH@/ftbwn0g16.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbwn3p08.png -o @TEMP_PATH@/ftbwn3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftbyn3p08.png -o @TEMP_PATH@/ftbyn3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftp0n0g08.png -o @TEMP_PATH@/ftp0n0g08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftp0n2c08.png -o @TEMP_PATH@/ftp0n2c08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftp0n3p08.png -o @TEMP_PATH@/ftp0n3p08.png.jp2
image_to_j2k -i @INPUT_NR_PATH@/pngsuite/ftp1n3p08.png -o @TEMP_PATH@/ftp1n3p08.png.jp2
# DECODER TEST SUITE
j2k_to_image -i @INPUT_NR_PATH@/Bretagne2.j2k -o @TEMP_PATH@/Bretagne2.j2k.pgx
j2k_to_image -i @INPUT_NR_PATH@/_00042.j2k -o @TEMP_PATH@/_00042.j2k.pgx
j2k_to_image -i @INPUT_NR_PATH@/123.j2c -o @TEMP_PATH@/123.j2c.pgx
j2k_to_image -i @INPUT_NR_PATH@/broken.jp2 -o @TEMP_PATH@/broken.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/broken2.jp2 -o @TEMP_PATH@/broken2.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/broken3.jp2 -o @TEMP_PATH@/broken3.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/broken4.jp2 -o @TEMP_PATH@/broken4.jp2.pgx
# The 4 following tests should failed (kakadu indicates that they are corrupted)
!j2k_to_image -i @INPUT_NR_PATH@/broken1.jp2 -o @TEMP_PATH@/broken1.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/broken2.jp2 -o @TEMP_PATH@/broken2.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/broken3.jp2 -o @TEMP_PATH@/broken3.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/broken4.jp2 -o @TEMP_PATH@/broken4.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/bug.j2c -o @TEMP_PATH@/bug.j2c.pgx
j2k_to_image -i @INPUT_NR_PATH@/buxI.j2k -o @TEMP_PATH@/buxI.j2k.pgx
j2k_to_image -i @INPUT_NR_PATH@/buxR.j2k -o @TEMP_PATH@/buxR.j2k.pgx
@@ -62,6 +173,344 @@ j2k_to_image -i @INPUT_NR_PATH@/orb-blue10-win-j2k.j2k -o @TEMP_PATH@/orb-blue1
j2k_to_image -i @INPUT_NR_PATH@/orb-blue10-win-jp2.jp2 -o @TEMP_PATH@/orb-blue10-win-jp2.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/relax.jp2 -o @TEMP_PATH@/relax.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/test_lossless.j2k -o @TEMP_PATH@/test_lossless.j2k.pgx
# text_GBR.jp2 file exhibt a error about a tile part with a index > of the number of tile-part in this tile (related to issue 202, 206, 208)
j2k_to_image -i @INPUT_NR_PATH@/text_GBR.jp2 -o @TEMP_PATH@/text_GBR.jp2.pgx
# pacs.ge file should throw an error but finally it seems work with v2
j2k_to_image -i @INPUT_NR_PATH@/pacs.ge.j2k -o @TEMP_PATH@/pacs.ge.j2k.pgx
# related to issue 135
j2k_to_image -i @INPUT_NR_PATH@/kodak_2layers_lrcp.j2c -o @TEMP_PATH@/kodak_2layers_lrcp.j2c.pgx
j2k_to_image -i @INPUT_NR_PATH@/kodak_2layers_lrcp.j2c -o @TEMP_PATH@/kodak_2layers_lrcp.j2c.pgx -l 2
# related to issue 104 and 110
j2k_to_image -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)
!j2k_to_image -i @INPUT_NR_PATH@/mem-b2ace68c-1381.jp2 -o @TEMP_PATH@/mem-b2ace68c-1381.jp2.pgx
# File which produced weird output with kakadu and not supoprter by openjpeg (problem with value of TPSot, issue 202, 206, 208)
j2k_to_image -i @INPUT_NR_PATH@/mem-b2b86b74-2753.jp2 -o @TEMP_PATH@/mem-b2b86b74-2753.jp2.pgx
# issue 191 raised by the gdal fuzzer test (should properly failed)
!j2k_to_image -i @INPUT_NR_PATH@/gdal_fuzzer_unchecked_numresolutions.jp2 -o @TEMP_PATH@/gdal_fuzzer_unchecked_numresolutions.pgx
# issue 192 raised by the gdal fuzzer test (should nicely failed)
!j2k_to_image -i @INPUT_NR_PATH@/gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2 -o @TEMP_PATH@/gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.pgx
# issue 193 raised by the gdal fuzzer test (should nicely failed)
!j2k_to_image -i @INPUT_NR_PATH@/gdal_fuzzer_check_number_of_tiles.jp2 -o @TEMP_PATH@/gdal_fuzzer_check_number_of_tiles.pgx
# issue 194 raised by the gdal fuzzer test (should nicely failed)
!j2k_to_image -i @INPUT_NR_PATH@/gdal_fuzzer_check_comp_dx_dy.jp2 -o @TEMP_PATH@/gdal_fuzzer_check_comp_dx_dy.pgx
# issue 202
j2k_to_image -i @INPUT_NR_PATH@/file409752.jp2 -o @TEMP_PATH@/file409752.jp2.pgx
# issue 188
j2k_to_image -i @INPUT_NR_PATH@/issue188_beach_64bitsbox.jp2 -o @TEMP_PATH@/issue188_beach_64bitsbox.jp2.pgx
# issue 206
j2k_to_image -i @INPUT_NR_PATH@/issue206_image-000.jp2 -o @TEMP_PATH@/issue206_image-000.jp2.pgx
# issue 205
j2k_to_image -i @INPUT_NR_PATH@/issue205.jp2 -o @TEMP_PATH@/issue205.jp2.pgx
# issue 225 (sumatrapdf)
!j2k_to_image -i @INPUT_NR_PATH@/451.pdf.SIGSEGV.5b5.3723.jp2 -o @TEMP_PATH@/451.pdf.SIGSEGV.5b5.3723.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/1888.pdf.asan.35.988.jp2 -o @TEMP_PATH@/1888.pdf.asan.35.988.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/2539.pdf.SIGFPE.706.1712.jp2 -o @TEMP_PATH@/2539.pdf.SIGFPE.706.1712.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/2236.pdf.SIGSEGV.398.1376.jp2 -o @TEMP_PATH@/2236.pdf.SIGSEGV.398.1376.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/1336.pdf.asan.47.376.jp2 -o @TEMP_PATH@/1336.pdf.asan.47.376.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/1851.pdf.SIGSEGV.ce9.948.jp2 -o @TEMP_PATH@/1851.pdf.SIGSEGV.ce9.948.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/4149.pdf.SIGSEGV.cf7.3501.jp2 -o @TEMP_PATH@/4149.pdf.SIGSEGV.cf7.3501.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/4035.pdf.SIGSEGV.d8b.3375.jp2 -o @TEMP_PATH@/4035.pdf.SIGSEGV.d8b.3375.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/2977.pdf.asan.67.2198.jp2 -o @TEMP_PATH@/2977.pdf.asan.67.2198.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/451.pdf.SIGSEGV.ce9.3723.jp2 -o @TEMP_PATH@/451.pdf.SIGSEGV.ce9.3723.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/3635.pdf.asan.77.2930.jp2 -o @TEMP_PATH@/3635.pdf.asan.77.2930.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/1802.pdf.SIGSEGV.36e.894.jp2 -o @TEMP_PATH@/1802.pdf.SIGSEGV.36e.894.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/451.pdf.SIGSEGV.f4c.3723.jp2 -o @TEMP_PATH@/451.pdf.SIGSEGV.f4c.3723.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/2.pdf.SIGFPE.706.1112.jp2 -o @TEMP_PATH@/2.pdf.SIGFPE.706.1112.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/147af3f1083de4393666b7d99b01b58b_signal_sigsegv_130c531_6155_5136.jp2 -o @TEMP_PATH@/147af3f1083de4393666b7d99b01b58b_signal_sigsegv_130c531_6155_5136.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/4241ac039aba57e6a9c948d519d94216_asan_heap-oob_14650f2_7469_602.jp2 -o @TEMP_PATH@/4241ac039aba57e6a9c948d519d94216_asan_heap-oob_14650f2_7469_602.jp2
# issue 228 (16bits/lossy)
j2k_to_image -i @INPUT_NR_PATH@/issue228.j2k -o @TEMP_PATH@/issue228.j2k.pgx
# issue 229
!j2k_to_image -i @INPUT_NR_PATH@/27ac957758a35d00d6765a0c86350d9c.SIGFPE.d25.537.jpc -o @TEMP_PATH@27ac957758a35d00d6765a0c86350d9c.SIGFPE.d25.537.jpc.pgx
!j2k_to_image -i @INPUT_NR_PATH@/26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2 -o @TEMP_PATH@26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/0290cb77c5df21828fa74cf2ab2c84d8.SIGFPE.d25.31.jp2 -o @TEMP_PATH@0290cb77c5df21828fa74cf2ab2c84d8.SIGFPE.d25.31.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/3672da2f1f67bbecad27d7181b4e9d7c.SIGFPE.d25.805.jpc -o @TEMP_PATH@3672da2f1f67bbecad27d7181b4e9d7c.SIGFPE.d25.805.jpc.pgx
# issue 254 (loss in quality)
j2k_to_image -i @INPUT_NR_PATH@/issue254.jp2 -o @TEMP_PATH@/issue254.jp2.pgx
# issue 142
j2k_to_image -i @INPUT_NR_PATH@/issue142.j2k -o @TEMP_PATH@/issue142.j2k.pgx
# issue 134
j2k_to_image -i @INPUT_NR_PATH@/issue134.jp2 -o @TEMP_PATH@/issue134.jp2.pgx
# issue 135
j2k_to_image -i @INPUT_NR_PATH@/issue135.j2k -o @TEMP_PATH@/issue135.j2k.pgx
# issue 208
j2k_to_image -i @INPUT_NR_PATH@/issue208.jp2 -o @TEMP_PATH@/issue208.jp2.pgx
# issue 211
j2k_to_image -i @INPUT_NR_PATH@/issue211.jp2 -o @TEMP_PATH@/issue211.jp2.pgx
# issue 171
j2k_to_image -i @INPUT_NR_PATH@/issue171.jp2 -o @TEMP_PATH@/issue171.jp2.pgx
# issue 171
!j2k_to_image -i @INPUT_NR_PATH@/issue165.jp2 -o @TEMP_PATH@/issue165.jp2.pgx
#
!j2k_to_image -i @INPUT_NR_PATH@/broken.jpc -o @TEMP_PATH@/broken.jpc.pgx
# issue 226
j2k_to_image -i @INPUT_NR_PATH@/issue226.j2k -o @TEMP_PATH@/issue226.j2k.pgx
# issue 297
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1103421.jp2 -o @TEMP_PATH@/edf_c2_1103421.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1178956.jp2 -o @TEMP_PATH@/edf_c2_1178956.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1000290.jp2 -o @TEMP_PATH@/edf_c2_1000290.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1000691.jp2 -o @TEMP_PATH@/edf_c2_1000691.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_20.jp2 -o @TEMP_PATH@/edf_c2_20.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1377017.jp2 -o @TEMP_PATH@/edf_c2_1377017.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1002767.jp2 -o @TEMP_PATH@/edf_c2_1002767.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_10025.jp2 -o @TEMP_PATH@/edf_c2_10025.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1000234.jp2 -o @TEMP_PATH@/edf_c2_1000234.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_225881.jp2 -o @TEMP_PATH@/edf_c2_225881.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1000671.jp2 -o @TEMP_PATH@/edf_c2_1000671.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1013627.jp2 -o @TEMP_PATH@/edf_c2_1013627.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1015644.jp2 -o @TEMP_PATH@/edf_c2_1015644.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_101463.jp2 -o @TEMP_PATH@/edf_c2_101463.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1674177.jp2 -o @TEMP_PATH@/edf_c2_1674177.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/edf_c2_1673169.jp2 -o @TEMP_PATH@/edf_c2_1673169.jp2.pgx
# issue 296
#!j2k_to_image -i @INPUT_NR_PATH@/3459.pdf.asan.78.2734.0.jp2 -o @TEMP_PATH@/3459.pdf.asan.78.2734.0.jp2.pgx
#!j2k_to_image -i @INPUT_NR_PATH@/3459.pdf.asan.78.2734.1.jp2 -o @TEMP_PATH@/3459.pdf.asan.78.2734.1.jp2.pgx
#!j2k_to_image -i @INPUT_NR_PATH@/3459.pdf.asan.78.2734.2.jp2 -o @TEMP_PATH@/3459.pdf.asan.78.2734.2.jp2.pgx
#!j2k_to_image -i @INPUT_NR_PATH@/3459.pdf.asan.6c.2734.0.jp2 -o @TEMP_PATH@/3459.pdf.asan.6c.2734.0.jp2.pgx
#!j2k_to_image -i @INPUT_NR_PATH@/3459.pdf.asan.6c.2734.1.jp2 -o @TEMP_PATH@/3459.pdf.asan.6c.2734.1.jp2.pgx
#!j2k_to_image -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
!j2k_to_image -i @INPUT_NR_PATH@/issue362-2863.jp2 -o @TEMP_PATH@/issue362-2863.jp2.pgx
# Invalid ftyp box size
!j2k_to_image -i @INPUT_NR_PATH@/issue362-2866.jp2 -o @TEMP_PATH@/issue362-2866.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/issue362-2894.jp2 -o @TEMP_PATH@/issue362-2894.jp2.pgx
# issue 363 (from pdfium fuzz engine)
# Invalid Tile part length
!j2k_to_image -i @INPUT_NR_PATH@/issue363-4723.jp2 -o @TEMP_PATH@/issue363-4723.jp2.pgx
# Invalid Marker length
!j2k_to_image -i @INPUT_NR_PATH@/issue363-4740.jp2 -o @TEMP_PATH@/issue363-4740.jp2.pgx
!j2k_to_image -i @INPUT_NR_PATH@/issue363-4792.jp2 -o @TEMP_PATH@/issue363-4792.jp2.pgx
# issue 390 (from pdfium fuzz engine) Invalid segment size
!j2k_to_image -i @INPUT_NR_PATH@/issue390.jp2 -o @TEMP_PATH@/issue390.jp2.pgx
# issue 391 (from pdfium fuzz engine) Invalid segment size
!j2k_to_image -i @INPUT_NR_PATH@/issue391.jp2 -o @TEMP_PATH@/issue391.jp2.pgx
# issue 400 (from pdfium fuzz engine) Unknown Scod value in COD marker
!j2k_to_image -i @INPUT_NR_PATH@/issue400.jp2 -o @TEMP_PATH@/issue400.jp2.pgx
# issue 413 (from pdfium fuzz engine) Unknown progression order in COD marker
!j2k_to_image -i @INPUT_NR_PATH@/issue413.jp2 -o @TEMP_PATH@/issue413.jp2.pgx
# issue 364 (from pdfium fuzz engine)
# Inconsistent box length for jp2 box
!j2k_to_image -i @INPUT_NR_PATH@/issue364-38.jp2 -o @TEMP_PATH@/issue364-38.jp2.pgx
# No ihdr box
!j2k_to_image -i @INPUT_NR_PATH@/issue364-903.jp2 -o @TEMP_PATH@/issue364-903.jp2.pgx
# issue 393 (from pdfium fuzz engine) Zppm found twice
!j2k_to_image -i @INPUT_NR_PATH@/issue393.jp2 -o @TEMP_PATH@/issue393.jp2.pgx
# issue 395 (from pdfium fuzz engine) Stream too short
!j2k_to_image -i @INPUT_NR_PATH@/issue395.jp2 -o @TEMP_PATH@/issue395.jp2.pgx
# issue 397 (from pdfium fuzz engine) Incomplete channel definitions.
!j2k_to_image -i @INPUT_NR_PATH@/issue397.jp2 -o @TEMP_PATH@/issue397.jp2.pgx
# issue 399 (from pdfium fuzz engine) Incomplete channel definitions.
j2k_to_image -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.
!j2k_to_image -i @INPUT_NR_PATH@/issue408.jp2 -o @TEMP_PATH@/issue408.jp2.pgx
# issue 412 Palette image with cdef fails to decompress.
j2k_to_image -i @INPUT_NR_PATH@/issue412.jp2 -o @TEMP_PATH@/issue412.jp2.pgx
# issue 428 Palette image with cdef fails to decompress properly.
j2k_to_image -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.
j2k_to_image -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.
!j2k_to_image -i @INPUT_NR_PATH@/issue418.jp2 -o @TEMP_PATH@/issue418.jp2.pgx
# issue 420 (from pdfium fuzz engine) Illegal custom precinct exponent.
!j2k_to_image -i @INPUT_NR_PATH@/issue420.jp2 -o @TEMP_PATH@/issue420.jp2.pgx
# issue 422 (rework of issue 411). ycc with odd width/height
j2k_to_image -i @INPUT_NR_PATH@/issue411-ycc444.jp2 -o @TEMP_PATH@/issue411-ycc444.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/issue411-ycc422.jp2 -o @TEMP_PATH@/issue411-ycc422.jp2.pgx
j2k_to_image -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.
!j2k_to_image -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.
!j2k_to_image -i @INPUT_NR_PATH@/issue432.jp2 -o @TEMP_PATH@/issue432.jp2.pgx
# issue 427 image width is 0
!j2k_to_image -i @INPUT_NR_PATH@/issue427-null-image-size.jp2 -o @TEMP_PATH@/issue427-null-image-size.jp2.pgx
# issue 427 illegal tile offset
!j2k_to_image -i @INPUT_NR_PATH@/issue427-illegal-tile-offset.jp2 -o @TEMP_PATH@/issue427-illegal-tile-offset.jp2.pgx
# issue 458 component precision upscaling
j2k_to_image -i @INPUT_NR_PATH@/issue458.jp2 -o @TEMP_PATH@/issue458.jp2.pgx
# issue 476 Multiple COD in MH
!j2k_to_image -i @INPUT_NR_PATH@/issue476.jp2 -o @TEMP_PATH@/issue476.jp2.pgx
# issue 475 Invalid number of layers
!j2k_to_image -i @INPUT_NR_PATH@/issue475.jp2 -o @TEMP_PATH@/issue475.jp2.pgx
# issue 495 Overflow op_image_comp_header_updat
j2k_to_image -i @INPUT_NR_PATH@/issue495.jp2 -o @TEMP_PATH@/issue495.jp2.pgx
# OPTIONS NOT IMPLEMENTED >
# # decode with specific area
# # prec=12; nb_c=1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04.j2k.png -d 0,0,1024,1024
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_1.j2k.png -d 512,640,640,768
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_2.j2k.png -d 896,896,1024,1024
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_3.j2k.png -d 100,500,300,800
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_4.j2k.png -d 260,520,360,600
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_5.j2k.png -d 260,520,360,660
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_6.j2k.png -d 360,520,400,600
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_10.j2k.png -d 0,0,1024,1024 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_11.j2k.png -d 512,640,640,768 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_12.j2k.png -d 896,896,1024,1024 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_13.j2k.png -d 100,500,300,800 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_14.j2k.png -d 260,520,360,600 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_15.j2k.png -d 260,520,360,660 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_16.j2k.png -d 360,520,400,600 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_17_t63.j2k.png -t 63
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_17_t63_r2.j2k.png -t 63 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_18.t12.j2k.png -t 12
# j2k_to_image -i @INPUT_CONF_PATH@/p1_04.j2k -o @TEMP_PATH@/p1_04_19_t12_r1.j2k.png -t 12 -r 1
# # prec=8; nb_c=3
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06.j2k.png -d 0,0,12,12
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_1.j2k.png -d 1,8,8,11
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_2.j2k.png -d 9,9,12,12
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_3.j2k.png -d 10,4,12,10
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_4.j2k.png -d 3,3,9,9
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_5.j2k.png -d 4,4,7,7
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_6.j2k.png -d 4,4,5,5
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7.j2k.png -d 0,0,12,12 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_1.j2k.png -d 1,8,8,11 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_2.j2k.png -d 9,9,12,12 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_3.j2k.png -d 10,4,12,10 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_4.j2k.png -d 3,3,9,9 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_5.j2k.png -d 4,4,7,7 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_7_6.j2k.png -d 4,4,5,5 -r 1
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_8_6.j2k.png -d 9,9,12,12 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_9.j2k.png -t 0
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_9_1.j2k.png -t 5
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_9_2.j2k.png -t 9
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_9_3.j2k.png -t 15
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_10.j2k.png -t 0 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_10_1.j2k.png -t 5 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_10_2.j2k.png -t 9 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_10_3.j2k.png -t 15 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p1_06.j2k -o @TEMP_PATH@/p1_06_11.j2k.png -r 4
# # prec=4; nb_c=3 ; signd=yes
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04.j2k.png -d 0,0,256,256
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_1.j2k.png -d 128,0,256,128
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_2.j2k.png -d 50,10,120,200
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_3.j2k.png -d 10,150,190,210
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_4.j2k.png -d 100,80,200,150
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_5.j2k.png -d 150,20,200,50
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6.j2k.png -d 0,0,256,256 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_1.j2k.png -d 128,0,256,128 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_2.j2k.png -d 50,10,120,200 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_3.j2k.png -d 10,150,190,210 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_4.j2k.png -d 100,80,200,150 -r 2
# j2k_to_image -i @INPUT_CONF_PATH@/p0_04.j2k -o @TEMP_PATH@/p0_04_6_5.j2k.png -d 150,20,200,50 -r 2
# # prec=8; nb_c=1 ; non standard origin (image offset and tile offset); sample sep: 2x1
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01.j2k.png -d 5,128,127,226
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_1.j2k.png -d 5,128,122,99
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_2.j2k.png -d 50,10,120,200
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_3.j2k.png -d 10,150,190,210
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_4.j2k.png -d 100,80,200,150
# #j2k_to_image -i @INPUT_CONF_PATH@/p1_01.j2k -o @TEMP_PATH@/p1_01_5.j2k.png -d 150,20,200,50
# < NOT IMPLEMENTED
# issue 322 limited tif support
# GRAYSCALE
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-1.tif -p 1S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-2.tif -p 2S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-4.tif -p 4S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-6.tif -p 6S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-8.tif -p 8S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-10.tif -p 10S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-12.tif -p 12S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-14.tif -p 14S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_tif-16.tif -p 16S
# GRAYSCALE ALPHA
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-1.tif -p 1S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-2.tif -p 2S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-4.tif -p 4S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-6.tif -p 6S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-8.tif -p 8S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-10.tif -p 10S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-12.tif -p 12S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-14.tif -p 14S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_tif-16.tif -p 16S
# RGB
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-1.tif -p 1S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-2.tif -p 2S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-4.tif -p 4S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-6.tif -p 6S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-8.tif -p 8S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-10.tif -p 10S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-12.tif -p 12S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-14.tif -p 14S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_tif-16.tif -p 16S
# RGBA
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-1.tif -p 1S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-2.tif -p 2S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-4.tif -p 4S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-6.tif -p 6S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-8.tif -p 8S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-10.tif -p 10S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-12.tif -p 12S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-14.tif -p 14S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_tif-16.tif -p 16S
#issue 235 CMAP outside jp2h box. CMAP is buggy
j2k_to_image -i @INPUT_NR_PATH@/issue235.jp2 -o @TEMP_PATH@/issue235.jp2.pgx
# issue 264, add checks for png
# GRAYSCALE
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-1.png -p 1S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-2.png -p 2S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-4.png -p 4S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-6.png -p 6S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-8.png -p 8S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-10.png -p 10S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-12.png -p 12S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-14.png -p 14S
j2k_to_image -i @INPUT_CONF_PATH@/a1_mono.j2c -o @TEMP_PATH@/a1_mono_png-16.png -p 16S
# GRAYSCALE ALPHA
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-1.png -p 1S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-2.png -p 2S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-4.png -p 4S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-6.png -p 6S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-8.png -p 8S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-10.png -p 10S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-12.png -p 12S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-14.png -p 14S
j2k_to_image -i @INPUT_NR_PATH@/basn4a08.jp2 -o @TEMP_PATH@/basn4a08_png-16.png -p 16S
# RGB
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-1.png -p 1S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-2.png -p 2S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-4.png -p 4S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-6.png -p 6S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-8.png -p 8S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-10.png -p 10S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-12.png -p 12S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-14.png -p 14S
j2k_to_image -i @INPUT_CONF_PATH@/p0_14.j2k -o @TEMP_PATH@/p0_14_png-16.png -p 16S
# RGBA
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-1.png -p 1S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-2.png -p 2S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-4.png -p 4S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-6.png -p 6S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-8.png -p 8S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-10.png -p 10S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-12.png -p 12S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-14.png -p 14S
j2k_to_image -i @INPUT_NR_PATH@/basn6a08.jp2 -o @TEMP_PATH@/basn6a08_png-16.png -p 16S
# issue 388
!j2k_to_image -i @INPUT_NR_PATH@/v4dwt_interleave_h.gsr105.j2k -o @TEMP_PATH@/v4dwt_interleave_h.gsr105.j2k.pgx
j2k_to_image -i @INPUT_NR_PATH@/dwt_interleave_h.gsr105.jp2 -o @TEMP_PATH@/dwt_interleave_h.gsr105.jp2.pgx
# PR 559 : CMYK tif output
j2k_to_image -i @INPUT_NR_PATH@/issue205.jp2 -o @TEMP_PATH@/issue205-tif.jp2.tif
# issue 236: esYCC colorspace
j2k_to_image -i @INPUT_NR_PATH@/issue236-ESYCC-CDEF.jp2 -o @TEMP_PATH@/issue236-ESYCC-CDEF.jp2.pgx
# issue 326 + PR 559: CIELab colorspace
j2k_to_image -i @INPUT_NR_PATH@/issue559-eci-090-CIELab.jp2 -o @TEMP_PATH@/issue559-eci-090-CIELab.jp2.pgx
j2k_to_image -i @INPUT_NR_PATH@/issue559-eci-091-CIELab.jp2 -o @TEMP_PATH@/issue559-eci-091-CIELab.jp2.pgx

142
tests/pdf2jp2.c Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2014, Mathieu Malaterre <mathieu.malaterre@voxxl.com>
* 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.
*/
/*
* Extract all JP2 files contained within a PDF file.
*
* Technically you could simply use mutool, eg:
*
* $ mutool show -be -o obj58.jp2 Bug691816.pdf 58
*
* to extract a given JP2 file from within a PDF
* However it happens sometimes that the PDF is itself corrupted, this tools is
* a lame PDF parser which only extract stream contained in JPXDecode box
* only work on linux since I need memmem function
*/
/*
* Add support for other signatures:
*
* obj<</Subtype/Image/Length 110494/Filter/JPXDecode/BitsPerComponent 8/ColorSpace/DeviceRGB/Width 712/Height 1052>>stream
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
int main(int argc, char *argv[])
{
#define NUMJP2 32
int i, c = 0;
long offets[NUMJP2];
char buffer[512];
#define BUFLEN 4096
int cont = 1;
FILE *f;
size_t nread;
char haystack[BUFLEN];
const char needle[] = "JPXDecode";
const size_t nlen = strlen( needle );
const size_t flen = BUFLEN - nlen;
char *fpos = haystack + nlen;
const char *filename;
if( argc < 2 ) return 1;
filename = argv[1];
memset( haystack, 0, nlen );
f = fopen( filename, "rb" );
while( cont )
{
const char *ret;
size_t hlen;
nread = fread(fpos, 1, flen, f);
hlen = nlen + nread;
ret = memmem( haystack, hlen, needle, nlen);
if( ret )
{
const long cpos = ftell(f);
const ptrdiff_t diff = ret - haystack;
assert( diff >= 0 );
/*fprintf( stdout, "Found it: %lx\n", (ptrdiff_t)cpos - (ptrdiff_t)hlen + diff);*/
offets[c++] = (ptrdiff_t)cpos - (ptrdiff_t)hlen + diff;
}
cont = (nread == flen);
memcpy( haystack, haystack + nread, nlen );
}
assert( feof( f ) );
for( i = 0; i < c; ++i )
{
int s, len = 0;
char *r;
const int ret = fseek(f, offets[i], SEEK_SET);
assert( ret == 0 );
r = fgets(buffer, sizeof(buffer), f);
assert( r );
/*fprintf( stderr, "DEBUG: %s", r );*/
s = sscanf(r, "JPXDecode]/Length %d/Width %*d/BitsPerComponent %*d/Height %*d", &len);
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;
char jp2fn[512];
sprintf( jp2fn, "%s.%d.jp2", filename, i );
jp2 = fopen( jp2fn, "wb" );
for( j = 0; j < len; ++j )
{
int v = fgetc(f);
int ret2 = fputc(v, jp2);
assert( ret2 != EOF );
}
fclose( jp2 );
#if 0
/* TODO need to check we reached endstream */
r = fgets(buffer, sizeof(buffer), f);
fprintf( stderr, "DEBUG: [%s]", r );
r = fgets(buffer, sizeof(buffer), f);
fprintf( stderr, "DEBUG: [%s]", r );
#endif
}
}
fclose(f);
return 0;
}

139
tests/ppm2rgb3.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2014, Mathieu Malaterre <mathieu.malaterre@voxxl.com>
* 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.
*/
/*
* Technically on UNIX, one can simply call `ppmtorgb3`, but on my system it
* did not work. So I had to write my own.
*/
#include <stdio.h> /* fprintf */
#include <string.h> /* strcmp */
#include <stdlib.h> /* malloc */
static const char magic[] = "P6";
static int readheader( FILE *ppm, int *X, int *Y, int *bpp )
{
char buffer[256];
char strbuffer[256];
char *line;
int n;
*X = *Y = *bpp = 0;
line = fgets(buffer, sizeof(buffer), ppm);
if( !line ) return 0;
n = sscanf(buffer, "%255[^\r\n]", strbuffer);
if( n != 1 ) return 0;
if( strcmp(strbuffer, magic ) != 0 ) return 0;
/* skip comments */
while( fgets(buffer, sizeof(buffer), ppm) && *buffer == '#' )
{
}
n = sscanf(buffer, "%d %d", X,Y);
if( n != 2 ) return 0;
line = fgets(buffer, sizeof(buffer), ppm);
if( !line ) return 0;
n = sscanf(buffer, "%d", bpp);
if( n != 1 ) return 0;
if( *bpp != 255 ) return 0;
return 1;
}
static int writeoutput( const char *fn, FILE *ppm, int X, int Y, int bpp )
{
FILE *outf[] = {NULL, NULL, NULL};
int i, x, y = 0;
char outfn[256];
static const char *exts[3] = {
"red",
"grn",
"blu"
};
char *image_line = NULL;
int ok = 0;
/* write single comp as PGM: P5 */
for( i = 0; i < 3; ++i )
{
#ifdef _MSC_VER
#define snprintf _snprintf /* Visual Studio */
#endif
snprintf( outfn, sizeof(outfn), "%s.%s.pgm", fn, exts[i] );
outf[i] = fopen( outfn, "wb" );
if( !outf[i] ) goto cleanup;
/* write header */
fprintf( outf[i], "P5\n" );
fprintf( outf[i], "%d %d\n", X, Y );
fprintf( outf[i], "%d\n", bpp );
}
/* write pixel data */
image_line = (char*)malloc( (size_t)X * 3 * sizeof(char) );
if( !image_line ) goto cleanup;
while( fread(image_line, sizeof(char), (size_t)X * 3, ppm) == (size_t)X * 3 )
{
for( x = 0; x < X; ++x )
for( i = 0; i < 3; ++i )
if( fputc( image_line[3*x+i], outf[i] ) == EOF ) goto cleanup;
++y;
}
if( y == Y )
ok = 1;
cleanup:
free(image_line);
for( i = 0; i < 3; ++i )
if( outf[i] ) fclose( outf[i] );
return ok;
}
int main(int argc, char *argv[])
{
const char *fn;
FILE *ppm = NULL;
int X, Y, bpp;
int ok = 0;
if( argc < 2 )
{
fprintf( stderr, "%s input.ppm\n", argv[0] );
goto cleanup;
}
fn = argv[1];
ppm = fopen( fn, "rb" );
if( !readheader( ppm, &X, &Y, &bpp ) ) goto cleanup;
if( !writeoutput(fn, ppm, X, Y, bpp ) ) goto cleanup;
ok = 1;
cleanup:
if(ppm) fclose(ppm);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,9 +1,17 @@
# UNIT TESTS
add_executable(testempty1 testempty1.c)
add_executable(testempty2 testempty2.c)
target_link_libraries(testempty1 openjpeg)
target_link_libraries(testempty2 openjpeg)
include_directories(
${OPENJPEG_BINARY_DIR}/libopenjpeg # opj_config.h
${OPENJPEG_SOURCE_DIR}/libopenjpeg
)
add_test(testempty1 ${EXECUTABLE_OUTPUT_PATH}/testempty1)
add_test(testempty2 ${EXECUTABLE_OUTPUT_PATH}/testempty2)
set(unit_test
testempty0
testempty1
testempty2
)
foreach(ut ${unit_test})
add_executable(${ut} ${ut}.c)
target_link_libraries(${ut} openjpeg)
add_test(NAME ${ut} COMMAND ${ut})
endforeach()

7
tests/unit/testempty0.c Normal file
View File

@@ -0,0 +1,7 @@
#include "openjpeg.h"
int main(int argc, char **argv) {
(void)argc;
(void)argv;
return 0;
}

View File

@@ -111,6 +111,15 @@ int main(int argc, char *argv[])
cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
assert( cio );
bSuccess = opj_encode(cinfo, cio, image, NULL);
if( !bSuccess )
{
opj_cio_close(cio);
opj_destroy_compress(cinfo);
opj_image_destroy(image);
return 0;
}
assert( bSuccess );
codestream_length = (size_t)cio_tell(cio);

View File

@@ -63,8 +63,8 @@ int main(int argc, char *argv[])
opj_cparameters_t parameters;
int subsampling_dx = parameters.subsampling_dx;
int subsampling_dy = parameters.subsampling_dy;
int subsampling_dx;
int subsampling_dy;
const char outputfile[] = "testempty2.j2k";
opj_image_cmptparm_t cmptparm;
@@ -81,6 +81,8 @@ int main(int argc, char *argv[])
opj_set_default_encoder_parameters(&parameters);
parameters.cod_format = J2K_CFMT;
puts(v);
subsampling_dx = parameters.subsampling_dx;
subsampling_dy = parameters.subsampling_dy;
cmptparm.prec = 8;
cmptparm.bpp = 8;
cmptparm.sgnd = 0;
@@ -113,6 +115,15 @@ int main(int argc, char *argv[])
cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
assert( cio );
bSuccess = opj_encode(cinfo, cio, image, NULL);
if( !bSuccess )
{
opj_cio_close(cio);
opj_destroy_compress(cinfo);
opj_image_destroy(image);
return 0;
}
assert( bSuccess );
codestream_length = (size_t)cio_tell(cio);

View File

@@ -57,7 +57,10 @@ IF(BUILD_THIRDPARTY)
message(STATUS "We will build TIFF lib from thirdparty")
ADD_SUBDIRECTORY(libtiff)
SET(TIFF_LIBNAME tiff PARENT_SCOPE)
SET(TIFF_INCLUDE_DIRNAME ${OPENJPEG_SOURCE_DIR}/thirdparty/libtiff PARENT_SCOPE)
SET(TIFF_INCLUDE_DIRNAME
${OPENJPEG_SOURCE_DIR}/thirdparty/libtiff
${OPENJPEG_BINARY_DIR}/thirdparty/libtiff
PARENT_SCOPE)
SET(HAVE_TIFF_H 1 PARENT_SCOPE)
SET(HAVE_LIBTIFF 1 PARENT_SCOPE)
ELSE (BUILD_THIRDPARTY)

View File

@@ -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 <limits.h>
# 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 <sys/types.h> /* for off_t */
# ifndef Z_SOLO
# include <sys/types.h> /* for off_t */
# endif
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
# include <stdarg.h> /* for va_list */
# endif
#endif
#ifdef _WIN32
# ifndef Z_SOLO
# include <stddef.h> /* 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 <unistd.h> /* for SEEK_* and off_t */
# ifdef VMS
# include <unixio.h> /* 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 <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS
# include <unixio.h> /* 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 */

View File

@@ -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 <windows.h>
/* 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 <sys/types.h> /* 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 <unistd.h> /* for SEEK_* and off_t */
# ifdef VMS
# include <unixio.h> /* 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 */

View File

@@ -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
}

View File

@@ -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,12 +889,17 @@ 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.
@@ -858,8 +908,21 @@ typedef void* cmsHTRANSFORM;
#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);
@@ -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,15 +1720,37 @@ 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,
@@ -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);

View File

@@ -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

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -52,7 +52,7 @@ typedef struct {
cmsUInt32Number surround;
cmsFloat64Number n, Nbb, Ncb, z, FL, D;
cmsContext ContextID;
cmsContext ContextID;
} cmsCIECAM02;
@@ -358,70 +358,70 @@ CAM02COLOR CAT02toXYZ(CAM02COLOR 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,7 +429,7 @@ void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel)
{
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
}
@@ -438,9 +438,11 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh
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;
@@ -462,9 +464,11 @@ 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;
@@ -480,4 +484,3 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ
pOut ->Y = clr.XYZ[1];
pOut ->Z = clr.XYZ[2];
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -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,6 +44,7 @@
# define DIR_CHAR '/'
#endif
// Symbols
typedef enum {
@@ -114,6 +115,8 @@ typedef struct _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
@@ -133,7 +136,6 @@ typedef struct _FileContext {
// 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
@@ -352,28 +354,28 @@ static const char* PredefinedSampleID[] = {
//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
// 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)
{
@@ -404,6 +406,7 @@ 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
@@ -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
@@ -759,6 +840,14 @@ void InSymbol(cmsIT8* it8)
// 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;
@@ -768,7 +857,7 @@ void InSymbol(cmsIT8* it8)
// Comment
case '#':
NextCh(it8);
while (it8->ch && it8->ch != '\n')
while (it8->ch && it8->ch != '\n' && it8->ch != '\r')
NextCh(it8);
it8->sy = SCOMMENT;
@@ -886,6 +975,9 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error
{
switch (it8->sy) {
case SEOLN: // Empty value
Buffer[0]=0;
break;
case SIDENT: strncpy(Buffer, it8->id, max);
Buffer[max-1]=0;
break;
@@ -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) {
@@ -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;
}
@@ -1174,7 +1268,7 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable)
it8 ->nTable = nTable;
return nTable;
return (cmsInt32Number) nTable;
}
@@ -1183,7 +1277,7 @@ 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;
@@ -1214,7 +1308,7 @@ 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
@@ -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,7 +1358,6 @@ 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;
@@ -1285,7 +1373,7 @@ cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUIn
cmsIT8* it8 = (cmsIT8*) hIT8;
char Buffer[1024];
sprintf(Buffer, "%d", Val);
sprintf(Buffer, "%u", Val);
return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != 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");
@@ -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");
@@ -1470,7 +1559,7 @@ void WriteStr(SAVESTREAM* f, const char *str)
if (str == NULL)
str = " ";
// Lenghth to write
// Length to write
len = (cmsUInt32Number) strlen(str);
f ->Used += len;
@@ -1524,6 +1613,9 @@ 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)
{
@@ -1672,8 +1764,6 @@ 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);
@@ -1708,20 +1798,18 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number*
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;
@@ -1934,12 +2022,8 @@ 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))
@@ -1950,9 +2034,20 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
*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);
@@ -1974,6 +2069,39 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
AllocTable(it8);
it8 ->nTable = it8 ->TablesCount - 1;
// Read sheet type if present. We only support identifier and string.
// <ident> <eoln> 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;
@@ -2022,9 +2150,9 @@ void CookPointers(cmsIT8* it8)
if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
t -> SampleID = idField;
t -> SampleID = idField;
for (i=0; i < t -> nPatches; i++) {
for (i=0; i < t -> nPatches; i++) {
char *Data = GetData(it8, i, idField);
if (Data) {
@@ -2039,7 +2167,7 @@ void CookPointers(cmsIT8* it8)
SetData(it8, i, idField, Buffer);
}
}
}
}
@@ -2070,7 +2198,7 @@ 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 );
@@ -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;
}
@@ -2151,7 +2278,7 @@ cmsBool IsMyFile(const char* FileName)
Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp);
if (fclose(fp) != 0)
return FALSE;
return FALSE;
Ptr[Size] = '\0';
@@ -2165,10 +2292,10 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt3
{
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;
@@ -2208,11 +2335,11 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileN
cmsHANDLE hIT8;
cmsIT8* it8;
int type;
int type;
_cmsAssert(cFileName != NULL);
_cmsAssert(cFileName != NULL);
type = IsMyFile(cFileName);
type = IsMyFile(cFileName);
if (type == 0) return NULL;
hIT8 = cmsIT8Alloc(ContextID);
@@ -2241,10 +2368,10 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileN
CookPointers(it8);
it8 ->nTable = 0;
if (fclose(it8 ->FileStack[0]->Stream)!= 0) {
cmsIT8Free(hIT8);
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;
}
@@ -2273,9 +2400,9 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN
char **Props;
TABLE* t;
_cmsAssert(hIT8 != NULL);
_cmsAssert(hIT8 != NULL);
t = GetTable(it8);
t = GetTable(it8);
// Pass#1 - count properties
@@ -2305,10 +2432,10 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cP
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;
@@ -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);
}
@@ -2425,13 +2552,9 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int c
Buffer = cmsIT8GetDataRowCol(hIT8, row, col);
if (Buffer) {
return atof(Buffer);
} else
return 0;
if (Buffer == NULL) return 0.0;
return ParseFloatNumber(Buffer);
}
@@ -2439,7 +2562,7 @@ cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const ch
{
cmsIT8* it8 = (cmsIT8*) hIT8;
_cmsAssert(hIT8 != NULL);
_cmsAssert(hIT8 != NULL);
return SetData(it8, row, col, Val);
}
@@ -2450,7 +2573,7 @@ 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);
@@ -2464,7 +2587,7 @@ const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const ch
cmsIT8* it8 = (cmsIT8*) hIT8;
int iField, iSet;
_cmsAssert(hIT8 != NULL);
_cmsAssert(hIT8 != NULL);
iField = LocateSample(it8, cSample);
if (iField < 0) {
@@ -2486,14 +2609,7 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch,
Buffer = cmsIT8GetData(it8, cPatch, cSample);
if (Buffer) {
return atof(Buffer);
} else {
return 0;
}
return ParseFloatNumber(Buffer);
}
@@ -2504,9 +2620,9 @@ cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char*
int iField, iSet;
TABLE* t;
_cmsAssert(hIT8 != NULL);
_cmsAssert(hIT8 != NULL);
t = GetTable(it8);
t = GetTable(it8);
iField = LocateSample(it8, cSample);
@@ -2541,53 +2657,53 @@ 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.
@@ -2627,17 +2743,17 @@ int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char
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;
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -108,15 +108,68 @@ static cmsIntentsList DefaultIntents[] = {
// 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)
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;
@@ -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,15 +247,14 @@ 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);
_cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ());
}
// Join scalings to obtain relative input to absolute and then to relative output.
@@ -211,7 +267,7 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState,
const cmsMAT3* ChromaticAdaptationMatrixOut,
cmsMAT3* m)
{
cmsMAT3 Scale, m1, m2, m3;
cmsMAT3 Scale, m1, m2, m3, m4;
// Adaptation state
if (AdaptationState == 1.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);
@@ -333,7 +398,7 @@ 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 ||
@@ -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;
@@ -452,7 +525,8 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags)
{
cmsPipeline* Lut, *Result;
cmsPipeline* Lut = NULL;
cmsPipeline* Result;
cmsHPROFILE hProfile;
cmsMAT3 m;
cmsVEC3 off;
@@ -460,8 +534,8 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
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);
@@ -478,14 +552,14 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
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];
@@ -508,7 +582,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
// 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 (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) {
// Get the involved LUT from the profile
Lut = _cmsReadDevicelinkLUT(hProfile, Intent);
@@ -548,8 +622,11 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
}
// Concatenate to the output LUT
cmsPipelineCat(Result, Lut);
if (!cmsPipelineCat(Result, Lut))
goto Error;
cmsPipelineFree(Lut);
Lut = NULL;
// Update current space
CurrentColorSpace = ColorSpaceOut;
@@ -559,6 +636,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
Error:
if (Lut != NULL) cmsPipelineFree(Lut);
if (Result != NULL) cmsPipelineFree(Result);
return NULL;
@@ -697,7 +775,8 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
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))
@@ -847,7 +926,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
// 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
@@ -864,6 +944,8 @@ 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,
@@ -873,6 +955,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
BPC,
AdaptationStates,
dwFlags);
if (bp.cmyk2cmyk == NULL) goto Cleanup;
// Now the tone curve
bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles,
@@ -881,7 +964,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
BPC,
AdaptationStates,
dwFlags);
if (bp.KTone == NULL) goto Cleanup;
// To measure the output, Last profile to Lab
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
@@ -889,13 +972,15 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
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),
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)
@@ -908,7 +993,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
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);
@@ -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);
@@ -984,12 +1070,14 @@ 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
// 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)
@@ -1002,37 +1090,52 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32
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;
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -31,13 +31,14 @@
// 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)
@@ -47,9 +48,9 @@ long int CMSEXPORT cmsfilelength(FILE* f)
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
@@ -62,9 +63,8 @@ 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))
@@ -74,7 +74,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// 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);
// *********************************************************************************
@@ -114,7 +114,7 @@ void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
cmsUNUSED_PARAMETER(ContextID);
}
// The default realloc function. Again it check for exploits. If Ptr is NULL,
// 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)
@@ -167,82 +167,132 @@ 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;
_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);
}
// ********************************************************************************************
@@ -250,12 +300,16 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe
// 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)
// 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,7 +375,7 @@ 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.
if (size > Free) {
@@ -351,6 +401,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number 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.
@@ -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
@@ -384,16 +472,27 @@ void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorC
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
@@ -402,13 +501,18 @@ void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, c
{
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);
// 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
@@ -426,3 +530,125 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
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);
}
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -53,7 +53,6 @@ typedef struct _cmsParametricCurvesCollection_st {
} _cmsParametricCurvesCollection;
// This is the default (built-in) evaluator
static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
@@ -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,12 +174,24 @@ 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)
*index = Position;
return c;
}
}
// If none found, revert for defaults
for (c = &DefaultCurves; c != NULL; c = c ->Next) {
Position = IsInSet(Type, c);
@@ -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;
@@ -384,7 +461,7 @@ 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];
@@ -419,7 +496,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
e = Params[1]*R + Params[2];
if (e < 0)
Val = 0;
Val = Params[3];
else
Val = pow(e, Params[0]) + Params[3];
break;
@@ -439,7 +516,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
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;
@@ -505,7 +582,7 @@ 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)
@@ -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.
@@ -577,20 +667,21 @@ 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].Type = 0;
@@ -598,7 +689,19 @@ cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cm
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;
}
@@ -806,7 +909,10 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con
_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),
@@ -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;

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -162,7 +162,7 @@ cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
out = ComputeKToLstar(ContextID, nPoints, 1,
Intents + (nProfiles - 1),
hProfiles + (nProfiles - 1),
&hProfiles [nProfiles - 1],
BPC + (nProfiles - 1),
AdaptationStates + (nProfiles - 1),
dwFlags);
@@ -183,7 +183,6 @@ cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
// Make sure it is monotonic
if (!cmsIsToneCurveMonotonic(KTone)) {
cmsFreeToneCurve(KTone);
return NULL;
}
@@ -221,13 +220,10 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
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);
cmsDoTransform(t -> hInput, In, &LabIn1, 1);
// converts from PCS to colorant. This always
// does return in-gamut values,
@@ -239,7 +235,7 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
// Try again, but this time taking Check as input
cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
// Take difference of direct value
@@ -289,126 +285,129 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
// 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 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];
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));
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;
}
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;
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.
// 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)) {
if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0;
}
else {
Chain.Thereshold = ERR_THERESHOLD;
}
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];
}
// 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;
// Fill Lab identity
ProfileList[nGamutPCSposition] = hLab;
BPCList[nGamutPCSposition] = 0;
AdaptationList[nGamutPCSposition] = 1.0;
IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
ColorSpace = cmsGetColorSpace(hGamut);
ColorSpace = cmsGetColorSpace(hGamut);
nChannels = cmsChannelsOf(ColorSpace);
nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
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);
// 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 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);
// 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) {
// 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.
// 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);
Gamut = cmsPipelineAlloc(ContextID, 3, 1);
if (Gamut != NULL) {
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...
CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
// 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);
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;
// And return computed hull
return Gamut;
}
// Total Area Coverage estimation ----------------------------------------------------------------
@@ -494,9 +493,9 @@ cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
GridPoints[2] = 74;
if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
bp.MaxTAC = 0;
}
if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
bp.MaxTAC = 0;
}
cmsDeleteTransform(bp.hRoundTrip);

535
thirdparty/liblcms2/src/cmshalf.c vendored Normal file
View File

@@ -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

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -33,32 +33,57 @@
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(cmsInterpParams* p)
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
{
// Invoke factory, possibly in the Plug-in
p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
p ->Interpolation.Lerp16 = NULL;
// 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
@@ -69,6 +94,7 @@ cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
if (p ->Interpolation.Lerp16 == NULL) {
return FALSE;
}
return TRUE;
}
@@ -113,7 +139,7 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
if (!_cmsSetInterpolationRoutine(p)) {
if (!_cmsSetInterpolationRoutine(ContextID, p)) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
_cmsFree(ContextID, p);
return NULL;
@@ -186,6 +212,11 @@ void LinLerp1D(register const cmsUInt16Number Value[],
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
@@ -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);
@@ -263,13 +296,15 @@ void Eval1InputFloat(const cmsFloat32Number Value[],
cmsUInt32Number OutChan;
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);
@@ -310,8 +345,8 @@ void BilinearInterpFloat(const cmsFloat32Number Input[],
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;
@@ -425,20 +460,9 @@ void TrilinearInterpFloat(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); fx = px - (cmsFloat32Number) x0;
y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
@@ -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);
@@ -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,99 +695,131 @@ 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])
@@ -784,7 +828,7 @@ 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;
@@ -979,8 +1023,7 @@ void Eval4InputsFloat(const cmsFloat32Number Input[],
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
cmsInterpParams p1;
pk = Input[0] * p->Domain[0];
pk = fclamp(Input[0]) * p->Domain[0];
k0 = _cmsQuickFloor(pk);
rest = pk - (cmsFloat32Number) k0;
@@ -1067,7 +1110,7 @@ void Eval5InputsFloat(const cmsFloat32Number Input[],
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
cmsInterpParams p1;
pk = Input[0] * p->Domain[0];
pk = fclamp(Input[0]) * p->Domain[0];
k0 = _cmsQuickFloor(pk);
rest = pk - (cmsFloat32Number) k0;
@@ -1154,7 +1197,7 @@ void Eval6InputsFloat(const cmsFloat32Number Input[],
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
cmsInterpParams p1;
pk = Input[0] * p->Domain[0];
pk = fclamp(Input[0]) * p->Domain[0];
k0 = _cmsQuickFloor(pk);
rest = pk - (cmsFloat32Number) k0;
@@ -1207,7 +1250,7 @@ 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;
@@ -1239,7 +1282,7 @@ void Eval7InputsFloat(const cmsFloat32Number Input[],
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
cmsInterpParams p1;
pk = Input[0] * p->Domain[0];
pk = fclamp(Input[0]) * p->Domain[0];
k0 = _cmsQuickFloor(pk);
rest = pk - (cmsFloat32Number) k0;
@@ -1324,7 +1367,7 @@ void Eval8InputsFloat(const cmsFloat32Number Input[],
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
cmsInterpParams p1;
pk = Input[0] * p->Domain[0];
pk = fclamp(Input[0]) * p->Domain[0];
k0 = _cmsQuickFloor(pk);
rest = pk - (cmsFloat32Number) k0;

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -100,7 +100,6 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile)
Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag);
if (Tag != NULL) {
*Dest = *Tag;
return TRUE;
}
@@ -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());
}
}
@@ -164,7 +163,8 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
if (GrayTRC == NULL) return NULL;
Lut = cmsPipelineAlloc(ContextID, 1, 3);
if (Lut == NULL) return NULL;
if (Lut == NULL)
goto Error;
if (cmsGetPCS(hProfile) == cmsSigLabData) {
@@ -175,28 +175,35 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
if (EmptyTab == NULL) {
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
@@ -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,40 +314,78 @@ 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.
@@ -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)
{
@@ -378,12 +490,26 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile)
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,62 +586,117 @@ 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);
}
// ---------------------------------------------------------------------------------------------------------------
// 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,10 +707,36 @@ 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];
@@ -509,10 +761,10 @@ 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);
@@ -522,17 +774,21 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
// 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;
}
// ---------------------------------------------------------------------------------------------------------------
@@ -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;
@@ -636,12 +891,13 @@ cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile)
NewSeq = cmsDupProfileSequenceDescription(ProfileSeq);
// Ok, proceed to the mixing
for (i=0; i < ProfileSeq ->n; i++) {
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);
memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID));
NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description);
}
}
return NewSeq;
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -125,7 +125,7 @@ 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.
@@ -235,10 +235,10 @@ Error:
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;
}
@@ -256,7 +256,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
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);
return NULL;
@@ -284,9 +284,10 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
cmsStageFree(NewMPE);
return NULL;
}
}
return NewMPE;
return NewMPE;
}
@@ -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);
@@ -496,10 +499,15 @@ 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,
@@ -508,8 +516,14 @@ void* CLUTElemDup(cmsStage* mpe)
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;
}
@@ -543,12 +557,19 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID,
_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;
@@ -599,7 +620,6 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID,
for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
Dimensions[i] = nGridPoints;
return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table);
}
@@ -630,12 +650,17 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c
_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;
}
@@ -731,15 +752,22 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
int i, t, nTotalPoints, index, rest;
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);
@@ -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];
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);
@@ -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;
}
@@ -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
// ********************************************************************************
@@ -1117,12 +1231,22 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
NULL);
if (NewMPE == NULL) return NULL;
NewMPE ->Implements = mpe ->Implements;
NewMPE ->Implements = mpe ->Implements;
if (mpe ->DupElemPtr) {
NewMPE ->Data = mpe ->DupElemPtr(mpe);
if (NewMPE->Data == NULL) {
cmsStageFree(NewMPE);
return NULL;
}
} else {
if (mpe ->DupElemPtr)
NewMPE ->Data = mpe ->DupElemPtr(mpe);
else
NewMPE ->Data = NULL;
}
return NewMPE;
}
@@ -1229,14 +1353,21 @@ 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;
}
@@ -1264,6 +1395,7 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* lut)
// 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);
}
@@ -1271,6 +1403,7 @@ void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out
// 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);
}
@@ -1286,6 +1419,8 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
if (lut == NULL) return NULL;
NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels);
if (NewLUT == NULL) return NULL;
for (mpe = lut ->Elements;
mpe != NULL;
mpe = mpe ->Next) {
@@ -1308,8 +1443,10 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
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)
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) {
@@ -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
@@ -1415,7 +1554,7 @@ 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
// the number of channels
@@ -1430,17 +1569,12 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
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,13 +1613,13 @@ 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)
_cmsFreeUserDataFn FreePrivateDataFn,
_cmsDupUserDataFn DupPrivateDataFn)
{
Lut ->Eval16Fn = Eval16;
@@ -1570,16 +1704,11 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
cmsFloat32Number fx[4], x[4], xd[4], fxd[4];
cmsVEC3 tmp, tmp2;
cmsMAT3 Jacobian;
cmsFloat64Number LastResult[4];
// 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) {
@@ -1663,3 +1792,4 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
return TRUE;
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -267,7 +267,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile)
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
_cmsICCPROFILE Keep;
_cmsAssert(hProfile != NULL);
_cmsAssert(hProfile != NULL);
ContextID = cmsGetProfileContextID(hProfile);
@@ -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;

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -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;
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -32,29 +32,29 @@
// 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;
}
@@ -62,48 +62,48 @@ cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
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;
@@ -120,17 +120,17 @@ int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number Co
{
int i;
// Sanity check
if (mlu == NULL) return -1;
// Sanity check
if (mlu == NULL) return -1;
// Iterate whole table
// Iterate whole table
for (i=0; i < mlu ->UsedEntries; i++) {
if (mlu ->Entries[i].Country == CountryCode &&
mlu ->Entries[i].Language == LanguageCode) return i;
}
// Not found
// Not found
return -1;
}
@@ -143,8 +143,8 @@ cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
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,17 +155,17 @@ 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;
Ptr = (cmsUInt8Number*) mlu ->MemPool;
if (Ptr == NULL) return FALSE;
// Set the entry
// Set the entry
memmove(Ptr + Offset, Block, size);
mlu ->PoolUsed += size;
@@ -209,7 +209,7 @@ cmsUInt32Number mywcslen(const wchar_t *s)
{
const wchar_t *p;
p = s;
p = s;
while (*p)
p++;
@@ -225,7 +225,7 @@ cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char
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,59 +234,59 @@ 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);
}
}
@@ -294,13 +294,13 @@ void CMSEXPORT cmsMLUfree(cmsMLU* mlu)
// 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)
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,8 +316,8 @@ 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;
@@ -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)
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
@@ -381,23 +381,23 @@ 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)
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);
@@ -414,7 +414,7 @@ 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);
}
@@ -422,27 +422,56 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
// 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])
const char LanguageCode[3], const char CountryCode[3],
char ObtainedLanguage[3], char ObtainedCountry[3])
{
const wchar_t *Wide;
const wchar_t *Wide;
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
cmsUInt16Number ObtLang, ObtCode;
// Sanitize
// Sanitize
if (mlu == NULL) return FALSE;
Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
if (Wide == NULL) return FALSE;
if (Wide == NULL) return FALSE;
// Get used language and code
// Get used language and code
*(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang);
*(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
*(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
ObtainedLanguage[2] = ObtainedCountry[2] = 0;
return TRUE;
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;
}
@@ -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;
@@ -498,8 +529,9 @@ 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)
@@ -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;
@@ -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)
{
@@ -636,15 +689,15 @@ void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const c
// 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));
cmsSigNamedColorElemType,
1, UsePCS ? 3 : NamedColorList ->ColorantCount,
UsePCS ? EvalNamedColorPCS : EvalNamedColor,
DupNamedColorList,
FreeNamedColorList,
cmsDupNamedColorList(NamedColorList));
}
@@ -680,6 +733,10 @@ cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUI
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;
@@ -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;
}

View File

@@ -2,7 +2,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"),
@@ -53,10 +53,6 @@ typedef struct {
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];
@@ -174,8 +170,6 @@ 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);
@@ -219,6 +219,7 @@ 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++) {
@@ -226,11 +227,11 @@ void PrelinEval16(register const cmsUInt16Number Input[],
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);
@@ -255,7 +255,6 @@ void* Prelin16dup(cmsContext ContextID, const void* ptr)
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* ));
@@ -270,7 +269,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
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;
@@ -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* ));
@@ -379,46 +377,58 @@ 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
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
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;
@@ -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[] )
{
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;
@@ -463,6 +475,8 @@ 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);
@@ -498,8 +512,14 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor
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 {
@@ -525,8 +545,9 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor
static
cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
cmsPipeline* Src;
cmsPipeline* Dest;
cmsPipeline* Src = NULL;
cmsPipeline* Dest = NULL;
cmsStage* mpe;
cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
int nGridPoints;
@@ -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,6 +572,13 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
Src = *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;
@@ -570,7 +597,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// 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) {
@@ -600,7 +630,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// 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);
@@ -611,10 +642,18 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// 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;
}
@@ -641,12 +680,11 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
else {
p16 = PrelinOpt16alloc(Dest ->ContextID,
DataCLUT ->Params,
Dest ->InputChannels,
DataSetIn,
Dest ->OutputChannels,
DataSetOut);
DataCLUT ->Params,
Dest ->InputChannels,
DataSetIn,
Dest ->OutputChannels,
DataSetOut);
_cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
}
@@ -789,8 +827,8 @@ void PrelinEval8(register const cmsUInt16Number Input[],
cmsUInt8Number r, g, b;
cmsS15Fixed16Number rx, ry, rz;
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
int OutChan;
register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
int OutChan;
register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
int TotalOut = p -> nOutputs;
@@ -864,15 +902,35 @@ void PrelinEval8(register const cmsUInt16Number Input[],
}
Rest = c1 * rx + c2 * ry + c3 * rz;
Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16);
}
}
#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
@@ -889,6 +947,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
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);
@@ -953,6 +1020,9 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
// Exclude if non-monotonic
if (!cmsIsToneCurveMonotonic(Trans[t]))
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);
@@ -977,13 +1048,15 @@ 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);
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;
@@ -1112,6 +1185,16 @@ 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++) {
@@ -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,6 +1339,7 @@ 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);
}
@@ -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);
@@ -1385,12 +1472,12 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
// 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);
}
}
@@ -1493,10 +1580,14 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (!Dest) return FALSE;
// Assamble the new LUT
cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1));
if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)))
goto Error;
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_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) {
@@ -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;
}
@@ -1544,44 +1639,102 @@ 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* OutputFormat,
cmsUInt32Number* dwFlags)
{
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
@@ -1611,8 +1764,8 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
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) {
@@ -1623,6 +1776,17 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
}
}
// 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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
@@ -869,8 +869,11 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
{
switch (ColorSpace) {
case cmsSigMCH1Data:
case cmsSig1colorData:
case cmsSigGrayData: return 1;
case cmsSigMCH2Data:
case cmsSig2colorData: return 2;
case cmsSigXYZData:
@@ -882,10 +885,12 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
case cmsSigHsvData:
case cmsSigHlsData:
case cmsSigCmyData:
case cmsSigMCH3Data:
case cmsSig3colorData: return 3;
case cmsSigLuvKData:
case cmsSigCmykData:
case cmsSigMCH4Data:
case cmsSig4colorData: return 4;
case cmsSigMCH5Data:

View File

@@ -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);
@@ -96,10 +96,14 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number Q
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
}
@@ -189,7 +193,7 @@ cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
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;
}
@@ -311,7 +315,7 @@ cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
{
cmsUInt64Number tmp;
@@ -511,20 +515,34 @@ 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;
@@ -533,56 +551,64 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
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;
}
}
@@ -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);
}

View File

@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -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;
int FirstComponent;
int SecondComponent;
const char* PreMaj;
const char* PostMaj;
const char* PreMin;
const char* PostMin;
const char* PreMaj;
const char* PostMaj;
const char* PreMin;
const char* PostMin;
int FixWhite; // Force mapping of pure white
int FixWhite; // Force mapping of pure white
cmsColorSpaceSignature ColorSpace; // ColorSpace of profile
cmsColorSpaceSignature ColorSpace; // ColorSpace of profile
} cmsPsSamplerCargo;
@@ -300,9 +300,9 @@ 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,14 +313,14 @@ 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
@@ -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];
cmsMLU *Description, *Copyright;
char DescASCII[256], CopyrightASCII[256];
time(&timer);
Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
DescASCII[0] = DescASCII[255] = 0;
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");
@@ -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;
@@ -495,7 +496,7 @@ 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
@@ -548,12 +549,14 @@ void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
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]);
Emit1Gamma(m, g[i]);
}
}
@@ -638,21 +641,21 @@ int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Nu
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
// We always deal with Lab4
wByteOut = Word2Byte(wWordOut);
WriteByte(sc -> m, wByteOut);
}
wByteOut = Word2Byte(wWordOut);
WriteByte(sc -> m, wByteOut);
}
return 1;
return 1;
}
// Writes a Pipeline on memstream. Could be 8 or 16 bits based
@@ -670,7 +673,7 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
sc.FirstComponent = -1;
sc.SecondComponent = -1;
sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
sc.m = m;
sc.PreMaj = PreMaj;
sc.PostMaj= PostMaj;
@@ -682,8 +685,8 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
_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");
@@ -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;
int i;
_cmsIOPrintf(m, "[ /CIEBasedABC\n");
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/DecodeABC [ ");
_cmsIOPrintf(m, "[ /CIEBasedABC\n");
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/DecodeABC [ ");
EmitNGamma(m, 3, CurveSet);
EmitNGamma(m, 3, CurveSet);
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/MatrixABC [ " );
_cmsIOPrintf(m, "/MatrixABC [ " );
for( i=0; i < 3; i++ ) {
for( i=0; i < 3; i++ ) {
_cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
Matrix[i + 3*1],
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,12 +773,11 @@ 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");
@@ -797,18 +799,16 @@ 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 ");
WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
@@ -822,28 +822,29 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY
_cmsIOPrintf(m, " >>\n");
_cmsIOPrintf(m, "]\n");
return 1;
}
// 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++) {
if (Out != NULL) {
for (i=0; i < 256; i++) {
cmsUInt8Number Gray = (cmsUInt8Number) i;
cmsCIEXYZ XYZ;
cmsUInt8Number Gray = (cmsUInt8Number) i;
cmsCIEXYZ XYZ;
cmsDoTransform(xform, &Gray, &XYZ, 1);
cmsDoTransform(xform, &Gray, &XYZ, 1);
Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
}
}
cmsDeleteTransform(xform);
@@ -874,29 +875,29 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu
nChannels = T_CHANNELS(InputFormat);
cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
// Adjust output to Lab4
// 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);
xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0);
cmsCloseProfile(hLab);
if (xform == NULL) {
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);
cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
cmsFreeToneCurve(Gray2Y);
}
@@ -904,24 +905,25 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu
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(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
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;
}
@@ -955,8 +957,8 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
if (ColorSpace == cmsSigGrayData) {
cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
}
else
@@ -972,16 +974,16 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat,
_cmsStageGetPtrToCurveSet(Shaper),
&BlackPointAdaptedToD50);
_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;
}
@@ -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");
@@ -1040,66 +1042,66 @@ 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)
cmsHPROFILE hProfile,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags,
cmsIOHANDLER* mem)
{
cmsUInt32Number dwBytesUsed;
cmsPipeline* lut = NULL;
cmsStage* Matrix, *Shaper;
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)
@@ -1176,15 +1178,15 @@ void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsol
if (lIsAbsolute) {
// For absolute colorimetric intent, encode back to relative
// and generate a relative Pipeline
// 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"
@@ -1192,7 +1194,7 @@ void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsol
"{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);
White.X, White.Y, White.Z);
return;
}
@@ -1285,50 +1287,50 @@ 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;
cmsUInt32Number InFrm = TYPE_Lab_16;
int RelativeEncodingIntent;
cmsColorSpaceSignature ColorSpace;
hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
if (hLab == NULL) return 0;
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;
if (DeviceLink == NULL) return 0;
// We need a CLUT
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
// We need a CLUT
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/ColorRenderingType 1\n");
@@ -1413,19 +1415,19 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cms
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");
@@ -1468,128 +1470,128 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cms
static
cmsUInt32Number GenerateCRD(cmsContext ContextID,
cmsHPROFILE hProfile,
cmsUInt32Number Intent, cmsUInt32Number dwFlags,
cmsIOHANDLER* mem)
cmsHPROFILE hProfile,
cmsUInt32Number Intent, cmsUInt32Number dwFlags,
cmsIOHANDLER* mem)
{
cmsUInt32Number dwBytesUsed;
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)
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;
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;
}
default:
case cmsPS_RESOURCE_CRD:
rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
break;
}
return rc;
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);
dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem);
// Get rid of memory stream
cmsCloseIOhandler(mem);
cmsCloseIOhandler(mem);
return dwBytesUsed;
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)
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);
dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem);
// Get rid of memory stream
cmsCloseIOhandler(mem);
cmsCloseIOhandler(mem);
return dwBytesUsed;
return dwBytesUsed;
}

View File

@@ -27,6 +27,8 @@
#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.
@@ -38,13 +40,13 @@
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;
@@ -112,8 +114,8 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
cmsCloseProfile(hLab);
if (xform == NULL) {
// Something went wrong. Get rid of open resources and return zero as black
// Something went wrong. Get rid of open resources and return zero as black
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
@@ -144,7 +146,6 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
static
cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile)
{
cmsHTRANSFORM hRoundTrip;
cmsCIELab LabIn, LabOut;
@@ -187,20 +188,29 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi
// 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) {
// 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;
}
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)) {
@@ -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;
}

View File

@@ -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"),
@@ -170,10 +170,10 @@ 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) );
if (*alpha >= SECTORS)
*alpha = SECTORS-1;
if (*theta >= SECTORS)
*theta = SECTORS-1;
if (*alpha >= SECTORS)
*alpha = SECTORS-1;
if (*theta >= SECTORS)
*theta = SECTORS-1;
}
@@ -326,8 +326,8 @@ cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp)
// 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
_cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b);
@@ -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++) {
@@ -476,7 +477,7 @@ cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta)
cmsVEC3 Centre;
cmsLine ray;
int nCloseSectors;
cmsGDBPoint* Close[NSTEPS];
cmsGDBPoint* Close[NSTEPS + 1];
cmsSpherical closel, templ;
cmsLine edge;
int k, m;
@@ -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;
}
@@ -708,10 +709,10 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname)
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))
fprintf (fp, "]\n");

File diff suppressed because it is too large Load Diff

View File

@@ -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"),
@@ -114,7 +114,7 @@ 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);
@@ -179,9 +179,26 @@ 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) {
@@ -218,7 +235,7 @@ cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID,
if (!hICC) // can't allocate
return NULL;
cmsSetProfileVersion(hICC, 4.2);
cmsSetProfileVersion(hICC, 4.3);
cmsSetDeviceClass(hICC, cmsSigDisplayClass);
cmsSetColorSpace(hICC, cmsSigGrayData);
@@ -274,14 +291,13 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
{
cmsHPROFILE hICC;
cmsPipeline* Pipeline;
cmsStage* Lin;
int nChannels;
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC)
return NULL;
cmsSetProfileVersion(hICC, 4.2);
cmsSetProfileVersion(hICC, 4.3);
cmsSetDeviceClass(hICC, cmsSigLinkClass);
cmsSetColorSpace(hICC, ColorSpace);
@@ -298,10 +314,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
// Copy tables to Pipeline
Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions);
if (Lin == NULL) goto Error;
cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin);
if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions)))
goto Error;
// Create tags
if (!SetTextTags(hICC, L"Linearization built-in")) goto Error;
@@ -315,6 +329,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
return hICC;
Error:
cmsPipelineFree(Pipeline);
if (hICC)
cmsCloseProfile(hICC);
@@ -401,7 +416,7 @@ 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);
@@ -422,9 +437,10 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
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;
@@ -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);
@@ -509,7 +526,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE
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);
@@ -554,7 +572,7 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID)
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);
@@ -705,81 +724,83 @@ 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;
cmsSetDeviceClass(hICC, cmsSigAbstractClass);
cmsSetColorSpace(hICC, cmsSigLabData);
cmsSetPCS(hICC, cmsSigLabData);
cmsWhitePointFromTemp(&WhitePnt, TempSrc );
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
cmsWhitePointFromTemp(&WhitePnt, TempDest);
cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt);
// Creates a Pipeline with 3D grid only
Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
if (Pipeline == NULL) {
cmsCloseProfile(hICC);
return NULL;
}
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC) // can't allocate
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;
cmsSetDeviceClass(hICC, cmsSigAbstractClass);
cmsSetColorSpace(hICC, cmsSigLabData);
cmsSetPCS(hICC, cmsSigLabData);
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
// Shouldn't reach here
goto Error;
}
if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
goto Error;
}
// Creates a Pipeline with 3D grid only
Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
if (Pipeline == NULL) {
cmsCloseProfile(hICC);
return NULL;
}
// Create tags
if (!SetTextTags(hICC, L"BCHS built-in")) 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;
cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
// Pipeline is already on virtual profile
cmsPipelineFree(Pipeline);
// Shouldn't reach here
cmsPipelineFree(Pipeline);
cmsCloseProfile(hICC);
return NULL;
}
// Ok, done
return hICC;
cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT);
// Create tags
if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
// Pipeline is already on virtual profile
cmsPipelineFree(Pipeline);
// Ok, done
return hICC;
Error:
cmsPipelineFree(Pipeline);
cmsCloseProfile(hICC);
return NULL;
}
@@ -809,7 +830,7 @@ 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;
@@ -827,7 +848,8 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
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;
@@ -934,6 +956,11 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
// 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 } },
@@ -997,7 +1025,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
static
const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag)
{
int n;
cmsUInt32Number n;
for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) {
@@ -1025,6 +1053,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
cmsContext ContextID = cmsGetTransformContextID(hTransform);
const cmsAllowedLUT* AllowedLUT;
cmsTagSignature DestinationTag;
cmsProfileClassSignature deviceClass;
_cmsAssert(hTransform != NULL);
@@ -1046,13 +1075,15 @@ 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;
}
@@ -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);
}
@@ -1134,10 +1168,22 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
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;
}
// 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;

View File

@@ -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"),
@@ -47,48 +47,48 @@ 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;
}
@@ -143,46 +143,46 @@ 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;
}
@@ -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,45 +278,45 @@ 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);
}
@@ -324,28 +324,28 @@ cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, con
// 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)
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;
}

View File

@@ -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"),
@@ -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,11 +165,13 @@ 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,
@@ -102,7 +180,20 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
{
_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) {
@@ -154,7 +245,31 @@ void FloatXFORM(_cmsTRANSFORM* p,
}
// 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;
@@ -200,14 +316,14 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Size);
accum = p -> FromInput(p, wIn, accum, Stride);
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
output = p -> ToOutput(p, wOut, output, Size);
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[],
@@ -219,9 +335,12 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
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);
@@ -231,7 +350,7 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
static
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size)
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -244,9 +363,9 @@ 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);
}
}
@@ -255,13 +374,13 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
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 {
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,52 +435,211 @@ 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);
accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) {
memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
}
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) {
@@ -378,21 +648,28 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo
return NULL;
}
// Float transforms don't use cach<63>, always are non-NULL
p ->xform = FloatXFORM;
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullFloatXFORM;
}
else {
// Float transforms don't use cach<63>, 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) {
@@ -403,25 +680,25 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo
BytesPerPixelInput = T_BYTES(p ->InputFormat);
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
*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<63>
else
p ->xform = PrecalculatedXFORM; // No cach<63>, no gamut check
}
else {
if (dwFlags & cmsFLAGS_GAMUTCHECK)
if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = CachedXFORMGamutCheck; // Gamut check, cach<63>
else
p ->xform = CachedXFORM; // No gamut check, cach<63>
@@ -430,14 +707,11 @@ _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;
}
@@ -448,36 +722,49 @@ cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpac
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);
}
if (i==0)
*Input = ColorSpaceIn;
PostColorSpace = ColorSpaceOut;
}
*Output = PostColorSpace;
return TRUE;
return TRUE;
}
// Check colorspace
@@ -498,6 +785,22 @@ 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[],
@@ -511,28 +814,31 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
cmsUInt32Number dwFlags)
{
_cmsTRANSFORM* xform;
cmsBool FloatTransform;
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)) {
@@ -552,21 +858,29 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
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
@@ -613,14 +927,14 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
// 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);
}
}
@@ -629,7 +943,6 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
}
// 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);
}
@@ -731,7 +1044,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
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;
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);
@@ -772,7 +1085,22 @@ 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,
@@ -782,18 +1110,17 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
_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;
}

View File

@@ -63,9 +63,11 @@ _cmsDefaultICCintents = _cmsDefaultICCintents
cmsDeleteTransform = cmsDeleteTransform
cmsDeltaE = cmsDeltaE
cmsDetectBlackPoint = cmsDetectBlackPoint
cmsDetectDestinationBlackPoint = cmsDetectDestinationBlackPoint
cmsDetectTAC = cmsDetectTAC
cmsDesaturateLab = cmsDesaturateLab
cmsDoTransform = cmsDoTransform
cmsDoTransformStride = cmsDoTransformStride
_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16
_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8
_cmsDupMem = _cmsDupMem
@@ -74,6 +76,8 @@ cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription
cmsDupToneCurve = cmsDupToneCurve
_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber
cmsEstimateGamma = cmsEstimateGamma
cmsGetToneCurveEstimatedTableEntries = cmsGetToneCurveEstimatedTableEntries
cmsGetToneCurveEstimatedTable = cmsGetToneCurveEstimatedTable
cmsEvalToneCurve16 = cmsEvalToneCurve16
cmsEvalToneCurveFloat = cmsEvalToneCurveFloat
cmsfilelength = cmsfilelength
@@ -110,12 +114,12 @@ cmsGetPostScriptCRD = cmsGetPostScriptCRD
cmsGetPostScriptCSA = cmsGetPostScriptCSA
cmsGetProfileInfo = cmsGetProfileInfo
cmsGetProfileInfoASCII = cmsGetProfileInfoASCII
cmsGetProfileContextID = cmsGetProfileContextID
cmsGetProfileContextID = cmsGetProfileContextID
cmsGetProfileVersion = cmsGetProfileVersion
cmsGetSupportedIntents = cmsGetSupportedIntents
cmsGetTagCount = cmsGetTagCount
cmsGetTagSignature = cmsGetTagSignature
cmsGetTransformContextID = cmsGetTransformContextID
cmsGetTransformContextID = cmsGetTransformContextID
_cmsICCcolorSpace = _cmsICCcolorSpace
_cmsIOPrintf = _cmsIOPrintf
cmsIsCLUT = cmsIsCLUT
@@ -131,15 +135,18 @@ cmsIT8Alloc = cmsIT8Alloc
cmsIT8DefineDblFormat = cmsIT8DefineDblFormat
cmsIT8EnumDataFormat = cmsIT8EnumDataFormat
cmsIT8EnumProperties = cmsIT8EnumProperties
cmsIT8EnumPropertyMulti = cmsIT8EnumPropertyMulti
cmsIT8Free = cmsIT8Free
cmsIT8GetData = cmsIT8GetData
cmsIT8GetDataDbl = cmsIT8GetDataDbl
cmsIT8FindDataFormat = cmsIT8FindDataFormat
cmsIT8FindDataFormat = cmsIT8FindDataFormat
cmsIT8GetDataRowCol = cmsIT8GetDataRowCol
cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl
cmsIT8GetPatchName = cmsIT8GetPatchName
cmsIT8GetPatchByName = cmsIT8GetPatchByName
cmsIT8GetProperty = cmsIT8GetProperty
cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl
cmsIT8GetPropertyMulti = cmsIT8GetPropertyMulti
cmsIT8GetSheetType = cmsIT8GetSheetType
cmsIT8LoadFromFile = cmsIT8LoadFromFile
cmsIT8LoadFromMem = cmsIT8LoadFromMem
@@ -154,10 +161,12 @@ 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
@@ -167,6 +176,7 @@ cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2
cmsLCh2Lab = cmsLCh2Lab
_cmsLCMScolorSpace = _cmsLCMScolorSpace
cmsLinkTag = cmsLinkTag
cmsTagLinkedTo = cmsTagLinkedTo
cmsPipelineAlloc = cmsPipelineAlloc
cmsPipelineCat = cmsPipelineCat
cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages
@@ -291,10 +301,41 @@ _cmsWriteUInt32Number = _cmsWriteUInt32Number
_cmsWriteUInt64Number = _cmsWriteUInt64Number
_cmsWriteUInt8Number = _cmsWriteUInt8Number
_cmsWriteXYZNumber = _cmsWriteXYZNumber
cmsxyY2XYZ = cmsxyY2XYZ
cmsXYZ2Lab = cmsXYZ2Lab
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

View File

@@ -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"),
@@ -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,7 +67,7 @@
#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)
@@ -88,36 +90,6 @@
# 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 <windows.h>
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 <pthread.h>
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))
@@ -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 <windows.h>
// 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 <pthread.h>
#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,9 +382,264 @@ 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 {
@@ -260,7 +647,7 @@ typedef struct {
cmsUInt16Number Country;
cmsUInt32Number StrW; // Offset to current unicode string
cmsUInt32Number Len; // Lenght in bytes
cmsUInt32Number Len; // Length in bytes
} _cmsMLUentry;
@@ -327,9 +714,11 @@ typedef struct _cms_iccprofile_struct {
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 ----------------------------------------------------------------------------------------------------------------
@@ -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,9 +816,13 @@ 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
cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
@@ -477,12 +843,12 @@ struct _cmsPipeline_struct {
_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 -------------------------------------------------------------------------------------------
@@ -525,7 +891,8 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
cmsUInt16Number **Black,
cmsUInt32Number *nOutputs);
cmsBool _cmsOptimizePipeline(cmsPipeline** Lut,
cmsBool _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** Lut,
int Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
@@ -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
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 {
@@ -586,17 +960,13 @@ typedef struct _cmstransform_struct {
cmsFormatterFloat FromInputFloat;
cmsFormatterFloat ToOutputFloat;
// 1-pixel cache (16 bits only)
cmsUInt16Number CacheIn[cmsMAXCHANNELS];
cmsUInt16Number CacheOut[cmsMAXCHANNELS];
// 1-pixel cache seed for zero as input (16 bits, read only)
_cmsCACHE Cache;
// Semaphor for cache
LCMS_RWLOCK_T rwlock;
// A MPE LUT holding the full (optimized) transform
// 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
@@ -607,6 +977,10 @@ typedef struct _cmstransform_struct {
cmsColorSpaceSignature EntryColorSpace;
cmsColorSpaceSignature ExitColorSpace;
// White points (informative only)
cmsCIEXYZ EntryWhitePoint;
cmsCIEXYZ ExitWhitePoint;
// Profiles used to create the transform
cmsSEQ* Sequence;
@@ -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;
// --------------------------------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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 = "<long 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 */

4362
thirdparty/libpng/png.c vendored

File diff suppressed because it is too large Load Diff

3397
thirdparty/libpng/png.h vendored

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More