libs: Import code from upstream lcms2 2.12.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-10-19 11:24:03 +02:00
parent d36615ee52
commit f550f624b2
29 changed files with 32719 additions and 0 deletions

26
configure vendored
View File

@ -707,6 +707,8 @@ TIFF_PE_LIBS
TIFF_PE_CFLAGS
PNG_PE_LIBS
PNG_PE_CFLAGS
LCMS2_PE_LIBS
LCMS2_PE_CFLAGS
JPEG_PE_LIBS
JPEG_PE_CFLAGS
EXCESS_PRECISION_CFLAGS
@ -1785,6 +1787,7 @@ enable_dxerr8
enable_dxerr9
enable_dxguid
enable_jpeg
enable_lcms2
enable_mfuuid
enable_png
enable_strmiids
@ -1926,6 +1929,8 @@ OBJCFLAGS
OBJCPP
JPEG_PE_CFLAGS
JPEG_PE_LIBS
LCMS2_PE_CFLAGS
LCMS2_PE_LIBS
PNG_PE_CFLAGS
PNG_PE_LIBS
TIFF_PE_CFLAGS
@ -2714,6 +2719,11 @@ Some influential environment variables:
C compiler flags for the PE jpeg, overriding the bundled version
JPEG_PE_LIBS
Linker flags for the PE jpeg, overriding the bundled version
LCMS2_PE_CFLAGS
C compiler flags for the PE lcms2, overriding the bundled
version
LCMS2_PE_LIBS
Linker flags for the PE lcms2, overriding the bundled version
PNG_PE_CFLAGS
C compiler flags for the PE png, overriding the bundled version
PNG_PE_LIBS Linker flags for the PE png, overriding the bundled version
@ -10720,6 +10730,19 @@ fi
$as_echo "$as_me:${as_lineno-$LINENO}: jpeg cflags: $JPEG_PE_CFLAGS" >&5
$as_echo "$as_me:${as_lineno-$LINENO}: jpeg libs: $JPEG_PE_LIBS" >&5
if ${LCMS2_PE_CFLAGS:+false} :; then :
LCMS2_PE_CFLAGS="-I\$(top_srcdir)/libs/lcms2/include"
else
enable_lcms2=no
fi
if ${LCMS2_PE_LIBS:+false} :; then :
LCMS2_PE_LIBS=lcms2
else
enable_lcms2=no
fi
$as_echo "$as_me:${as_lineno-$LINENO}: lcms2 cflags: $LCMS2_PE_CFLAGS" >&5
$as_echo "$as_me:${as_lineno-$LINENO}: lcms2 libs: $LCMS2_PE_LIBS" >&5
if ${PNG_PE_CFLAGS:+false} :; then :
PNG_PE_CFLAGS="-I\$(top_srcdir)/libs/png"
else
@ -19487,6 +19510,8 @@ METAL_LIBS = $METAL_LIBS
EXCESS_PRECISION_CFLAGS = $EXCESS_PRECISION_CFLAGS
JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS
JPEG_PE_LIBS = $JPEG_PE_LIBS
LCMS2_PE_CFLAGS = $LCMS2_PE_CFLAGS
LCMS2_PE_LIBS = $LCMS2_PE_LIBS
PNG_PE_CFLAGS = $PNG_PE_CFLAGS
PNG_PE_LIBS = $PNG_PE_LIBS
TIFF_PE_CFLAGS = $TIFF_PE_CFLAGS
@ -20782,6 +20807,7 @@ wine_fn_config_makefile libs/dxerr8 enable_dxerr8
wine_fn_config_makefile libs/dxerr9 enable_dxerr9
wine_fn_config_makefile libs/dxguid enable_dxguid
wine_fn_config_makefile libs/jpeg enable_jpeg
wine_fn_config_makefile libs/lcms2 enable_lcms2
wine_fn_config_makefile libs/mfuuid enable_mfuuid
wine_fn_config_makefile libs/png enable_png
wine_fn_config_makefile libs/strmiids enable_strmiids

View File

@ -1062,6 +1062,7 @@ WINE_NOTICE_WITH(mingw,[test "x$CROSSTARGET" = "x"],
dnl **** External libraries ****
WINE_EXTLIB_FLAGS(JPEG, jpeg, jpeg, "-I\$(top_srcdir)/libs/jpeg")
WINE_EXTLIB_FLAGS(LCMS2, lcms2, lcms2, "-I\$(top_srcdir)/libs/lcms2/include")
WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png")
WINE_EXTLIB_FLAGS(TIFF, tiff, tiff, "-I\$(top_srcdir)/libs/tiff/libtiff")
WINE_EXTLIB_FLAGS(ZLIB, zlib, z, "-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO")
@ -3781,6 +3782,7 @@ WINE_CONFIG_MAKEFILE(libs/dxerr8)
WINE_CONFIG_MAKEFILE(libs/dxerr9)
WINE_CONFIG_MAKEFILE(libs/dxguid)
WINE_CONFIG_MAKEFILE(libs/jpeg)
WINE_CONFIG_MAKEFILE(libs/lcms2)
WINE_CONFIG_MAKEFILE(libs/mfuuid)
WINE_CONFIG_MAKEFILE(libs/png)
WINE_CONFIG_MAKEFILE(libs/strmiids)

53
libs/lcms2/AUTHORS Normal file
View File

@ -0,0 +1,53 @@
Main Author
------------
Marti Maria
Contributors
------------
Bob Friesenhahn
Kai-Uwe Behrmann
Stuart Nixon
Jordi Vilar
Richard Hughes
Auke Nauta
Chris Evans (Google)
Lorenzo Ridolfi
Robin Watts (Artifex)
Shawn Pedersen
Andrew Brygin
Samuli Suominen
Florian Höch
Aurelien Jarno
Claudiu Cebuc
Michael Vhrel (Artifex)
Michal Cihar
Daniel Kaneider
Mateusz Jurczyk (Google)
Paul Miller
Sébastien Léon
Christian Schmitz
XhmikosR
Stanislav Brabec (SuSe)
Leonhard Gruenschloss (Google)
Patrick Noffke
Christopher James Halse Rogers
John Hein
Thomas Weber (Debian)
Mark Allen
Noel Carboni
Sergei Trofimovic
Philipp Knechtges
Special Thanks
--------------
Artifex software
AlienSkin software
Jan Morovic
Jos Vernon (WebSupergoo)
Harald Schneider (Maxon)
Christian Albrecht
Dimitrios Anastassakis
Lemke Software
Tim Zaman

21
libs/lcms2/COPYING Normal file
View File

@ -0,0 +1,21 @@
Little CMS
Copyright (c) 1998-2020 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.

25
libs/lcms2/Makefile.in Normal file
View File

@ -0,0 +1,25 @@
EXTLIB = liblcms2.a
EXTRAINCL = -I$(srcdir)/include
C_SRCS = \
src/cmsalpha.c \
src/cmscnvrt.c \
src/cmserr.c \
src/cmsgamma.c \
src/cmsgmt.c \
src/cmshalf.c \
src/cmsintrp.c \
src/cmsio0.c \
src/cmsio1.c \
src/cmslut.c \
src/cmsmtrx.c \
src/cmsnamed.c \
src/cmsopt.c \
src/cmspack.c \
src/cmspcs.c \
src/cmsplugin.c \
src/cmssamp.c \
src/cmstypes.c \
src/cmsvirt.c \
src/cmswtpnt.c \
src/cmsxform.c

1922
libs/lcms2/include/lcms2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,680 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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.
//
//---------------------------------------------------------------------------------
//
// This is the plug-in header file. Normal LittleCMS clients should not use it.
// It is provided for plug-in writters that may want to access the support
// functions to do low level operations. All plug-in related structures
// are defined here. Including this file forces to include the standard API too.
#ifndef _lcms_plugin_H
// Deal with Microsoft's attempt at deprecating C standard runtime functions
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
# ifndef _CRT_SECURE_NO_DEPRECATE
# define _CRT_SECURE_NO_DEPRECATE
# endif
# ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
# endif
# endif
#endif
#ifndef _lcms2_H
#include "lcms2.h"
#endif
// We need some standard C functions.
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <memory.h>
#include <string.h>
#ifndef CMS_USE_CPP_API
# ifdef __cplusplus
extern "C" {
# endif
#endif
// Vector & Matrix operations -----------------------------------------------------------------------
// Axis of the matrix/array. No specific meaning at all.
#define VX 0
#define VY 1
#define VZ 2
// Vectors
typedef struct {
cmsFloat64Number n[3];
} cmsVEC3;
// 3x3 Matrix
typedef struct {
cmsVEC3 v[3];
} cmsMAT3;
CMSAPI void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z);
CMSAPI void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b);
CMSAPI void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v);
CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v);
CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a);
CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b);
CMSAPI void CMSEXPORT _cmsMAT3identity(cmsMAT3* a);
CMSAPI cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a);
CMSAPI void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b);
CMSAPI cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b);
CMSAPI cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b);
CMSAPI void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v);
// MD5 low level -------------------------------------------------------------------------------------
CMSAPI cmsHANDLE CMSEXPORT cmsMD5alloc(cmsContext ContextID);
CMSAPI void CMSEXPORT cmsMD5add(cmsHANDLE Handle, const cmsUInt8Number* buf, cmsUInt32Number len);
CMSAPI void CMSEXPORT cmsMD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle);
// Error logging -------------------------------------------------------------------------------------
CMSAPI void WINAPIV cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...);
// Memory management ----------------------------------------------------------------------------------
CMSAPI void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size);
CMSAPI void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size);
CMSAPI void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
CMSAPI void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
CMSAPI void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr);
CMSAPI void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size);
// I/O handler ----------------------------------------------------------------------------------
struct _cms_io_handler {
void* stream; // Associated stream, which is implemented differently depending on media.
cmsContext ContextID;
cmsUInt32Number UsedSpace;
cmsUInt32Number ReportedSize;
char PhysicalFile[cmsMAX_PATH];
cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer,
cmsUInt32Number size,
cmsUInt32Number count);
cmsBool (* Seek)(struct _cms_io_handler* iohandler, cmsUInt32Number offset);
cmsBool (* Close)(struct _cms_io_handler* iohandler);
cmsUInt32Number (* Tell)(struct _cms_io_handler* iohandler);
cmsBool (* Write)(struct _cms_io_handler* iohandler, cmsUInt32Number size,
const void* Buffer);
};
// Endianness adjust functions
CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word);
CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value);
CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord);
// Helper IO functions
CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n);
CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n);
CMSAPI cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n);
CMSAPI cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n);
CMSAPI cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n);
CMSAPI cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n);
CMSAPI cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ);
CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array);
CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n);
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 _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);
// ICC base tag
typedef struct {
cmsTagTypeSignature sig;
cmsInt8Number reserved[4];
} _cmsTagBase;
// Type base helper functions
CMSAPI cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io);
CMSAPI cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig);
// Alignment functions
CMSAPI cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io);
CMSAPI cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io);
// To deal with text streams. 2K at most
CMSAPI cmsBool WINAPIV _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...);
// Fixed point helper functions
CMSAPI cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8);
CMSAPI cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val);
CMSAPI cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32);
CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v);
// Date/time helper functions
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);
//----------------------------------------------------------------------------------------------------------
// Plug-in foundation
#define cmsPluginMagicNumber 0x61637070 // 'acpp'
#define cmsPluginMemHandlerSig 0x6D656D48 // 'memH'
#define cmsPluginInterpolationSig 0x696E7048 // 'inpH'
#define cmsPluginParametricCurveSig 0x70617248 // 'parH'
#define cmsPluginFormattersSig 0x66726D48 // 'frmH
#define cmsPluginTagTypeSig 0x74797048 // 'typH'
#define cmsPluginTagSig 0x74616748 // 'tagH'
#define cmsPluginRenderingIntentSig 0x696E7448 // 'intH'
#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH'
#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
#define cmsPluginTransformSig 0x7A666D48 // 'xfmH'
#define cmsPluginMutexSig 0x6D747A48 // 'mtxH'
typedef struct _cmsPluginBaseStruct {
cmsUInt32Number Magic; // 'acpp' signature
cmsUInt32Number ExpectedVersion; // Expected version of LittleCMS
cmsUInt32Number Type; // Type of plug-in
struct _cmsPluginBaseStruct* Next; // For multiple plugin definition. NULL for end of list.
} cmsPluginBase;
// Maximum number of types in a plugin array
#define MAX_TYPES_IN_LCMS_PLUGIN 20
//----------------------------------------------------------------------------------------------------------
// 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
_cmsMallocFnPtrType MallocPtr;
_cmsFreeFnPtrType FreePtr;
_cmsReallocFnPtrType ReallocPtr;
// Optional
_cmsMalloZerocFnPtrType MallocZeroPtr;
_cmsCallocFnPtrType CallocPtr;
_cmsDupFnPtrType DupPtr;
} cmsPluginMemHandler;
// ------------------------------------------------------------------------------------------------------------------
// Interpolation. 16 bits and floating point versions.
struct _cms_interp_struc;
// Interpolation callbacks
// 16 bits forward interpolation. This function performs precision-limited linear interpolation
// and is supposed to be quite fast. Implementation may be tetrahedral or trilinear, and plug-ins may
// choose to implement any other interpolation algorithm.
typedef void (* _cmsInterpFn16)(CMSREGISTER const cmsUInt16Number Input[],
CMSREGISTER cmsUInt16Number Output[],
CMSREGISTER const struct _cms_interp_struc* p);
// Floating point forward interpolation. Full precision interpolation using floats. This is not a
// time critical function. Implementation may be tetrahedral or trilinear, and plug-ins may
// choose to implement any other interpolation algorithm.
typedef void (* _cmsInterpFnFloat)(cmsFloat32Number const Input[],
cmsFloat32Number Output[],
const struct _cms_interp_struc* p);
// This type holds a pointer to an interpolator that can be either 16 bits or float
typedef union {
_cmsInterpFn16 Lerp16; // Forward interpolation in 16 bits
_cmsInterpFnFloat LerpFloat; // Forward interpolation in floating point
} cmsInterpFunction;
// Flags for interpolator selection
#define CMS_LERP_FLAGS_16BITS 0x0000 // The default
#define CMS_LERP_FLAGS_FLOAT 0x0001 // Requires different implementation
#define CMS_LERP_FLAGS_TRILINEAR 0x0100 // Hint only
#define MAX_INPUT_DIMENSIONS 15
typedef struct _cms_interp_struc { // Used on all interpolations. Supplied by lcms2 when calling the interpolation function
cmsContext ContextID; // The calling thread
cmsUInt32Number dwFlags; // Keep original flags
cmsUInt32Number nInputs; // != 1 only in 3D interpolation
cmsUInt32Number nOutputs; // != 1 only in 3D interpolation
cmsUInt32Number nSamples[MAX_INPUT_DIMENSIONS]; // Valid on all kinds of tables
cmsUInt32Number Domain[MAX_INPUT_DIMENSIONS]; // Domain = nSamples - 1
cmsUInt32Number opta[MAX_INPUT_DIMENSIONS]; // Optimization for 3D CLUT. This is the number of nodes premultiplied for each
// dimension. For example, in 7 nodes, 7, 7^2 , 7^3, 7^4, etc. On non-regular
// Samplings may vary according of the number of nodes for each dimension.
const void *Table; // Points to the actual interpolation table
cmsInterpFunction Interpolation; // Points to the function to do the interpolation
} cmsInterpParams;
// Interpolators factory
typedef cmsInterpFunction (* cmsInterpFnFactory)(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
// The plug-in
typedef struct {
cmsPluginBase base;
// Points to a user-supplied function which implements the factory
cmsInterpFnFactory InterpolatorsFactory;
} cmsPluginInterpolation;
//----------------------------------------------------------------------------------------------------------
// Parametric curves. A negative type means same function but analytically inverted. Max. number of params is 10
// Evaluator callback for user-supplied parametric curves. May implement more than one type
typedef cmsFloat64Number (* cmsParametricCurveEvaluator)(cmsInt32Number Type, const cmsFloat64Number Params[10], cmsFloat64Number R);
// Plug-in may implement an arbitrary number of parametric curves
typedef struct {
cmsPluginBase base;
cmsUInt32Number nFunctions; // Number of supported functions
cmsUInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types
cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function
cmsParametricCurveEvaluator Evaluator; // The evaluator
} cmsPluginParametricCurves;
//----------------------------------------------------------------------------------------------------------
// Formatters. This plug-in adds new handlers, replacing them if they already exist. Formatters dealing with
// cmsFloat32Number (bps = 4) or double (bps = 0) types are requested via FormatterFloat callback. Others come across
// Formatter16 callback
struct _cmstransform_struct;
typedef cmsUInt8Number* (* cmsFormatter16)(CMSREGISTER struct _cmstransform_struct* CMMcargo,
CMSREGISTER cmsUInt16Number Values[],
CMSREGISTER cmsUInt8Number* Buffer,
CMSREGISTER cmsUInt32Number Stride);
typedef cmsUInt8Number* (* cmsFormatterFloat)(struct _cmstransform_struct* CMMcargo,
cmsFloat32Number Values[],
cmsUInt8Number* Buffer,
cmsUInt32Number Stride);
// This type holds a pointer to a formatter that can be either 16 bits or cmsFloat32Number
typedef union {
cmsFormatter16 Fmt16;
cmsFormatterFloat FmtFloat;
} cmsFormatter;
#define CMS_PACK_FLAGS_16BITS 0x0000
#define CMS_PACK_FLAGS_FLOAT 0x0001
typedef enum { cmsFormatterInput=0, cmsFormatterOutput=1 } cmsFormatterDirection;
typedef cmsFormatter (* cmsFormatterFactory)(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
cmsUInt32Number dwFlags); // precision
// Plug-in may implement an arbitrary number of formatters
typedef struct {
cmsPluginBase base;
cmsFormatterFactory FormattersFactory;
} cmsPluginFormatters;
//----------------------------------------------------------------------------------------------------------
// Tag type handler. Each type is free to return anything it wants, and it is up to the caller to
// know in advance what is the type contained in the tag.
typedef struct _cms_typehandler_struct {
cmsTagTypeSignature Signature; // The signature of the type
// Allocates and reads items
void * (* ReadPtr)(struct _cms_typehandler_struct* self,
cmsIOHANDLER* io,
cmsUInt32Number* nItems,
cmsUInt32Number SizeOfTag);
// Writes n Items
cmsBool (* WritePtr)(struct _cms_typehandler_struct* self,
cmsIOHANDLER* io,
void* Ptr,
cmsUInt32Number nItems);
// Duplicate an item or array of items
void* (* DupPtr)(struct _cms_typehandler_struct* self,
const void *Ptr,
cmsUInt32Number n);
// Free all resources
void (* FreePtr)(struct _cms_typehandler_struct* self,
void *Ptr);
// Additional parameters used by the calling thread
cmsContext ContextID;
cmsUInt32Number ICCVersion;
} cmsTagTypeHandler;
// Each plug-in implements a single type
typedef struct {
cmsPluginBase base;
cmsTagTypeHandler Handler;
} cmsPluginTagType;
//----------------------------------------------------------------------------------------------------------
// This is the tag plugin, which identifies tags. For writing, a pointer to function is provided.
// This function should return the desired type for this tag, given the version of profile
// and the data being serialized.
typedef struct {
cmsUInt32Number ElemCount; // If this tag needs an array, how many elements should keep
// For reading.
cmsUInt32Number nSupportedTypes; // In how many types this tag can come (MAX_TYPES_IN_LCMS_PLUGIN maximum)
cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN];
// For writing
cmsTagTypeSignature (* DecideType)(cmsFloat64Number ICCVersion, const void *Data);
} cmsTagDescriptor;
// Plug-in implements a single tag
typedef struct {
cmsPluginBase base;
cmsTagSignature Signature;
cmsTagDescriptor Descriptor;
} cmsPluginTag;
//----------------------------------------------------------------------------------------------------------
// Custom intents. This function should join all profiles specified in the array in
// a single LUT. Any custom intent in the chain redirects to custom function. If more than
// one custom intent is found, the one located first is invoked. Usually users should use only one
// custom intent, so mixing custom intents in same multiprofile transform is not supported.
typedef cmsPipeline* (* cmsIntentFn)( cmsContext ContextID,
cmsUInt32Number nProfiles,
cmsUInt32Number Intents[],
cmsHPROFILE hProfiles[],
cmsBool BPC[],
cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags);
// Each plug-in defines a single intent number.
typedef struct {
cmsPluginBase base;
cmsUInt32Number Intent;
cmsIntentFn Link;
char Description[256];
} cmsPluginRenderingIntent;
// The default ICC intents (perceptual, saturation, rel.col and abs.col)
CMSAPI cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID,
cmsUInt32Number nProfiles,
cmsUInt32Number Intents[],
cmsHPROFILE hProfiles[],
cmsBool BPC[],
cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags);
//----------------------------------------------------------------------------------------------------------
// Pipelines, Multi Process Elements.
typedef void (* _cmsStageEvalFn) (const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage* mpe);
typedef void*(* _cmsStageDupElemFn) (cmsStage* mpe);
typedef void (* _cmsStageFreeElemFn) (cmsStage* mpe);
// This function allocates a generic MPE
CMSAPI cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID,
cmsStageSignature Type,
cmsUInt32Number InputChannels,
cmsUInt32Number OutputChannels,
_cmsStageEvalFn EvalPtr, // Points to fn that evaluates the element (always in floating point)
_cmsStageDupElemFn DupElemPtr, // Points to a fn that duplicates the stage
_cmsStageFreeElemFn FreePtr, // Points to a fn that sets the element free
void* Data); // A generic pointer to whatever memory needed by the element
typedef struct {
cmsPluginBase base;
cmsTagTypeHandler Handler;
} 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
// the optimization search. Or FALSE if it is unable to optimize and want to give a chance
// to the rest of optimizers.
typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut,
cmsUInt32Number Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags);
// Pipeline Evaluator (in 16 bits)
typedef void (* _cmsPipelineEval16Fn)(CMSREGISTER const cmsUInt16Number In[],
CMSREGISTER cmsUInt16Number Out[],
const void* Data);
// Pipeline Evaluator (in floating point)
typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[],
cmsFloat32Number Out[],
const void* Data);
// 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.
CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
_cmsPipelineEval16Fn Eval16,
void* PrivateData,
_cmsFreeUserDataFn FreePrivateDataFn,
_cmsDupUserDataFn DupPrivateDataFn);
typedef struct {
cmsPluginBase base;
// Optimize entry point
_cmsOPToptimizeFn OptimizePtr;
} cmsPluginOptimization;
//----------------------------------------------------------------------------------------------------------
// Full xform
typedef struct {
cmsUInt32Number BytesPerLineIn;
cmsUInt32Number BytesPerLineOut;
cmsUInt32Number BytesPerPlaneIn;
cmsUInt32Number BytesPerPlaneOut;
} cmsStride;
typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, // Legacy function, handles just ONE scanline.
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number Size,
cmsUInt32Number Stride); // Stride in bytes to the next plana in planar formats
typedef void (*_cmsTransform2Fn)(struct _cmstransform_struct *CMMcargo,
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number PixelsPerLine,
cmsUInt32Number LineCount,
const cmsStride* Stride);
typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* xform,
void** UserData,
_cmsFreeUserDataFn* FreePrivateDataFn,
cmsPipeline** Lut,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags);
typedef cmsBool (* _cmsTransform2Factory)(_cmsTransform2Fn* 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);
// Retrieve original flags
CMSAPI cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo);
typedef struct {
cmsPluginBase base;
// Transform entry point
union {
_cmsTransformFactory legacy_xform;
_cmsTransform2Factory xform;
} factories;
} 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
}
# endif
#endif
#define _lcms_plugin_H
#endif

646
libs/lcms2/src/cmsalpha.c Normal file
View File

@ -0,0 +1,646 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// Alpha copy ------------------------------------------------------------------------------------------------------------------
// This macro return words stored as big endian
#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
// Floor to byte, taking care of saturation
cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
{
d += 0.5;
if (d <= 0) return 0;
if (d >= 255.0) return 255;
return (cmsUInt8Number) _cmsQuickFloorWord(d);
}
// Return the size in bytes of a given formatter
static
cmsUInt32Number trueBytesSize(cmsUInt32Number Format)
{
cmsUInt32Number fmt_bytes = T_BYTES(Format);
// For double, the T_BYTES field returns zero
if (fmt_bytes == 0)
return sizeof(double);
// Otherwise, it is already correct for all formats
return fmt_bytes;
}
// Several format converters
typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);
// From 8
static
void copy8(void* dst, const void* src)
{
memmove(dst, src, 1);
}
static
void from8to16(void* dst, const void* src)
{
cmsUInt8Number n = *(cmsUInt8Number*)src;
*(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n);
}
static
void from8to16SE(void* dst, const void* src)
{
cmsUInt8Number n = *(cmsUInt8Number*)src;
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n));
}
static
void from8toFLT(void* dst, const void* src)
{
*(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f;
}
static
void from8toDBL(void* dst, const void* src)
{
*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0;
}
static
void from8toHLF(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
// From 16
static
void from16to8(void* dst, const void* src)
{
cmsUInt16Number n = *(cmsUInt16Number*)src;
*(cmsUInt8Number*) dst = FROM_16_TO_8(n);
}
static
void from16SEto8(void* dst, const void* src)
{
cmsUInt16Number n = *(cmsUInt16Number*)src;
*(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n));
}
static
void copy16(void* dst, const void* src)
{
memmove(dst, src, 2);
}
static
void from16to16(void* dst, const void* src)
{
cmsUInt16Number n = *(cmsUInt16Number*)src;
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(n);
}
static
void from16toFLT(void* dst, const void* src)
{
*(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
}
static
void from16SEtoFLT(void* dst, const void* src)
{
*(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
}
static
void from16toDBL(void* dst, const void* src)
{
*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0;
}
static
void from16SEtoDBL(void* dst, const void* src)
{
*(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0;
}
static
void from16toHLF(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void from16SEtoHLF(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
// From Float
static
void fromFLTto8(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
}
static
void fromFLTto16(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
}
static
void fromFLTto16SE(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
}
static
void copy32(void* dst, const void* src)
{
memmove(dst, src, sizeof(cmsFloat32Number));
}
static
void fromFLTtoDBL(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsFloat64Number*)dst = (cmsFloat64Number)n;
}
static
void fromFLTtoHLF(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
// From HALF
static
void fromHLFto8(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void fromHLFto16(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void fromHLFto16SE(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void fromHLFtoFLT(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
*(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void fromHLFtoDBL(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
*(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
// From double
static
void fromDBLto8(void* dst, const void* src)
{
cmsFloat64Number n = *(cmsFloat64Number*)src;
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
}
static
void fromDBLto16(void* dst, const void* src)
{
cmsFloat64Number n = *(cmsFloat64Number*)src;
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
}
static
void fromDBLto16SE(void* dst, const void* src)
{
cmsFloat64Number n = *(cmsFloat64Number*)src;
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
}
static
void fromDBLtoFLT(void* dst, const void* src)
{
cmsFloat64Number n = *(cmsFloat64Number*)src;
*(cmsFloat32Number*)dst = (cmsFloat32Number) n;
}
static
void fromDBLtoHLF(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
#endif
}
static
void copy64(void* dst, const void* src)
{
memmove(dst, src, sizeof(cmsFloat64Number));
}
// Returns the position (x or y) of the formatter in the table of functions
static
int FormatterPos(cmsUInt32Number frm)
{
cmsUInt32Number b = T_BYTES(frm);
if (b == 0 && T_FLOAT(frm))
return 5; // DBL
#ifndef CMS_NO_HALF_SUPPORT
if (b == 2 && T_FLOAT(frm))
return 3; // HLF
#endif
if (b == 4 && T_FLOAT(frm))
return 4; // FLT
if (b == 2 && !T_FLOAT(frm))
{
if (T_ENDIAN16(frm))
return 2; // 16SE
else
return 1; // 16
}
if (b == 1 && !T_FLOAT(frm))
return 0; // 8
return -1; // not recognized
}
// Obtains an alpha-to-alpha function formatter
static
cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
{
static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
/* from 8 */ { copy8, from8to16, from8to16SE, from8toHLF, from8toFLT, from8toDBL },
/* from 16*/ { from16to8, copy16, from16to16, from16toHLF, from16toFLT, from16toDBL },
/* from 16SE*/{ from16SEto8, from16to16, copy16, from16SEtoHLF,from16SEtoFLT, from16SEtoDBL },
/* from HLF*/ { fromHLFto8, fromHLFto16, fromHLFto16SE, copy16, fromHLFtoFLT, fromHLFtoDBL },
/* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTto16SE, fromFLTtoHLF, copy32, fromFLTtoDBL },
/* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLto16SE, fromDBLtoHLF, fromDBLtoFLT, copy64 }};
int in_n = FormatterPos(in);
int out_n = FormatterPos(out);
if (in_n < 0 || out_n < 0 || in_n > 5 || out_n > 5) {
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");
return NULL;
}
return FormattersAlpha[in_n][out_n];
}
// This function computes the distance from each component to the next one in bytes.
static
void ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[])
{
cmsUInt32Number channels[cmsMAXCHANNELS];
cmsUInt32Number extra = T_EXTRA(Format);
cmsUInt32Number nchannels = T_CHANNELS(Format);
cmsUInt32Number total_chans = nchannels + extra;
cmsUInt32Number i;
cmsUInt32Number channelSize = trueBytesSize(Format);
cmsUInt32Number pixelSize = channelSize * total_chans;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
memset(channels, 0, sizeof(channels));
// Separation is independent of starting point and only depends on channel size
for (i = 0; i < extra; i++)
ComponentPointerIncrements[i] = pixelSize;
// Handle do swap
for (i = 0; i < total_chans; i++)
{
if (T_DOSWAP(Format)) {
channels[i] = total_chans - i - 1;
}
else {
channels[i] = i;
}
}
// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
if (T_SWAPFIRST(Format) && total_chans > 1) {
cmsUInt32Number tmp = channels[0];
for (i = 0; i < total_chans-1; i++)
channels[i] = channels[i + 1];
channels[total_chans - 1] = tmp;
}
// Handle size
if (channelSize > 1)
for (i = 0; i < total_chans; i++) {
channels[i] *= channelSize;
}
for (i = 0; i < extra; i++)
ComponentStartingOrder[i] = channels[i + nchannels];
}
// On planar configurations, the distance is the stride added to any non-negative
static
void ComputeIncrementsForPlanar(cmsUInt32Number Format,
cmsUInt32Number BytesPerPlane,
cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[])
{
cmsUInt32Number channels[cmsMAXCHANNELS];
cmsUInt32Number extra = T_EXTRA(Format);
cmsUInt32Number nchannels = T_CHANNELS(Format);
cmsUInt32Number total_chans = nchannels + extra;
cmsUInt32Number i;
cmsUInt32Number channelSize = trueBytesSize(Format);
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
memset(channels, 0, sizeof(channels));
// Separation is independent of starting point and only depends on channel size
for (i = 0; i < extra; i++)
ComponentPointerIncrements[i] = channelSize;
// Handle do swap
for (i = 0; i < total_chans; i++)
{
if (T_DOSWAP(Format)) {
channels[i] = total_chans - i - 1;
}
else {
channels[i] = i;
}
}
// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
if (T_SWAPFIRST(Format) && total_chans > 0) {
cmsUInt32Number tmp = channels[0];
for (i = 0; i < total_chans - 1; i++)
channels[i] = channels[i + 1];
channels[total_chans - 1] = tmp;
}
// Handle size
for (i = 0; i < total_chans; i++) {
channels[i] *= BytesPerPlane;
}
for (i = 0; i < extra; i++)
ComponentStartingOrder[i] = channels[i + nchannels];
}
// Dispatcher por chunky and planar RGB
static
void ComputeComponentIncrements(cmsUInt32Number Format,
cmsUInt32Number BytesPerPlane,
cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[])
{
if (T_PLANAR(Format)) {
ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
}
else {
ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);
}
}
// Handles extra channels copying alpha if requested by the flags
void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
void* out,
cmsUInt32Number PixelsPerLine,
cmsUInt32Number LineCount,
const cmsStride* Stride)
{
cmsUInt32Number i, j, k;
cmsUInt32Number nExtra;
cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
cmsFormatterAlphaFn copyValueFn;
// Make sure we need some copy
if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))
return;
// Exit early if in-place color-management is occurring - no need to copy extra channels to themselves.
if (p->InputFormat == p->OutputFormat && in == out)
return;
// Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time.
nExtra = T_EXTRA(p->InputFormat);
if (nExtra != T_EXTRA(p->OutputFormat))
return;
// Anything to do?
if (nExtra == 0)
return;
// Compute the increments
ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);
ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);
// Check for conversions 8, 16, half, float, dbl
copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
if (copyValueFn == NULL)
return;
if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly
cmsUInt8Number* SourcePtr;
cmsUInt8Number* DestPtr;
cmsUInt32Number SourceStrideIncrement = 0;
cmsUInt32Number DestStrideIncrement = 0;
// The loop itself
for (i = 0; i < LineCount; i++) {
// Prepare pointers for the loop
SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;
DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;
for (j = 0; j < PixelsPerLine; j++) {
copyValueFn(DestPtr, SourcePtr);
SourcePtr += SourceIncrements[0];
DestPtr += DestIncrements[0];
}
SourceStrideIncrement += Stride->BytesPerLineIn;
DestStrideIncrement += Stride->BytesPerLineOut;
}
}
else { // General case with more than one extra channel
cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];
cmsUInt8Number* DestPtr[cmsMAXCHANNELS];
cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS];
cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS];
memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));
memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));
// The loop itself
for (i = 0; i < LineCount; i++) {
// Prepare pointers for the loop
for (j = 0; j < nExtra; j++) {
SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];
DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];
}
for (j = 0; j < PixelsPerLine; j++) {
for (k = 0; k < nExtra; k++) {
copyValueFn(DestPtr[k], SourcePtr[k]);
SourcePtr[k] += SourceIncrements[k];
DestPtr[k] += DestIncrements[k];
}
}
for (j = 0; j < nExtra; j++) {
SourceStrideIncrements[j] += Stride->BytesPerLineIn;
DestStrideIncrements[j] += Stride->BytesPerLineOut;
}
}
}
}

1214
libs/lcms2/src/cmscnvrt.c Normal file

File diff suppressed because it is too large Load Diff

663
libs/lcms2/src/cmserr.c Normal file
View File

@ -0,0 +1,663 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// This function is here to help applications to prevent mixing lcms versions on header and shared objects.
int CMSEXPORT cmsGetEncodedCMMversion(void)
{
return LCMS_VERSION;
}
// I am so tired about incompatibilities on those functions that here are some replacements
// that hopefully would be fully portable.
// compare two strings ignoring case
int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
{
CMSREGISTER 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));
}
// long int because C99 specifies ftell in such way (7.19.9.2)
long int CMSEXPORT cmsfilelength(FILE* f)
{
long int p , n;
p = ftell(f); // register current file position
if (p == -1L)
return -1L;
if (fseek(f, 0, SEEK_END) != 0) {
return -1L;
}
n = ftell(f);
fseek(f, p, SEEK_SET); // file position restored
return n;
}
// Memory handling ------------------------------------------------------------------
//
// 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 evil code to allocate huge blocks that otherwise lcms would never need.
#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
// User may override this behaviour by using a memory plug-in, which basically replaces
// the default memory management functions. In this case, no check is performed and it
// is up to the plug-in writter to keep in the safe side. There are only three functions
// required to be implemented: malloc, realloc and free, although the user may want to
// replace the optional mallocZero, calloc and dup as well.
cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// *********************************************************************************
// This is the default memory allocation function. It does a very coarse
// check of amount of memory, just to prevent exploits
static
void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
{
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum
return (void*) malloc(size);
cmsUNUSED_PARAMETER(ContextID);
}
// Generic allocate & zero
static
void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size)
{
void *pt = _cmsMalloc(ContextID, size);
if (pt == NULL) return NULL;
memset(pt, 0, size);
return pt;
}
// The default free function. The only check proformed is against NULL pointers
static
void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
{
// free(NULL) is defined a no-op by C99, therefore it is safe to
// avoid the check, but it is here just in case...
if (Ptr) free(Ptr);
cmsUNUSED_PARAMETER(ContextID);
}
// 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)
{
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb
return realloc(Ptr, size);
cmsUNUSED_PARAMETER(ContextID);
}
// The default calloc function. Allocates an array of num elements, each one of size bytes
// all memory is initialized to zero.
static
void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
{
cmsUInt32Number Total = num * size;
// Preserve calloc behaviour
if (Total == 0) return NULL;
// Safe check for overflow.
if (num >= UINT_MAX / size) return NULL;
// Check for overflow
if (Total < num || Total < size) {
return NULL;
}
if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb
return _cmsMallocZero(ContextID, Total);
}
// Generic block duplication
static
void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size)
{
void* mem;
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb
mem = _cmsMalloc(ContextID, size);
if (mem != NULL && Org != NULL)
memmove(mem, Org, size);
return mem;
}
// 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 overridden
ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;
}
}
// Auxiliary 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(cmsContext ContextID, cmsPluginBase *Data)
{
cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
_cmsMemPluginChunkType* ptr;
// 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) {
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 ||
Plugin -> FreePtr == NULL ||
Plugin -> ReallocPtr == NULL) return FALSE;
// Set replacement functions
ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
if (ptr == NULL)
return FALSE;
_cmsInstallAllocFunctions(Plugin, ptr);
return TRUE;
}
// Generic allocate
void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
{
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr ->MallocPtr(ContextID, size);
}
// Generic allocate & zero
void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
{
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr->MallocZeroPtr(ContextID, size);
}
// Generic calloc
void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
{
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr->CallocPtr(ContextID, num, size);
}
// Generic reallocate
void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number 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) {
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
ptr ->FreePtr(ContextID, Ptr);
}
}
// Generic block duplication
void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
{
_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
return ptr ->DupPtr(ContextID, Org, size);
}
// ********************************************************************************************
// Sub allocation takes care of many pointers of small size. The memory allocated in
// this way have be freed at once. Next function allocates a single chunk for linked list
// I prefer this method over realloc due to the big inpact on xput realloc may have if
// memory is being swapped to disk. This approach is safer (although 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;
// Initialize values
chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial);
if (chunk ->Block == NULL) {
// Something went wrong
_cmsFree(ContextID, chunk);
return NULL;
}
chunk ->BlockSize = Initial;
chunk ->Used = 0;
chunk ->next = NULL;
return chunk;
}
// The suballocated is nothing but a pointer to the first element in the list. We also keep
// the thread ID in this structure.
_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial)
{
_cmsSubAllocator* sub;
// Create the container
sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator));
if (sub == NULL) return NULL;
sub ->ContextID = ContextID;
sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial);
if (sub ->h == NULL) {
_cmsFree(ContextID, sub);
return NULL;
}
return sub;
}
// Get rid of whole linked list
void _cmsSubAllocDestroy(_cmsSubAllocator* sub)
{
_cmsSubAllocator_chunk *chunk, *n;
for (chunk = sub ->h; chunk != NULL; chunk = n) {
n = chunk->next;
if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block);
_cmsFree(sub ->ContextID, chunk);
}
// Free the header
_cmsFree(sub ->ContextID, sub);
}
// Get a pointer to small memory block.
void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
{
cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;
cmsUInt8Number* ptr;
size = _cmsALIGNMEM(size);
// Check for memory. If there is no room, allocate a new chunk of double memory size.
if (size > Free) {
_cmsSubAllocator_chunk* chunk;
cmsUInt32Number newSize;
newSize = sub -> h ->BlockSize * 2;
if (newSize < size) newSize = size;
chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize);
if (chunk == NULL) return NULL;
// Link list
chunk ->next = sub ->h;
sub ->h = chunk;
}
ptr = sub -> h ->Block + sub -> h ->Used;
sub -> h -> Used += size;
return (void*) ptr;
}
// Duplicate in pool
void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size)
{
void *NewPtr;
// Dup of null pointer is also NULL
if (ptr == NULL)
return NULL;
NewPtr = _cmsSubAlloc(s, size);
if (ptr != NULL && NewPtr != NULL) {
memcpy(NewPtr, ptr, size);
}
return NewPtr;
}
// Error logging ******************************************************************
// There is no error handling at all. When a function fails, it returns proper value.
// For example, all create functions does return NULL on failure. Other return FALSE
// It may be interesting, for the developer, to know why the function is failing.
// for that reason, lcms2 does offer a logging function. This function does receive
// a ENGLISH string with some clues on what is going wrong. You can show this
// info to the end user, or just create some sort of log.
// The logging function should NOT terminate the program, as this obviously can leave
// resources. It is the programmer's responsibility to check each function return code
// to make sure it didn't fail.
// Error messages are limited to MAX_ERROR_MESSAGE_LEN
#define MAX_ERROR_MESSAGE_LEN 1024
// ---------------------------------------------------------------------------------------------------------
// This is our default log error
static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
// 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
void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
{
// fprintf(stderr, "[lcms]: %s\n", Text);
// fflush(stderr);
cmsUNUSED_PARAMETER(ContextID);
cmsUNUSED_PARAMETER(ErrorCode);
cmsUNUSED_PARAMETER(Text);
}
// 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)
{
cmsSetLogErrorHandlerTHR(NULL, Fn);
}
// Log an error
// ErrorText is a text holding an english description of error.
void WINAPIV cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...)
{
va_list args;
char Buffer[MAX_ERROR_MESSAGE_LEN];
_cmsLogErrorChunkType* lhg;
va_start(args, ErrorText);
vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
va_end(args);
// 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
void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
{
cmsUInt32Number be;
// Convert to big endian
be = _cmsAdjustEndianess32((cmsUInt32Number) sig);
// Move chars
memmove(String, &be, 4);
// Make sure of terminator
String[4] = 0;
}
//--------------------------------------------------------------------------------------------------
static
void* defMtxCreate(cmsContext id)
{
_cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex));
_cmsInitMutexPrimitive(ptr_mutex);
return (void*) ptr_mutex;
}
static
void defMtxDestroy(cmsContext id, void* mtx)
{
_cmsDestroyMutexPrimitive((_cmsMutex *) mtx);
_cmsFree(id, mtx);
}
static
cmsBool defMtxLock(cmsContext id, void* mtx)
{
cmsUNUSED_PARAMETER(id);
return _cmsLockPrimitive((_cmsMutex *) mtx) == 0;
}
static
void defMtxUnlock(cmsContext id, void* mtx)
{
cmsUNUSED_PARAMETER(id);
_cmsUnlockPrimitive((_cmsMutex *) mtx);
}
// Pointers to memory manager functions in Context0
_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
// Allocate and init mutex container.
void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
void* from;
if (src != NULL) {
from = src ->chunks[MutexPlugin];
}
else {
from = &MutexChunk;
}
ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType));
}
// Register new ways to transform
cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginMutex* Plugin = (cmsPluginMutex*) Data;
_cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (Data == NULL) {
// No lock routines
ctx->CreateMutexPtr = NULL;
ctx->DestroyMutexPtr = NULL;
ctx->LockMutexPtr = NULL;
ctx ->UnlockMutexPtr = NULL;
return TRUE;
}
// Factory callback is required
if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL ||
Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE;
ctx->CreateMutexPtr = Plugin->CreateMutexPtr;
ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr;
ctx ->LockMutexPtr = Plugin ->LockMutexPtr;
ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr;
// All is ok
return TRUE;
}
// Generic Mutex fns
void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->CreateMutexPtr == NULL) return NULL;
return ptr ->CreateMutexPtr(ContextID);
}
void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->DestroyMutexPtr != NULL) {
ptr ->DestroyMutexPtr(ContextID, mtx);
}
}
cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->LockMutexPtr == NULL) return TRUE;
return ptr ->LockMutexPtr(ContextID, mtx);
}
void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx)
{
_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
if (ptr ->UnlockMutexPtr != NULL) {
ptr ->UnlockMutexPtr(ContextID, mtx);
}
}

1488
libs/lcms2/src/cmsgamma.c Normal file

File diff suppressed because it is too large Load Diff

590
libs/lcms2/src/cmsgmt.c Normal file
View File

@ -0,0 +1,590 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// Auxiliary: append a Lab identity after the given sequence of profiles
// and return the transform. Lab profile is closed, rest of profiles are kept open.
cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
cmsUInt32Number nProfiles,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat,
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsBool BPC[],
const cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags)
{
cmsHTRANSFORM xform;
cmsHPROFILE hLab;
cmsHPROFILE ProfileList[256];
cmsBool BPCList[256];
cmsFloat64Number AdaptationList[256];
cmsUInt32Number IntentList[256];
cmsUInt32Number i;
// This is a rather big number and there is no need of dynamic memory
// since we are adding a profile, 254 + 1 = 255 and this is the limit
if (nProfiles > 254) return NULL;
// The output space
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
if (hLab == NULL) return NULL;
// Create a copy of parameters
for (i=0; i < nProfiles; i++) {
ProfileList[i] = hProfiles[i];
BPCList[i] = BPC[i];
AdaptationList[i] = AdaptationStates[i];
IntentList[i] = Intents[i];
}
// Place Lab identity at chain's end.
ProfileList[nProfiles] = hLab;
BPCList[nProfiles] = 0;
AdaptationList[nProfiles] = 1.0;
IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC;
// Create the transform
xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList,
BPCList,
IntentList,
AdaptationList,
NULL, 0,
InputFormat,
OutputFormat,
dwFlags);
cmsCloseProfile(hLab);
return xform;
}
// Compute K -> L* relationship. Flags may include black point compensation. In this case,
// the relationship is assumed from the profile with BPC to a black point zero.
static
cmsToneCurve* ComputeKToLstar(cmsContext ContextID,
cmsUInt32Number nPoints,
cmsUInt32Number nProfiles,
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsBool BPC[],
const cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags)
{
cmsToneCurve* out = NULL;
cmsUInt32Number i;
cmsHTRANSFORM xform;
cmsCIELab Lab;
cmsFloat32Number cmyk[4];
cmsFloat32Number* SampledPoints;
xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (xform == NULL) return NULL;
SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number));
if (SampledPoints == NULL) goto Error;
for (i=0; i < nPoints; i++) {
cmyk[0] = 0;
cmyk[1] = 0;
cmyk[2] = 0;
cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1));
cmsDoTransform(xform, cmyk, &Lab, 1);
SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation
}
out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints);
Error:
cmsDeleteTransform(xform);
if (SampledPoints) _cmsFree(ContextID, SampledPoints);
return out;
}
// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
// using the proof direction on both profiles to find K->L* relationship
// then joining both curves. dwFlags may include black point compensation.
cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
cmsUInt32Number nPoints,
cmsUInt32Number nProfiles,
const cmsUInt32Number Intents[],
const cmsHPROFILE hProfiles[],
const cmsBool BPC[],
const cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags)
{
cmsToneCurve *in, *out, *KTone;
// Make sure CMYK -> CMYK
if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL;
// Make sure last is an output profile
if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL;
// Create individual curves. BPC works also as each K to L* is
// computed as a BPC to zero black point in case of L*
in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (in == NULL) return NULL;
out = ComputeKToLstar(ContextID, nPoints, 1,
Intents + (nProfiles - 1),
&hProfiles [nProfiles - 1],
BPC + (nProfiles - 1),
AdaptationStates + (nProfiles - 1),
dwFlags);
if (out == NULL) {
cmsFreeToneCurve(in);
return NULL;
}
// Build the relationship. This effectively limits the maximum accuracy to 16 bits, but
// since this is used on black-preserving LUTs, we are not losing accuracy in any case
KTone = cmsJoinToneCurve(ContextID, in, out, nPoints);
// Get rid of components
cmsFreeToneCurve(in); cmsFreeToneCurve(out);
// Something went wrong...
if (KTone == NULL) return NULL;
// Make sure it is monotonic
if (!cmsIsToneCurveMonotonic(KTone)) {
cmsFreeToneCurve(KTone);
return NULL;
}
return KTone;
}
// Gamut LUT Creation -----------------------------------------------------------------------------------------
// Used by gamut & softproofing
typedef struct {
cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back
cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut
} GAMUTCHAIN;
// This sampler does compute gamut boundaries by comparing original
// values with a transform going back and forth. Values above ERR_THERESHOLD
// of maximum are considered out of gamut.
#define ERR_THERESHOLD 5
static
int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
{
GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo;
cmsCIELab LabIn1, LabOut1;
cmsCIELab LabIn2, LabOut2;
cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
cmsFloat64Number dE1, dE2, ErrorRatio;
// Assume in-gamut by default.
ErrorRatio = 1.0;
// Convert input to Lab
cmsDoTransform(t -> hInput, In, &LabIn1, 1);
// converts from PCS to colorant. This always
// does return in-gamut values,
cmsDoTransform(t -> hForward, &LabIn1, Proof, 1);
// Now, do the inverse, from colorant to PCS.
cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1);
memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
// Try again, but this time taking Check as input
cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
// Take difference of direct value
dE1 = cmsDeltaE(&LabIn1, &LabOut1);
// Take difference of converted value
dE2 = cmsDeltaE(&LabIn2, &LabOut2);
// if dE1 is small and dE2 is small, value is likely to be in gamut
if (dE1 < t->Thereshold && dE2 < t->Thereshold)
Out[0] = 0;
else {
// if dE1 is small and dE2 is big, undefined. Assume in gamut
if (dE1 < t->Thereshold && dE2 > t->Thereshold)
Out[0] = 0;
else
// dE1 is big and dE2 is small, clearly out of gamut
if (dE1 > t->Thereshold && dE2 < t->Thereshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
else {
// dE1 is big and dE2 is also big, could be due to perceptual mapping
// so take error ratio
if (dE2 == 0.0)
ErrorRatio = dE1;
else
ErrorRatio = dE1 / dE2;
if (ErrorRatio > t->Thereshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
else
Out[0] = 0;
}
}
return TRUE;
}
// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs
// the dE obtained is then annotated on the LUT. Values truly out of gamut are clipped to dE = 0xFFFE
// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well.
//
// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors,
// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should.
cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
cmsHPROFILE hProfiles[],
cmsBool BPC[],
cmsUInt32Number Intents[],
cmsFloat64Number AdaptationStates[],
cmsUInt32Number nGamutPCSposition,
cmsHPROFILE hGamut)
{
cmsHPROFILE hLab;
cmsPipeline* Gamut;
cmsStage* CLUT;
cmsUInt32Number dwFormat;
GAMUTCHAIN Chain;
cmsUInt32Number nChannels, nGridpoints;
cmsColorSpaceSignature ColorSpace;
cmsUInt32Number i;
cmsHPROFILE ProfileList[256];
cmsBool BPCList[256];
cmsFloat64Number AdaptationList[256];
cmsUInt32Number IntentList[256];
memset(&Chain, 0, sizeof(GAMUTCHAIN));
if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
return NULL;
}
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
if (hLab == NULL) return NULL;
// The figure of merit. On matrix-shaper profiles, should be almost zero as
// the conversion is pretty exact. On LUT based profiles, different resolutions
// of input and output CLUT may result in differences.
if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0;
}
else {
Chain.Thereshold = ERR_THERESHOLD;
}
// Create a copy of parameters
for (i=0; i < nGamutPCSposition; i++) {
ProfileList[i] = hProfiles[i];
BPCList[i] = BPC[i];
AdaptationList[i] = AdaptationStates[i];
IntentList[i] = Intents[i];
}
// Fill Lab identity
ProfileList[nGamutPCSposition] = hLab;
BPCList[nGamutPCSposition] = 0;
AdaptationList[nGamutPCSposition] = 1.0;
IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
ColorSpace = cmsGetColorSpace(hGamut);
nChannels = cmsChannelsOf(ColorSpace);
nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
// 16 bits to Lab double
Chain.hInput = cmsCreateExtendedTransform(ContextID,
nGamutPCSposition + 1,
ProfileList,
BPCList,
IntentList,
AdaptationList,
NULL, 0,
dwFormat, TYPE_Lab_DBL,
cmsFLAGS_NOCACHE);
// Does create the forward step. Lab double to device
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
Chain.hForward = cmsCreateTransformTHR(ContextID,
hLab, TYPE_Lab_DBL,
hGamut, dwFormat,
INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE);
// Does create the backwards step
Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
hLab, TYPE_Lab_DBL,
INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE);
// All ok?
if (Chain.hInput && Chain.hForward && Chain.hReverse) {
// Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
// dE when doing a transform back and forth on the colorimetric intent.
Gamut = cmsPipelineAlloc(ContextID, 3, 1);
if (Gamut != NULL) {
CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) {
cmsPipelineFree(Gamut);
Gamut = NULL;
}
else {
cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
}
}
}
else
Gamut = NULL; // Didn't work...
// Free all needed stuff.
if (Chain.hInput) cmsDeleteTransform(Chain.hInput);
if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
if (hLab) cmsCloseProfile(hLab);
// And return computed hull
return Gamut;
}
// Total Area Coverage estimation ----------------------------------------------------------------
typedef struct {
cmsUInt32Number nOutputChans;
cmsHTRANSFORM hRoundTrip;
cmsFloat32Number MaxTAC;
cmsFloat32Number MaxInput[cmsMAXCHANNELS];
} cmsTACestimator;
// This callback just accounts the maximum ink dropped in the given node. It does not populate any
// memory, as the destination table is NULL. Its only purpose it to know the global maximum.
static
int EstimateTAC(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void * Cargo)
{
cmsTACestimator* bp = (cmsTACestimator*) Cargo;
cmsFloat32Number RoundTrip[cmsMAXCHANNELS];
cmsUInt32Number i;
cmsFloat32Number Sum;
// Evaluate the xform
cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
// All all amounts of ink
for (Sum=0, i=0; i < bp ->nOutputChans; i++)
Sum += RoundTrip[i];
// If above maximum, keep track of input values
if (Sum > bp ->MaxTAC) {
bp ->MaxTAC = Sum;
for (i=0; i < bp ->nOutputChans; i++) {
bp ->MaxInput[i] = In[i];
}
}
return TRUE;
cmsUNUSED_PARAMETER(Out);
}
// Detect Total area coverage of the profile
cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
{
cmsTACestimator bp;
cmsUInt32Number dwFormatter;
cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS];
cmsHPROFILE hLab;
cmsContext ContextID = cmsGetProfileContextID(hProfile);
// TAC only works on output profiles
if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) {
return 0;
}
// Create a fake formatter for result
dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
bp.nOutputChans = T_CHANNELS(dwFormatter);
bp.MaxTAC = 0; // Initial TAC is 0
// for safety
if (bp.nOutputChans >= cmsMAXCHANNELS) return 0;
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
if (hLab == NULL) return 0;
// Setup a roundtrip on perceptual intent in output profile for TAC estimation
bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16,
hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
cmsCloseProfile(hLab);
if (bp.hRoundTrip == NULL) return 0;
// For L* we only need black and white. For C* we need many points
GridPoints[0] = 6;
GridPoints[1] = 74;
GridPoints[2] = 74;
if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
bp.MaxTAC = 0;
}
cmsDeleteTransform(bp.hRoundTrip);
// Results in %
return bp.MaxTAC;
}
// Carefully, clamp on CIELab space.
cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
double amax, double amin,
double bmax, double bmin)
{
// Whole Luma surface to zero
if (Lab -> L < 0) {
Lab-> L = Lab->a = Lab-> b = 0.0;
return FALSE;
}
// Clamp white, DISCARD HIGHLIGHTS. This is done
// in such way because icc spec doesn't allow the
// use of L>100 as a highlight means.
if (Lab->L > 100)
Lab -> L = 100;
// Check out gamut prism, on a, b faces
if (Lab -> a < amin || Lab->a > amax||
Lab -> b < bmin || Lab->b > bmax) {
cmsCIELCh LCh;
double h, slope;
// Falls outside a, b limits. Transports to LCh space,
// and then do the clipping
if (Lab -> a == 0.0) { // Is hue exactly 90?
// atan will not work, so clamp here
Lab -> b = Lab->b < 0 ? bmin : bmax;
return TRUE;
}
cmsLab2LCh(&LCh, Lab);
slope = Lab -> b / Lab -> a;
h = LCh.h;
// There are 4 zones
if ((h >= 0. && h < 45.) ||
(h >= 315 && h <= 360.)) {
// clip by amax
Lab -> a = amax;
Lab -> b = amax * slope;
}
else
if (h >= 45. && h < 135.)
{
// clip by bmax
Lab -> b = bmax;
Lab -> a = bmax / slope;
}
else
if (h >= 135. && h < 225.) {
// clip by amin
Lab -> a = amin;
Lab -> b = amin * slope;
}
else
if (h >= 225. && h < 315.) {
// clip by bmin
Lab -> b = bmin;
Lab -> a = bmin / slope;
}
else {
cmsSignalError(0, cmsERROR_RANGE, "Invalid angle");
return FALSE;
}
}
return TRUE;
}

535
libs/lcms2/src/cmshalf.c Normal file
View File

@ -0,0 +1,535 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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 const 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 const 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 const 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 const 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 CMSEXPORT _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 CMSEXPORT _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

1316
libs/lcms2/src/cmsintrp.c Normal file

File diff suppressed because it is too large Load Diff

1949
libs/lcms2/src/cmsio0.c Normal file

File diff suppressed because it is too large Load Diff

1028
libs/lcms2/src/cmsio1.c Normal file

File diff suppressed because it is too large Load Diff

1837
libs/lcms2/src/cmslut.c Normal file

File diff suppressed because it is too large Load Diff

176
libs/lcms2/src/cmsmtrx.c Normal file
View File

@ -0,0 +1,176 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;}
// Initiate a vector
void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z)
{
r -> n[VX] = x;
r -> n[VY] = y;
r -> n[VZ] = z;
}
// Vector subtraction
void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b)
{
r -> n[VX] = a -> n[VX] - b -> n[VX];
r -> n[VY] = a -> n[VY] - b -> n[VY];
r -> n[VZ] = a -> n[VZ] - b -> n[VZ];
}
// Vector cross product
void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v)
{
r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ];
r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX];
r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY];
}
// Vector dot product
cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v)
{
return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ];
}
// Euclidean length
cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a)
{
return sqrt(a ->n[VX] * a ->n[VX] +
a ->n[VY] * a ->n[VY] +
a ->n[VZ] * a ->n[VZ]);
}
// Euclidean distance
cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b)
{
cmsFloat64Number d1 = a ->n[VX] - b ->n[VX];
cmsFloat64Number d2 = a ->n[VY] - b ->n[VY];
cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ];
return sqrt(d1*d1 + d2*d2 + d3*d3);
}
// 3x3 Identity
void CMSEXPORT _cmsMAT3identity(cmsMAT3* a)
{
_cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0);
_cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0);
_cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0);
}
static
cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
{
return fabs(b - a) < (1.0 / 65535.0);
}
cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a)
{
cmsMAT3 Identity;
int i, j;
_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;
return TRUE;
}
// Multiply two matrices
void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b)
{
#define ROWCOL(i, j) \
a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j]
_cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2));
_cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2));
_cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2));
#undef ROWCOL //(i, j)
}
// Inverse of a matrix b = a^(-1)
cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b)
{
cmsFloat64Number det, c0, c1, c2;
c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1];
c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0];
c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0];
det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2;
if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert
b -> v[0].n[0] = c0/det;
b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det;
b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det;
b -> v[1].n[0] = c1/det;
b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det;
b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det;
b -> v[2].n[0] = c2/det;
b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det;
b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det;
return TRUE;
}
// Solve a system in the form Ax = b
cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b)
{
cmsMAT3 m, a_1;
memmove(&m, a, sizeof(cmsMAT3));
if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix
_cmsMAT3eval(x, &a_1, b);
return TRUE;
}
// Evaluate a vector across a matrix
void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v)
{
r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ];
r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ];
r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ];
}

980
libs/lcms2/src/cmsnamed.c Normal file
View File

@ -0,0 +1,980 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// Multilocalized unicode objects. That is an attempt to encapsulate i18n.
// Allocates an empty multi localizad unicode object
cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
{
cmsMLU* mlu;
// 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;
mlu ->ContextID = ContextID;
// 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;
return mlu;
}
// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
static
cmsBool GrowMLUpool(cmsMLU* mlu)
{
cmsUInt32Number size;
void *NewPtr;
// Sanity check
if (mlu == NULL) return FALSE;
if (mlu ->PoolSize == 0)
size = 256;
else
size = mlu ->PoolSize * 2;
// Check for overflow
if (size < mlu ->PoolSize) return FALSE;
// Reallocate the pool
NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);
if (NewPtr == NULL) return FALSE;
mlu ->MemPool = NewPtr;
mlu ->PoolSize = size;
return TRUE;
}
// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two.
static
cmsBool GrowMLUtable(cmsMLU* mlu)
{
cmsUInt32Number AllocatedEntries;
_cmsMLUentry *NewPtr;
// Sanity check
if (mlu == NULL) return FALSE;
AllocatedEntries = mlu ->AllocatedEntries * 2;
// Check for overflow
if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;
// Reallocate the memory
NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
if (NewPtr == NULL) return FALSE;
mlu ->Entries = NewPtr;
mlu ->AllocatedEntries = AllocatedEntries;
return TRUE;
}
// Search for a specific entry in the structure. Language and Country are used.
static
int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
{
cmsUInt32Number i;
// Sanity check
if (mlu == NULL) return -1;
// Iterate whole table
for (i=0; i < mlu ->UsedEntries; i++) {
if (mlu ->Entries[i].Country == CountryCode &&
mlu ->Entries[i].Language == LanguageCode) return (int) i;
}
// Not found
return -1;
}
// Add a block of characters to the intended MLU. Language and country are specified.
// Only one entry for Language/country pair is allowed.
static
cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
{
cmsUInt32Number Offset;
cmsUInt8Number* Ptr;
// Sanity check
if (mlu == NULL) return FALSE;
// Is there any room available?
if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {
if (!GrowMLUtable(mlu)) return FALSE;
}
// Only one ASCII string
if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!
// Check for size
while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {
if (!GrowMLUpool(mlu)) return FALSE;
}
Offset = mlu ->PoolUsed;
Ptr = (cmsUInt8Number*) mlu ->MemPool;
if (Ptr == NULL) return FALSE;
// Set the entry
memmove(Ptr + Offset, Block, size);
mlu ->PoolUsed += size;
mlu ->Entries[mlu ->UsedEntries].StrW = Offset;
mlu ->Entries[mlu ->UsedEntries].Len = size;
mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;
mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;
mlu ->UsedEntries++;
return TRUE;
}
// Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some
// compilers don't properly align beginning of strings
static
cmsUInt16Number strTo16(const char str[3])
{
const cmsUInt8Number* ptr8;
cmsUInt16Number n;
// For non-existent strings
if (str == NULL) return 0;
ptr8 = (const cmsUInt8Number*)str;
n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]);
return n;
}
static
void strFrom16(char str[3], cmsUInt16Number n)
{
str[0] = (char)(n >> 8);
str[1] = (char)n;
str[2] = (char)0;
}
// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
// In the case the user explicitely sets an empty string, we force a \0
cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
{
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
wchar_t* WStr;
cmsBool rc;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
if (mlu == NULL) return FALSE;
// len == 0 would prevent operation, so we set a empty string pointing to zero
if (len == 0)
{
len = 1;
}
WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));
if (WStr == NULL) return FALSE;
for (i=0; i < len; i++)
WStr[i] = (wchar_t) ASCIIString[i];
rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
_cmsFree(mlu ->ContextID, WStr);
return rc;
}
// We don't need any wcs support library
static
cmsUInt32Number mywcslen(const wchar_t *s)
{
const wchar_t *p;
p = s;
while (*p)
p++;
return (cmsUInt32Number)(p - s);
}
// Add a wide entry. Do not add any \0 terminator (ICC1v43_2010-12.pdf page 61)
cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)
{
cmsUInt16Number Lang = strTo16(Language);
cmsUInt16Number Cntry = strTo16(Country);
cmsUInt32Number len;
if (mlu == NULL) return FALSE;
if (WideString == NULL) return FALSE;
len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t);
if (len == 0)
len = sizeof(wchar_t);
return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
}
// Duplicating a MLU is as easy as copying all members
cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)
{
cmsMLU* NewMlu = NULL;
// Duplicating a NULL obtains a NULL
if (mlu == NULL) return NULL;
NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);
if (NewMlu == NULL) return NULL;
// Should never happen
if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)
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;
// 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;
if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;
memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);
NewMlu ->PoolUsed = mlu ->PoolUsed;
return NewMlu;
Error:
if (NewMlu != NULL) cmsMLUfree(NewMlu);
return NULL;
}
// Free any used memory
void CMSEXPORT cmsMLUfree(cmsMLU* mlu)
{
if (mlu) {
if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);
if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);
_cmsFree(mlu ->ContextID, mlu);
}
}
// The algorithm first searches for an exact match of country and language, if not found it uses
// the Language. If none is found, first entry is used instead.
static
const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
cmsUInt32Number *len,
cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,
cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
{
cmsUInt32Number i;
int Best = -1;
_cmsMLUentry* v;
if (mlu == NULL) return NULL;
if (mlu -> AllocatedEntries <= 0) return NULL;
for (i=0; i < mlu ->UsedEntries; i++) {
v = mlu ->Entries + i;
if (v -> Language == LanguageCode) {
if (Best == -1) Best = (int) i;
if (v -> Country == CountryCode) {
if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
if (len != NULL) *len = v ->Len;
return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match
}
}
}
// No string found. Return First one
if (Best == -1)
Best = 0;
v = mlu ->Entries + Best;
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);
}
// 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 wchar_t *Wide;
cmsUInt32Number StrLen = 0;
cmsUInt32Number ASCIIlen, i;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
// Sanitize
if (mlu == NULL) return 0;
// Get WideChar
Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
if (Wide == NULL) return 0;
ASCIIlen = StrLen / sizeof(wchar_t);
// Maybe we want only to know the len?
if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end
// No buffer size means no data
if (BufferSize <= 0) return 0;
// Some clipping may be required
if (BufferSize < ASCIIlen + 1)
ASCIIlen = BufferSize - 1;
// Precess each character
for (i=0; i < ASCIIlen; i++) {
if (Wide[i] == 0)
Buffer[i] = 0;
else
Buffer[i] = (char) Wide[i];
}
// 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 wchar_t *Wide;
cmsUInt32Number StrLen = 0;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
// Sanitize
if (mlu == NULL) return 0;
Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
if (Wide == NULL) return 0;
// Maybe we want only to know the len?
if (Buffer == NULL) return StrLen + sizeof(wchar_t);
// No buffer size means no data
if (BufferSize <= 0) return 0;
// Some clipping may be required
if (BufferSize < StrLen + sizeof(wchar_t))
StrLen = BufferSize - + sizeof(wchar_t);
memmove(Buffer, Wide, StrLen);
Buffer[StrLen / sizeof(wchar_t)] = 0;
return StrLen + sizeof(wchar_t);
}
// Get also the language and country
CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3],
char ObtainedLanguage[3], char ObtainedCountry[3])
{
const wchar_t *Wide;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
cmsUInt16Number ObtLang, ObtCode;
// Sanitize
if (mlu == NULL) return FALSE;
Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
if (Wide == NULL) return FALSE;
// Get used language and code
strFrom16(ObtainedLanguage, ObtLang);
strFrom16(ObtainedCountry, ObtCode);
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 >= mlu->UsedEntries) return FALSE;
entry = &mlu->Entries[idx];
strFrom16(LanguageCode, entry->Language);
strFrom16(CountryCode, entry->Country);
return TRUE;
}
// Named color lists --------------------------------------------------------------------------------------------
// Grow the list to keep at least NumElements
static
cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)
{
cmsUInt32Number size;
_cmsNAMEDCOLOR * NewPtr;
if (v == NULL) return FALSE;
if (v ->Allocated == 0)
size = 64; // Initial guess
else
size = v ->Allocated * 2;
// Keep a maximum color lists can grow, 100K entries seems reasonable
if (size > 1024 * 100) {
_cmsFree(v->ContextID, (void*) v->List);
v->List = NULL;
return FALSE;
}
NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
if (NewPtr == NULL)
return FALSE;
v ->List = NewPtr;
v ->Allocated = size;
return TRUE;
}
// Allocate a list for n elements
cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
{
cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
if (v == NULL) return NULL;
v ->List = NULL;
v ->nColors = 0;
v ->ContextID = ContextID;
while (v -> Allocated < n) {
if (!GrowNamedColorList(v)) {
cmsFreeNamedColorList(v);
return NULL;
}
}
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;
}
// Free a list
void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
{
if (v == NULL) return;
if (v ->List) _cmsFree(v ->ContextID, v ->List);
_cmsFree(v ->ContextID, v);
}
cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
{
cmsNAMEDCOLORLIST* NewNC;
if (v == NULL) return NULL;
NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);
if (NewNC == NULL) return NULL;
// For really large tables we need this
while (NewNC ->Allocated < v ->Allocated){
if (!GrowNamedColorList(NewNC))
{
cmsFreeNamedColorList(NewNC);
return NULL;
}
}
memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
NewNC ->ColorantCount = v ->ColorantCount;
memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));
NewNC ->nColors = v ->nColors;
return NewNC;
}
// Append a color to a list. List pointer may change if reallocated
cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
const char* Name,
cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])
{
cmsUInt32Number i;
if (NamedColorList == NULL) return FALSE;
if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {
if (!GrowNamedColorList(NamedColorList)) return FALSE;
}
for (i=0; i < NamedColorList ->ColorantCount; i++)
NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL ? (cmsUInt16Number)0 : Colorant[i];
for (i=0; i < 3; i++)
NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? (cmsUInt16Number) 0 : PCS[i];
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;
NamedColorList ->nColors++;
return TRUE;
}
// Returns number of elements
cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)
{
if (NamedColorList == NULL) return 0;
return NamedColorList ->nColors;
}
// Info aboout a given color
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
char* Name,
char* Prefix,
char* Suffix,
cmsUInt16Number* PCS,
cmsUInt16Number* Colorant)
{
if (NamedColorList == NULL) return FALSE;
if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
// strcpy instead of strncpy because many apps are using small buffers
if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
if (PCS)
memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));
if (Colorant)
memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,
sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);
return TRUE;
}
// Search for a given color name (no prefix or suffix)
cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
{
cmsUInt32Number i;
cmsUInt32Number n;
if (NamedColorList == NULL) return -1;
n = cmsNamedColorCount(NamedColorList);
for (i=0; i < n; i++) {
if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
return (cmsInt32Number) i;
}
return -1;
}
// MPE support -----------------------------------------------------------------------------------------------------------------
static
void FreeNamedColorList(cmsStage* mpe)
{
cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
cmsFreeNamedColorList(List);
}
static
void* DupNamedColorList(cmsStage* mpe)
{
cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
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", index);
Out[0] = Out[1] = Out[2] = 0.0f;
}
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)
{
cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
cmsUInt32Number j;
if (index >= NamedColorList-> nColors) {
cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index);
for (j = 0; j < NamedColorList->ColorantCount; j++)
Out[j] = 0.0f;
}
else {
for (j=0; j < NamedColorList ->ColorantCount; j++)
Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);
}
}
// Named color lookup element
cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
{
return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
cmsSigNamedColorElemType,
1, UsePCS ? 3 : NamedColorList ->ColorantCount,
UsePCS ? EvalNamedColorPCS : EvalNamedColor,
DupNamedColorList,
FreeNamedColorList,
cmsDupNamedColorList(NamedColorList));
}
// Retrieve the named color list from a transform. Should be first element in the LUT
cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)
{
_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
cmsStage* mpe = v ->Lut->Elements;
if (mpe ->Type != cmsSigNamedColorElemType) return NULL;
return (cmsNAMEDCOLORLIST*) mpe ->Data;
}
// Profile sequence description routines -------------------------------------------------------------------------------------
cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)
{
cmsSEQ* Seq;
cmsUInt32Number i;
if (n == 0) return NULL;
// In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
// in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
if (n > 255) return NULL;
Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));
if (Seq == NULL) return NULL;
Seq -> ContextID = ContextID;
Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));
Seq -> n = n;
if (Seq -> seq == NULL) {
_cmsFree(ContextID, Seq);
return NULL;
}
for (i=0; i < n; i++) {
Seq -> seq[i].Manufacturer = NULL;
Seq -> seq[i].Model = NULL;
Seq -> seq[i].Description = NULL;
}
return Seq;
}
void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
{
cmsUInt32Number i;
for (i=0; i < pseq ->n; i++) {
if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
}
if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
_cmsFree(pseq -> ContextID, pseq);
}
cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
{
cmsSEQ *NewSeq;
cmsUInt32Number i;
if (pseq == NULL)
return NULL;
NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
if (NewSeq == NULL) return NULL;
NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
if (NewSeq ->seq == NULL) goto Error;
NewSeq -> ContextID = pseq ->ContextID;
NewSeq -> n = pseq ->n;
for (i=0; i < pseq->n; i++) {
memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;
NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;
memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));
NewSeq ->seq[i].technology = pseq ->seq[i].technology;
NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);
NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);
NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);
}
return NewSeq;
Error:
cmsFreeProfileSequenceDescription(NewSeq);
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;
}

1976
libs/lcms2/src/cmsopt.c Normal file

File diff suppressed because it is too large Load Diff

3433
libs/lcms2/src/cmspack.c Normal file

File diff suppressed because it is too large Load Diff

940
libs/lcms2/src/cmspcs.c Normal file
View File

@ -0,0 +1,940 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// inter PCS conversions XYZ <-> CIE L* a* b*
/*
CIE 15:2004 CIELab is defined as:
L* = 116*f(Y/Yn) - 16 0 <= L* <= 100
a* = 500*[f(X/Xn) - f(Y/Yn)]
b* = 200*[f(Y/Yn) - f(Z/Zn)]
and
f(t) = t^(1/3) 1 >= t > (24/116)^3
(841/108)*t + (16/116) 0 <= t <= (24/116)^3
Reverse transform is:
X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116)
= Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116)
PCS in Lab2 is encoded as:
8 bit Lab PCS:
L* 0..100 into a 0..ff byte.
a* t + 128 range is -128.0 +127.0
b*
16 bit Lab PCS:
L* 0..100 into a 0..ff00 word.
a* t + 128 range is -128.0 +127.9961
b*
Interchange Space Component Actual Range Encoded Range
CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff
CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff
CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff
Version 2,3
-----------
CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00
CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
Version 4
---------
CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff
CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
*/
// Conversions
void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source)
{
cmsFloat64Number ISum;
ISum = 1./(Source -> X + Source -> Y + Source -> Z);
Dest -> x = (Source -> X) * ISum;
Dest -> y = (Source -> Y) * ISum;
Dest -> Y = Source -> Y;
}
void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source)
{
Dest -> X = (Source -> x / Source -> y) * Source -> Y;
Dest -> Y = Source -> Y;
Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y;
}
/*
The break point (24/116)^3 = (6/29)^3 is a very small amount of tristimulus
primary (0.008856). Generally, this only happens for
nearly ideal blacks and for some orange / amber colors in transmission mode.
For example, the Z value of the orange turn indicator lamp lens on an
automobile will often be below this value. But the Z does not
contribute to the perceived color directly.
*/
static
cmsFloat64Number f(cmsFloat64Number t)
{
const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0);
if (t <= Limit)
return (841.0/108.0) * t + (16.0/116.0);
else
return pow(t, 1.0/3.0);
}
static
cmsFloat64Number f_1(cmsFloat64Number t)
{
const cmsFloat64Number Limit = (24.0/116.0);
if (t <= Limit) {
return (108.0/841.0) * (t - (16.0/116.0));
}
return t * t * t;
}
// Standard XYZ to Lab. it can handle negative XZY numbers in some cases
void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz)
{
cmsFloat64Number fx, fy, fz;
if (WhitePoint == NULL)
WhitePoint = cmsD50_XYZ();
fx = f(xyz->X / WhitePoint->X);
fy = f(xyz->Y / WhitePoint->Y);
fz = f(xyz->Z / WhitePoint->Z);
Lab->L = 116.0*fy - 16.0;
Lab->a = 500.0*(fx - fy);
Lab->b = 200.0*(fy - fz);
}
// Standard XYZ to Lab. It can return negative XYZ in some cases
void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab)
{
cmsFloat64Number x, y, z;
if (WhitePoint == NULL)
WhitePoint = cmsD50_XYZ();
y = (Lab-> L + 16.0) / 116.0;
x = y + 0.002 * Lab -> a;
z = y - 0.005 * Lab -> b;
xyz -> X = f_1(x) * WhitePoint -> X;
xyz -> Y = f_1(y) * WhitePoint -> Y;
xyz -> Z = f_1(z) * WhitePoint -> Z;
}
static
cmsFloat64Number L2float2(cmsUInt16Number v)
{
return (cmsFloat64Number) v / 652.800;
}
// the a/b part
static
cmsFloat64Number ab2float2(cmsUInt16Number v)
{
return ((cmsFloat64Number) v / 256.0) - 128.0;
}
static
cmsUInt16Number L2Fix2(cmsFloat64Number L)
{
return _cmsQuickSaturateWord(L * 652.8);
}
static
cmsUInt16Number ab2Fix2(cmsFloat64Number ab)
{
return _cmsQuickSaturateWord((ab + 128.0) * 256.0);
}
static
cmsFloat64Number L2float4(cmsUInt16Number v)
{
return (cmsFloat64Number) v / 655.35;
}
// the a/b part
static
cmsFloat64Number ab2float4(cmsUInt16Number v)
{
return ((cmsFloat64Number) v / 257.0) - 128.0;
}
void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
{
Lab->L = L2float2(wLab[0]);
Lab->a = ab2float2(wLab[1]);
Lab->b = ab2float2(wLab[2]);
}
void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
{
Lab->L = L2float4(wLab[0]);
Lab->a = ab2float4(wLab[1]);
Lab->b = ab2float4(wLab[2]);
}
static
cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L)
{
const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00;
if (L < 0) L = 0;
if (L > L_max) L = L_max;
return L;
}
static
cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab)
{
if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2;
if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2;
return ab;
}
void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
{
cmsCIELab Lab;
Lab.L = Clamp_L_doubleV2(fLab ->L);
Lab.a = Clamp_ab_doubleV2(fLab ->a);
Lab.b = Clamp_ab_doubleV2(fLab ->b);
wLab[0] = L2Fix2(Lab.L);
wLab[1] = ab2Fix2(Lab.a);
wLab[2] = ab2Fix2(Lab.b);
}
static
cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L)
{
if (L < 0) L = 0;
if (L > 100.0) L = 100.0;
return L;
}
static
cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab)
{
if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4;
if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4;
return ab;
}
static
cmsUInt16Number L2Fix4(cmsFloat64Number L)
{
return _cmsQuickSaturateWord(L * 655.35);
}
static
cmsUInt16Number ab2Fix4(cmsFloat64Number ab)
{
return _cmsQuickSaturateWord((ab + 128.0) * 257.0);
}
void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
{
cmsCIELab Lab;
Lab.L = Clamp_L_doubleV4(fLab ->L);
Lab.a = Clamp_ab_doubleV4(fLab ->a);
Lab.b = Clamp_ab_doubleV4(fLab ->b);
wLab[0] = L2Fix4(Lab.L);
wLab[1] = ab2Fix4(Lab.a);
wLab[2] = ab2Fix4(Lab.b);
}
// Auxiliary: convert to Radians
static
cmsFloat64Number RADIANS(cmsFloat64Number deg)
{
return (deg * M_PI) / 180.;
}
// Auxiliary: atan2 but operating in degrees and returning 0 if a==b==0
static
cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b)
{
cmsFloat64Number h;
if (a == 0 && b == 0)
h = 0;
else
h = atan2(a, b);
h *= (180. / M_PI);
while (h > 360.)
h -= 360.;
while ( h < 0)
h += 360.;
return h;
}
// Auxiliary: Square
static
cmsFloat64Number Sqr(cmsFloat64Number v)
{
return v * v;
}
// From cylindrical coordinates. No check is performed, then negative values are allowed
void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab)
{
LCh -> L = Lab -> L;
LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5);
LCh -> h = atan2deg(Lab ->b, Lab ->a);
}
// To cylindrical coordinates. No check is performed, then negative values are allowed
void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh)
{
cmsFloat64Number h = (LCh -> h * M_PI) / 180.0;
Lab -> L = LCh -> L;
Lab -> a = LCh -> C * cos(h);
Lab -> b = LCh -> C * sin(h);
}
// In XYZ All 3 components are encoded using 1.15 fixed point
static
cmsUInt16Number XYZ2Fix(cmsFloat64Number d)
{
return _cmsQuickSaturateWord(d * 32768.0);
}
void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ)
{
cmsCIEXYZ xyz;
xyz.X = fXYZ -> X;
xyz.Y = fXYZ -> Y;
xyz.Z = fXYZ -> Z;
// Clamp to encodeable values.
if (xyz.Y <= 0) {
xyz.X = 0;
xyz.Y = 0;
xyz.Z = 0;
}
if (xyz.X > MAX_ENCODEABLE_XYZ)
xyz.X = MAX_ENCODEABLE_XYZ;
if (xyz.X < 0)
xyz.X = 0;
if (xyz.Y > MAX_ENCODEABLE_XYZ)
xyz.Y = MAX_ENCODEABLE_XYZ;
if (xyz.Y < 0)
xyz.Y = 0;
if (xyz.Z > MAX_ENCODEABLE_XYZ)
xyz.Z = MAX_ENCODEABLE_XYZ;
if (xyz.Z < 0)
xyz.Z = 0;
XYZ[0] = XYZ2Fix(xyz.X);
XYZ[1] = XYZ2Fix(xyz.Y);
XYZ[2] = XYZ2Fix(xyz.Z);
}
// To convert from Fixed 1.15 point to cmsFloat64Number
static
cmsFloat64Number XYZ2float(cmsUInt16Number v)
{
cmsS15Fixed16Number fix32;
// From 1.15 to 15.16
fix32 = v << 1;
// From fixed 15.16 to cmsFloat64Number
return _cms15Fixed16toDouble(fix32);
}
void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3])
{
fXYZ -> X = XYZ2float(XYZ[0]);
fXYZ -> Y = XYZ2float(XYZ[1]);
fXYZ -> Z = XYZ2float(XYZ[2]);
}
// Returns dE on two Lab values
cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
{
cmsFloat64Number dL, da, db;
dL = fabs(Lab1 -> L - Lab2 -> L);
da = fabs(Lab1 -> a - Lab2 -> a);
db = fabs(Lab1 -> b - Lab2 -> b);
return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5);
}
// Return the CIE94 Delta E
cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
{
cmsCIELCh LCh1, LCh2;
cmsFloat64Number dE, dL, dC, dh, dhsq;
cmsFloat64Number c12, sc, sh;
dL = fabs(Lab1 ->L - Lab2 ->L);
cmsLab2LCh(&LCh1, Lab1);
cmsLab2LCh(&LCh2, Lab2);
dC = fabs(LCh1.C - LCh2.C);
dE = cmsDeltaE(Lab1, Lab2);
dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC);
if (dhsq < 0)
dh = 0;
else
dh = pow(dhsq, 0.5);
c12 = sqrt(LCh1.C * LCh2.C);
sc = 1.0 + (0.048 * c12);
sh = 1.0 + (0.014 * c12);
return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh));
}
// Auxiliary
static
cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab)
{
cmsFloat64Number yt;
if (Lab->L > 7.996969)
yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100;
else
yt = 100 * (Lab->L / 903.3);
return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6);
}
// bfd - gets BFD(1:1) difference between Lab1, Lab2
cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
{
cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL,
deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd;
cmsCIELCh LCh1, LCh2;
lbfd1 = ComputeLBFD(Lab1);
lbfd2 = ComputeLBFD(Lab2);
deltaL = lbfd2 - lbfd1;
cmsLab2LCh(&LCh1, Lab1);
cmsLab2LCh(&LCh2, Lab2);
deltaC = LCh2.C - LCh1.C;
AveC = (LCh1.C+LCh2.C)/2;
Aveh = (LCh1.h+LCh2.h)/2;
dE = cmsDeltaE(Lab1, Lab2);
if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC)))
deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC));
else
deltah =0;
dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521;
g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000));
t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))-
0.040*cos((2*Aveh-136)/(180/M_PI))+
0.070*cos((3*Aveh-31)/(180/M_PI))+
0.049*cos((4*Aveh+114)/(180/M_PI))-
0.015*cos((5*Aveh-103)/(180/M_PI)));
dh = dc*(g*t+1-g);
rh = -0.260*cos((Aveh-308)/(180/M_PI))-
0.379*cos((2*Aveh-160)/(180/M_PI))-
0.636*cos((3*Aveh+254)/(180/M_PI))+
0.226*cos((4*Aveh+140)/(180/M_PI))-
0.194*cos((5*Aveh+280)/(180/M_PI));
rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000));
rt = rh*rc;
bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh)));
return bfd;
}
// cmc - CMC(l:c) difference between Lab1, Lab2
cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c)
{
cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc;
cmsCIELCh LCh1, LCh2;
if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
cmsLab2LCh(&LCh1, Lab1);
cmsLab2LCh(&LCh2, Lab2);
dL = Lab2->L-Lab1->L;
dC = LCh2.C-LCh1.C;
dE = cmsDeltaE(Lab1, Lab2);
if (Sqr(dE)>(Sqr(dL)+Sqr(dC)))
dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC));
else
dh =0;
if ((LCh1.h > 164) && (LCh1.h < 345))
t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI))));
else
t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI))));
sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638;
sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L);
if (Lab1->L<16)
sl = 0.511;
f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900));
sh = sc*(t*f+1-f);
cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh));
return cmc;
}
// dE2000 The weightings KL, KC and KH can be modified to reflect the relative
// importance of lightness, chroma and hue in different industrial applications
cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2,
cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh)
{
cmsFloat64Number L1 = Lab1->L;
cmsFloat64Number a1 = Lab1->a;
cmsFloat64Number b1 = Lab1->b;
cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) );
cmsFloat64Number Ls = Lab2 ->L;
cmsFloat64Number as = Lab2 ->a;
cmsFloat64Number bs = Lab2 ->b;
cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) );
cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) ));
cmsFloat64Number a_p = (1 + G ) * a1;
cmsFloat64Number b_p = b1;
cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p));
cmsFloat64Number h_p = atan2deg(b_p, a_p);
cmsFloat64Number a_ps = (1 + G) * as;
cmsFloat64Number b_ps = bs;
cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps));
cmsFloat64Number h_ps = atan2deg(b_ps, a_ps);
cmsFloat64Number meanC_p =(C_p + C_ps) / 2;
cmsFloat64Number hps_plus_hp = h_ps + h_p;
cmsFloat64Number hps_minus_hp = h_ps - h_p;
cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 :
(hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 :
(hps_plus_hp - 360)/2;
cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) :
(hps_minus_hp) > 180 ? (hps_minus_hp - 360) :
(hps_minus_hp);
cmsFloat64Number delta_L = (Ls - L1);
cmsFloat64Number delta_C = (C_ps - C_p );
cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2);
cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30))
+ 0.24 * cos(RADIANS(2*meanh_p))
+ 0.32 * cos(RADIANS(3*meanh_p + 6))
- 0.2 * cos(RADIANS(4*meanh_p - 63));
cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) );
cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2;
cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T;
cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25)));
cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0)));
cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc;
cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) +
Sqr(delta_C/(Sc * Kc)) +
Sqr(delta_H/(Sh * Kh)) +
Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh)));
return deltaE00;
}
// This function returns a number of gridpoints to be used as LUT table. It assumes same number
// of gripdpoints in all dimensions. Flags may override the choice.
cmsUInt32Number CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
{
cmsUInt32Number nChannels;
// Already specified?
if (dwFlags & 0x00FF0000) {
// Yes, grab'em
return (dwFlags >> 16) & 0xFF;
}
nChannels = cmsChannelsOf(Colorspace);
// HighResPrecalc is maximum resolution
if (dwFlags & cmsFLAGS_HIGHRESPRECALC) {
if (nChannels > 4)
return 7; // 7 for Hifi
if (nChannels == 4) // 23 for CMYK
return 23;
return 49; // 49 for RGB and others
}
// LowResPrecal is lower resolution
if (dwFlags & cmsFLAGS_LOWRESPRECALC) {
if (nChannels > 4)
return 6; // 6 for more than 4 channels
if (nChannels == 1)
return 33; // For monochrome
return 17; // 17 for remaining
}
// Default values
if (nChannels > 4)
return 7; // 7 for Hifi
if (nChannels == 4)
return 17; // 17 for CMYK
return 33; // 33 for RGB
}
cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
cmsUInt16Number **White,
cmsUInt16Number **Black,
cmsUInt32Number *nOutputs)
{
// Only most common spaces
static cmsUInt16Number RGBblack[4] = { 0, 0, 0 };
static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff };
static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink
static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 };
static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding
static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 };
static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff };
static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 };
static cmsUInt16Number Grayblack[4] = { 0 };
static cmsUInt16Number GrayWhite[4] = { 0xffff };
switch (Space) {
case cmsSigGrayData: if (White) *White = GrayWhite;
if (Black) *Black = Grayblack;
if (nOutputs) *nOutputs = 1;
return TRUE;
case cmsSigRgbData: if (White) *White = RGBwhite;
if (Black) *Black = RGBblack;
if (nOutputs) *nOutputs = 3;
return TRUE;
case cmsSigLabData: if (White) *White = LABwhite;
if (Black) *Black = LABblack;
if (nOutputs) *nOutputs = 3;
return TRUE;
case cmsSigCmykData: if (White) *White = CMYKwhite;
if (Black) *Black = CMYKblack;
if (nOutputs) *nOutputs = 4;
return TRUE;
case cmsSigCmyData: if (White) *White = CMYwhite;
if (Black) *Black = CMYblack;
if (nOutputs) *nOutputs = 3;
return TRUE;
default:;
}
return FALSE;
}
// Several utilities -------------------------------------------------------
// Translate from our colorspace to ICC representation
cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation)
{
switch (OurNotation) {
case 1:
case PT_GRAY: return cmsSigGrayData;
case 2:
case PT_RGB: return cmsSigRgbData;
case PT_CMY: return cmsSigCmyData;
case PT_CMYK: return cmsSigCmykData;
case PT_YCbCr:return cmsSigYCbCrData;
case PT_YUV: return cmsSigLuvData;
case PT_XYZ: return cmsSigXYZData;
case PT_LabV2:
case PT_Lab: return cmsSigLabData;
case PT_YUVK: return cmsSigLuvKData;
case PT_HSV: return cmsSigHsvData;
case PT_HLS: return cmsSigHlsData;
case PT_Yxy: return cmsSigYxyData;
case PT_MCH1: return cmsSigMCH1Data;
case PT_MCH2: return cmsSigMCH2Data;
case PT_MCH3: return cmsSigMCH3Data;
case PT_MCH4: return cmsSigMCH4Data;
case PT_MCH5: return cmsSigMCH5Data;
case PT_MCH6: return cmsSigMCH6Data;
case PT_MCH7: return cmsSigMCH7Data;
case PT_MCH8: return cmsSigMCH8Data;
case PT_MCH9: return cmsSigMCH9Data;
case PT_MCH10: return cmsSigMCHAData;
case PT_MCH11: return cmsSigMCHBData;
case PT_MCH12: return cmsSigMCHCData;
case PT_MCH13: return cmsSigMCHDData;
case PT_MCH14: return cmsSigMCHEData;
case PT_MCH15: return cmsSigMCHFData;
default: return (cmsColorSpaceSignature) 0;
}
}
int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace)
{
switch (ProfileSpace) {
case cmsSigGrayData: return PT_GRAY;
case cmsSigRgbData: return PT_RGB;
case cmsSigCmyData: return PT_CMY;
case cmsSigCmykData: return PT_CMYK;
case cmsSigYCbCrData:return PT_YCbCr;
case cmsSigLuvData: return PT_YUV;
case cmsSigXYZData: return PT_XYZ;
case cmsSigLabData: return PT_Lab;
case cmsSigLuvKData: return PT_YUVK;
case cmsSigHsvData: return PT_HSV;
case cmsSigHlsData: return PT_HLS;
case cmsSigYxyData: return PT_Yxy;
case cmsSig1colorData:
case cmsSigMCH1Data: return PT_MCH1;
case cmsSig2colorData:
case cmsSigMCH2Data: return PT_MCH2;
case cmsSig3colorData:
case cmsSigMCH3Data: return PT_MCH3;
case cmsSig4colorData:
case cmsSigMCH4Data: return PT_MCH4;
case cmsSig5colorData:
case cmsSigMCH5Data: return PT_MCH5;
case cmsSig6colorData:
case cmsSigMCH6Data: return PT_MCH6;
case cmsSigMCH7Data:
case cmsSig7colorData:return PT_MCH7;
case cmsSigMCH8Data:
case cmsSig8colorData:return PT_MCH8;
case cmsSigMCH9Data:
case cmsSig9colorData:return PT_MCH9;
case cmsSigMCHAData:
case cmsSig10colorData:return PT_MCH10;
case cmsSigMCHBData:
case cmsSig11colorData:return PT_MCH11;
case cmsSigMCHCData:
case cmsSig12colorData:return PT_MCH12;
case cmsSigMCHDData:
case cmsSig13colorData:return PT_MCH13;
case cmsSigMCHEData:
case cmsSig14colorData:return PT_MCH14;
case cmsSigMCHFData:
case cmsSig15colorData:return PT_MCH15;
default: return (cmsColorSpaceSignature) 0;
}
}
cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
{
switch (ColorSpace) {
case cmsSigMCH1Data:
case cmsSig1colorData:
case cmsSigGrayData: return 1;
case cmsSigMCH2Data:
case cmsSig2colorData: return 2;
case cmsSigXYZData:
case cmsSigLabData:
case cmsSigLuvData:
case cmsSigYCbCrData:
case cmsSigYxyData:
case cmsSigRgbData:
case cmsSigHsvData:
case cmsSigHlsData:
case cmsSigCmyData:
case cmsSigMCH3Data:
case cmsSig3colorData: return 3;
case cmsSigLuvKData:
case cmsSigCmykData:
case cmsSigMCH4Data:
case cmsSig4colorData: return 4;
case cmsSigMCH5Data:
case cmsSig5colorData: return 5;
case cmsSigMCH6Data:
case cmsSig6colorData: return 6;
case cmsSigMCH7Data:
case cmsSig7colorData: return 7;
case cmsSigMCH8Data:
case cmsSig8colorData: return 8;
case cmsSigMCH9Data:
case cmsSig9colorData: return 9;
case cmsSigMCHAData:
case cmsSig10colorData: return 10;
case cmsSigMCHBData:
case cmsSig11colorData: return 11;
case cmsSigMCHCData:
case cmsSig12colorData: return 12;
case cmsSigMCHDData:
case cmsSig13colorData: return 13;
case cmsSigMCHEData:
case cmsSig14colorData: return 14;
case cmsSigMCHFData:
case cmsSig15colorData: return 15;
default: return 3;
}
}

991
libs/lcms2/src/cmsplugin.c Normal file
View File

@ -0,0 +1,991 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// ----------------------------------------------------------------------------------
// Encoding & Decoding support functions
// ----------------------------------------------------------------------------------
// Little-Endian to Big-Endian
// Adjust a word value after being read/ before being written from/to an ICC profile
cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
{
#ifndef CMS_USE_BIG_ENDIAN
cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
cmsUInt8Number tmp;
tmp = pByte[0];
pByte[0] = pByte[1];
pByte[1] = tmp;
#endif
return Word;
}
// Transports to properly encoded values - note that icc profiles does use big endian notation.
// 1 2 3 4
// 4 3 2 1
cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
{
#ifndef CMS_USE_BIG_ENDIAN
cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
cmsUInt8Number temp1;
cmsUInt8Number temp2;
temp1 = *pByte++;
temp2 = *pByte++;
*(pByte-1) = *pByte;
*pByte++ = temp2;
*(pByte-3) = *pByte;
*pByte = temp1;
#endif
return DWord;
}
// 1 2 3 4 5 6 7 8
// 8 7 6 5 4 3 2 1
void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
{
#ifndef CMS_USE_BIG_ENDIAN
cmsUInt8Number* pIn = (cmsUInt8Number*) QWord;
cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
_cmsAssert(Result != NULL);
pOut[7] = pIn[0];
pOut[6] = pIn[1];
pOut[5] = pIn[2];
pOut[4] = pIn[3];
pOut[3] = pIn[4];
pOut[2] = pIn[5];
pOut[1] = pIn[6];
pOut[0] = pIn[7];
#else
_cmsAssert(Result != NULL);
# ifdef CMS_DONT_USE_INT64
(*Result)[0] = (*QWord)[0];
(*Result)[1] = (*QWord)[1];
# else
*Result = *QWord;
# endif
#endif
}
// Auxiliary -- read 8, 16 and 32-bit numbers
cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
{
cmsUInt8Number tmp;
_cmsAssert(io != NULL);
if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
return FALSE;
if (n != NULL) *n = tmp;
return TRUE;
}
cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
{
cmsUInt16Number tmp;
_cmsAssert(io != NULL);
if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
return FALSE;
if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
return TRUE;
}
cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
{
cmsUInt32Number i;
_cmsAssert(io != NULL);
for (i=0; i < n; i++) {
if (Array != NULL) {
if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
}
else {
if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
}
}
return TRUE;
}
cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
return FALSE;
if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
return TRUE;
}
cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
if (io->Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
return FALSE;
if (n != NULL) {
tmp = _cmsAdjustEndianess32(tmp);
*n = *(cmsFloat32Number*)(void*)&tmp;
// Safeguard which covers against absurd values
if (*n > 1E+20 || *n < -1E+20) return FALSE;
#if defined(_MSC_VER) && _MSC_VER < 1800
return TRUE;
#elif defined (__BORLANDC__)
return TRUE;
#elif !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L)
return TRUE;
#else
// fpclassify() required by C99 (only provided by MSVC >= 1800, VS2013 onwards)
return ((fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL));
#endif
}
return TRUE;
}
cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
{
cmsUInt64Number tmp;
_cmsAssert(io != NULL);
if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
return FALSE;
if (n != NULL) {
_cmsAdjustEndianess64(n, &tmp);
}
return TRUE;
}
cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
return FALSE;
if (n != NULL) {
*n = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32(tmp));
}
return TRUE;
}
cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
{
cmsEncodedXYZNumber xyz;
_cmsAssert(io != NULL);
if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
if (XYZ != NULL) {
XYZ->X = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.X));
XYZ->Y = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Y));
XYZ->Z = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Z));
}
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
{
_cmsAssert(io != NULL);
if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
{
cmsUInt16Number tmp;
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess16(n);
if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
{
cmsUInt32Number i;
_cmsAssert(io != NULL);
_cmsAssert(Array != NULL);
for (i=0; i < n; i++) {
if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
}
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess32(n);
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
tmp = *(cmsUInt32Number*) (void*) &n;
tmp = _cmsAdjustEndianess32(tmp);
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
{
cmsUInt64Number tmp;
_cmsAssert(io != NULL);
_cmsAdjustEndianess64(&tmp, n);
if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
{
cmsUInt32Number tmp;
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(n));
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
return FALSE;
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
{
cmsEncodedXYZNumber xyz;
_cmsAssert(io != NULL);
_cmsAssert(XYZ != NULL);
xyz.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->X));
xyz.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Y));
xyz.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Z));
return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
}
// from Fixed point 8.8 to double
cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
{
cmsUInt8Number msb, lsb;
lsb = (cmsUInt8Number) (fixed8 & 0xff);
msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
}
cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
{
cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
}
// from Fixed point 15.16 to double
cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
{
cmsFloat64Number floater, sign, mid;
int Whole, FracPart;
sign = (fix32 < 0 ? -1 : 1);
fix32 = abs(fix32);
Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
FracPart = (cmsUInt16Number)(fix32 & 0xffff);
mid = (cmsFloat64Number) FracPart / 65536.0;
floater = (cmsFloat64Number) Whole + mid;
return sign * floater;
}
// from double to Fixed point 15.16
cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
{
return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
}
// Date/Time functions
void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
{
_cmsAssert(Dest != NULL);
_cmsAssert(Source != NULL);
Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);
Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);
Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);
Dest->tm_mday = _cmsAdjustEndianess16(Source->day);
Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;
Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;
Dest->tm_wday = -1;
Dest->tm_yday = -1;
Dest->tm_isdst = 0;
}
void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
{
_cmsAssert(Dest != NULL);
_cmsAssert(Source != NULL);
Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
}
// Read base and return type base
cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
{
_cmsTagBase Base;
_cmsAssert(io != NULL);
if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
return (cmsTagTypeSignature) 0;
return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
}
// Setup base marker
cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
{
_cmsTagBase Base;
_cmsAssert(io != NULL);
Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
memset(&Base.reserved, 0, sizeof(Base.reserved));
return io -> Write(io, sizeof(_cmsTagBase), &Base);
}
cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
{
cmsUInt8Number Buffer[4];
cmsUInt32Number NextAligned, At;
cmsUInt32Number BytesToNextAlignedPos;
_cmsAssert(io != NULL);
At = io -> Tell(io);
NextAligned = _cmsALIGNLONG(At);
BytesToNextAlignedPos = NextAligned - At;
if (BytesToNextAlignedPos == 0) return TRUE;
if (BytesToNextAlignedPos > 4) return FALSE;
return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
}
cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
{
cmsUInt8Number Buffer[4];
cmsUInt32Number NextAligned, At;
cmsUInt32Number BytesToNextAlignedPos;
_cmsAssert(io != NULL);
At = io -> Tell(io);
NextAligned = _cmsALIGNLONG(At);
BytesToNextAlignedPos = NextAligned - At;
if (BytesToNextAlignedPos == 0) return TRUE;
if (BytesToNextAlignedPos > 4) return FALSE;
memset(Buffer, 0, BytesToNextAlignedPos);
return io -> Write(io, BytesToNextAlignedPos, Buffer);
}
// To deal with text streams. 2K at most
cmsBool WINAPIV _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
{
va_list args;
int len;
cmsUInt8Number Buffer[2048];
cmsBool rc;
cmsUInt8Number* ptr;
_cmsAssert(io != NULL);
_cmsAssert(frm != NULL);
va_start(args, frm);
len = vsnprintf((char*) Buffer, 2047, frm, args);
if (len < 0) {
va_end(args);
return FALSE; // Truncated, which is a fatal error for us
}
// setlocale may be active, no commas are needed in PS generator
// and PS generator is our only client
for (ptr = Buffer; *ptr; ptr++)
{
if (*ptr == ',') *ptr = '.';
}
rc = io ->Write(io, (cmsUInt32Number) len, Buffer);
va_end(args);
return rc;
}
// Plugin memory management -------------------------------------------------------------------------------------------------
// Specialized malloc for plug-ins, that is freed upon exit.
void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
{
struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
if (ctx ->MemPool == NULL) {
if (ContextID == NULL) {
ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
if (ctx->MemPool == NULL) return NULL;
}
else {
cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
return NULL;
}
}
return _cmsSubAlloc(ctx->MemPool, size);
}
// Main plug-in dispatcher
cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
{
return cmsPluginTHR(NULL, Plug_in);
}
cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
{
cmsPluginBase* Plugin;
for (Plugin = (cmsPluginBase*) Plug_in;
Plugin != NULL;
Plugin = Plugin -> Next) {
if (Plugin -> Magic != cmsPluginMagicNumber) {
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
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(id, Plugin)) return FALSE;
break;
case cmsPluginInterpolationSig:
if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginTagTypeSig:
if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
break;
case cmsPluginTagSig:
if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginFormattersSig:
if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginRenderingIntentSig:
if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginParametricCurveSig:
if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginMultiProcessElementSig:
if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginOptimizationSig:
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(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
}
}
// Keep a reference to the plug-in
return TRUE;
}
// Revert all plug-ins to default
void CMSEXPORT cmsUnregisterPlugins(void)
{
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
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
for (ctx = _cmsContextPoolHead;
ctx != NULL;
ctx = ctx ->Next) {
// Found it?
if (id == ctx)
{
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
return ctx; // New-style context
}
}
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
return &globalContext;
}
// Internal: get the memory area associanted with each context client
// Returns the block assigned to the specific zone. Never return NULL.
void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
{
struct _cmsContext_struct* ctx;
void *ptr;
if ((int) mc < 0 || mc >= MemoryClientMax) {
cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");
// This is catastrophic. Should never reach here
_cmsAssert(0);
// Reverts to global context
return globalContext.chunks[UserPtr];
}
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;
// See the comments regarding locking in lcms2_internal.h
// for an explanation of why we need the following code.
#ifndef CMS_NO_PTHREADS
#ifdef CMS_IS_WINDOWS_
#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
{
static HANDLE _cmsWindowsInitMutex = NULL;
static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
if (*mutex == NULL)
{
HANDLE p = CreateMutex(NULL, FALSE, NULL);
if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)
CloseHandle(p);
}
if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
return NULL;
if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)
InitializeCriticalSection(&_cmsContextPoolHeadMutex);
if (*mutex == NULL || !ReleaseMutex(*mutex))
return NULL;
}
#endif
#endif
#endif
_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 22 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;
}
// 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);
}

547
libs/lcms2/src/cmssamp.c Normal file
View File

@ -0,0 +1,547 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
#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.
// Black point detection -------------------------------------------------------------------------
// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs
static
cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent)
{
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];
hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab;
Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC;
xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents,
States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
cmsCloseProfile(hLab);
return xform;
}
// Use darker colorants to obtain black point. This works in the relative colorimetric intent and
// assumes more ink results in darker colors. No ink limit is assumed.
static
cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
cmsUInt32Number Intent,
cmsCIEXYZ* BlackPoint,
cmsUInt32Number dwFlags)
{
cmsUInt16Number *Black;
cmsHTRANSFORM xform;
cmsColorSpaceSignature Space;
cmsUInt32Number nChannels;
cmsUInt32Number dwFormat;
cmsHPROFILE hLab;
cmsCIELab Lab;
cmsCIEXYZ BlackXYZ;
cmsContext ContextID = cmsGetProfileContextID(hInput);
// If the profile does not support input direction, assume Black point 0
if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Create a formatter which has n channels and no floating point
dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE);
// Try to get black by using black colorant
Space = cmsGetColorSpace(hInput);
// This function returns darker colorant in 16 bits for several spaces
if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
if (nChannels != T_CHANNELS(dwFormat)) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Lab will be used as the output space, but lab2 will avoid recursion
hLab = cmsCreateLab2ProfileTHR(ContextID, NULL);
if (hLab == NULL) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Create the transform
xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat,
hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
cmsCloseProfile(hLab);
if (xform == NULL) {
// Something went wrong. Get rid of open resources and return zero as black
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Convert black to Lab
cmsDoTransform(xform, Black, &Lab, 1);
// Force it to be neutral, clip to max. L* of 50
Lab.a = Lab.b = 0;
if (Lab.L > 50) Lab.L = 50;
// Free the resources
cmsDeleteTransform(xform);
// Convert from Lab (which is now clipped) to XYZ.
cmsLab2XYZ(NULL, &BlackXYZ, &Lab);
if (BlackPoint != NULL)
*BlackPoint = BlackXYZ;
return TRUE;
cmsUNUSED_PARAMETER(dwFlags);
}
// Get a black point of output CMYK profile, discounting any ink-limiting embedded
// in the profile. For doing that, we use perceptual intent in input direction:
// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
static
cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile)
{
cmsHTRANSFORM hRoundTrip;
cmsCIELab LabIn, LabOut;
cmsCIEXYZ BlackXYZ;
// Is the intent supported by the profile?
if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return TRUE;
}
hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL);
if (hRoundTrip == NULL) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
LabIn.L = LabIn.a = LabIn.b = 0;
cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1);
// Clip Lab to reasonable limits
if (LabOut.L > 50) LabOut.L = 50;
LabOut.a = LabOut.b = 0;
cmsDeleteTransform(hRoundTrip);
// Convert it to XYZ
cmsLab2XYZ(NULL, &BlackXYZ, &LabOut);
if (BlackPoint != NULL)
*BlackPoint = BlackXYZ;
return TRUE;
}
// This function shouldn't exist at all -- there is such quantity of broken
// profiles on black point tag, that we must somehow fix chromaticity to
// avoid huge tint when doing Black point compensation. This function does
// just that. There is a special flag for using black point tag, but turned
// off by default because it is bogus on most profiles. The detection algorithm
// involves to turn BP to neutral and to use only L component.
cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
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;
}
#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG
// v2, v4 rel/abs colorimetric
if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) &&
Intent == INTENT_RELATIVE_COLORIMETRIC) {
cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
cmsCIELab Lab;
// If black point is specified, then use it,
BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag);
if (BlackPtr != NULL) {
BlackXYZ = *BlackPtr;
_cmsReadMediaWhitePoint(&MediaWhite, hProfile);
// Black point is absolute XYZ, so adapt to D50 to get PCS value
cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);
// Force a=b=0 to get rid of any chroma
cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
Lab.a = Lab.b = 0;
if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50
cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);
if (BlackPoint != NULL)
*BlackPoint = TrustedBlackPoint;
return TRUE;
}
}
#endif
// That is about v2 profiles.
// If output profile, discount ink-limiting and that's all
if (Intent == INTENT_RELATIVE_COLORIMETRIC &&
(cmsGetDeviceClass(hProfile) == cmsSigOutputClass) &&
(cmsGetColorSpace(hProfile) == cmsSigCmykData))
return BlackPointUsingPerceptualBlack(BlackPoint, hProfile);
// Nope, compute BP using current intent.
return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
}
// ---------------------------------------------------------------------------------------------------------
// 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));
}
}
}
// 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;
}

5627
libs/lcms2/src/cmstypes.c Normal file

File diff suppressed because it is too large Load Diff

1217
libs/lcms2/src/cmsvirt.c Normal file

File diff suppressed because it is too large Load Diff

350
libs/lcms2/src/cmswtpnt.c Normal file
View File

@ -0,0 +1,350 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 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"
// D50 - Widely used
const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void)
{
static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z};
return &D50XYZ;
}
const cmsCIExyY* CMSEXPORT cmsD50_xyY(void)
{
static cmsCIExyY D50xyY;
cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
return &D50xyY;
}
// Obtains WhitePoint from Temperature
cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK)
{
cmsFloat64Number x, y;
cmsFloat64Number T, T2, T3;
// cmsFloat64Number M1, M2;
_cmsAssert(WhitePoint != NULL);
T = TempK;
T2 = T*T; // Square
T3 = T2*T; // Cube
// 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 > 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)
y = -3.000*(x*x) + 2.870*x - 0.275;
// 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);
WhitePoint -> x = x;
WhitePoint -> y = y;
WhitePoint -> Y = 1.0;
return TRUE;
}
typedef struct {
cmsFloat64Number mirek; // temp (in microreciprocal kelvin)
cmsFloat64Number ut; // u coord of intersection w/ blackbody locus
cmsFloat64Number vt; // v coord of intersection w/ blackbody locus
cmsFloat64Number tt; // slope of ISOTEMPERATURE. line
} ISOTEMPERATURE;
static const ISOTEMPERATURE isotempdata[] = {
// {Mirek, Ut, Vt, Tt }
{0, 0.18006, 0.26352, -0.24341},
{10, 0.18066, 0.26589, -0.25479},
{20, 0.18133, 0.26846, -0.26876},
{30, 0.18208, 0.27119, -0.28539},
{40, 0.18293, 0.27407, -0.30470},
{50, 0.18388, 0.27709, -0.32675},
{60, 0.18494, 0.28021, -0.35156},
{70, 0.18611, 0.28342, -0.37915},
{80, 0.18740, 0.28668, -0.40955},
{90, 0.18880, 0.28997, -0.44278},
{100, 0.19032, 0.29326, -0.47888},
{125, 0.19462, 0.30141, -0.58204},
{150, 0.19962, 0.30921, -0.70471},
{175, 0.20525, 0.31647, -0.84901},
{200, 0.21142, 0.32312, -1.0182 },
{225, 0.21807, 0.32909, -1.2168 },
{250, 0.22511, 0.33439, -1.4512 },
{275, 0.23247, 0.33904, -1.7298 },
{300, 0.24010, 0.34308, -2.0637 },
{325, 0.24702, 0.34655, -2.4681 },
{350, 0.25591, 0.34951, -2.9641 },
{375, 0.26400, 0.35200, -3.5814 },
{400, 0.27218, 0.35407, -4.3633 },
{425, 0.28039, 0.35577, -5.3762 },
{450, 0.28863, 0.35714, -6.7262 },
{475, 0.29685, 0.35823, -8.5955 },
{500, 0.30505, 0.35907, -11.324 },
{525, 0.31320, 0.35968, -15.628 },
{550, 0.32129, 0.36011, -23.325 },
{575, 0.32931, 0.36038, -40.770 },
{600, 0.33724, 0.36051, -116.45 }
};
#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE)
// Robertson's method
cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint)
{
cmsUInt32Number j;
cmsFloat64Number us,vs;
cmsFloat64Number uj,vj,tj,di,dj,mi,mj;
cmsFloat64Number xs, ys;
_cmsAssert(WhitePoint != NULL);
_cmsAssert(TempK != NULL);
di = mi = 0;
xs = WhitePoint -> x;
ys = WhitePoint -> y;
// convert (x,y) to CIE 1960 (u,WhitePoint)
us = (2*xs) / (-xs + 6*ys + 1.5);
vs = (3*ys) / (-xs + 6*ys + 1.5);
for (j=0; j < NISO; j++) {
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);
if ((j != 0) && (di/dj < 0.0)) {
// Found a match
*TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi));
return TRUE;
}
di = dj;
mi = mj;
}
// Not found
return FALSE;
}
// Compute chromatic adaptation matrix using Chad as cone matrix
static
cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion,
const cmsCIEXYZ* SourceWhitePoint,
const cmsCIEXYZ* DestWhitePoint,
const cmsMAT3* Chad)
{
cmsMAT3 Chad_Inv;
cmsVEC3 ConeSourceXYZ, ConeSourceRGB;
cmsVEC3 ConeDestXYZ, ConeDestRGB;
cmsMAT3 Cone, Tmp;
Tmp = *Chad;
if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE;
_cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X,
SourceWhitePoint -> Y,
SourceWhitePoint -> Z);
_cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X,
DestWhitePoint -> Y,
DestWhitePoint -> Z);
_cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ);
_cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ);
// Build matrix
_cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0);
_cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0);
_cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]);
// Normalize
_cmsMAT3per(&Tmp, &Cone, Chad);
_cmsMAT3per(Conversion, &Chad_Inv, &Tmp);
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 }}
}};
if (ConeMatrix == NULL)
ConeMatrix = &LamRigg;
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;
cmsxyY2XYZ(&Dn, SourceWhitePt);
if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE;
Tmp = *r;
_cmsMAT3per(r, &Bradford, &Tmp);
return TRUE;
}
// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
// This is just an approximation, I am not handling all the non-linear
// aspects of the RGB to XYZ process, and assumming that the gamma correction
// has transitive property in the transformation chain.
//
// the alghoritm:
//
// - First I build the absolute conversion matrix using
// primaries in XYZ. This matrix is next inverted
// - Then I eval the source white point across this matrix
// obtaining the coeficients of the transformation
// - Then, I apply these coeficients to the original matrix
//
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;
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));
// Result = Primaries ^ (-1) inverse matrix
if (!_cmsMAT3inverse(&Primaries, &Result))
return FALSE;
_cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn);
// 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));
return _cmsAdaptMatrixToD50(r, WhitePt);
}
// Adapts a color to a given illuminant. Original color is expected to have
// a SourceWhitePt white point.
cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result,
const cmsCIEXYZ* SourceWhitePt,
const cmsCIEXYZ* Illuminant,
const cmsCIEXYZ* Value)
{
cmsMAT3 Bradford;
cmsVEC3 In, Out;
_cmsAssert(Result != NULL);
_cmsAssert(SourceWhitePt != NULL);
_cmsAssert(Illuminant != NULL);
_cmsAssert(Value != NULL);
if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE;
_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];
return TRUE;
}

1365
libs/lcms2/src/cmsxform.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff