lcms: Import upstream release 2.13.1.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2022-05-20 18:30:43 +02:00
parent b0c9a28e04
commit 95ef954f67
24 changed files with 1045 additions and 330 deletions

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2021 Marti Maria Saguer
// Copyright (c) 1998-2022 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@ -23,7 +23,7 @@
//
//---------------------------------------------------------------------------------
//
// Version 2.12
// Version 2.13.1
//
#ifndef _lcms2_H
@ -81,7 +81,7 @@ extern "C" {
#endif
// Version/release
#define LCMS_VERSION 2120
#define LCMS_VERSION 2131
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@ -666,9 +666,10 @@ typedef void* cmsHTRANSFORM;
// Format of pixel is defined by one cmsUInt32Number, using bit fields as follows
//
// 2 1 0
// 3 2 10987 6 5 4 3 2 1 098 7654 321
// A O TTTTT U Y F P X S EEE CCCC BBB
// 4 3 2 10987 6 5 4 3 2 1 098 7654 321
// M A O TTTTT U Y F P X S EEE CCCC BBB
//
// M: Premultiplied alpha (only works when extra samples is 1)
// A: Floating point -- With this flag we can differentiate 16 bits as float and as int
// O: Optimized -- previous optimization already returns the final 8-bit value
// T: Pixeltype
@ -681,6 +682,7 @@ typedef void* cmsHTRANSFORM;
// B: bytes per sample
// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK
#define PREMUL_SH(m) ((m) << 23)
#define FLOAT_SH(a) ((a) << 22)
#define OPTIMIZED_SH(s) ((s) << 21)
#define COLORSPACE_SH(s) ((s) << 16)
@ -694,6 +696,7 @@ typedef void* cmsHTRANSFORM;
#define BYTES_SH(b) (b)
// These macros unpack format specifiers into integers
#define T_PREMUL(m) (((m)>>23)&1)
#define T_FLOAT(a) (((a)>>22)&1)
#define T_OPTIMIZED(o) (((o)>>21)&1)
#define T_COLORSPACE(s) (((s)>>16)&31)
@ -722,7 +725,6 @@ typedef void* cmsHTRANSFORM;
#define PT_HSV 12
#define PT_HLS 13
#define PT_Yxy 14
#define PT_MCH1 15
#define PT_MCH2 16
#define PT_MCH3 17
@ -738,7 +740,6 @@ typedef void* cmsHTRANSFORM;
#define PT_MCH13 27
#define PT_MCH14 28
#define PT_MCH15 29
#define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding
// Some (not all!) representations
@ -752,7 +753,9 @@ typedef void* cmsHTRANSFORM;
#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1))
#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1))
#define TYPE_GRAYA_8_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PREMUL_SH(1))
#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
#define TYPE_GRAYA_16_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PREMUL_SH(1))
#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1))
#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1))
@ -769,24 +772,32 @@ typedef void* cmsHTRANSFORM;
#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1))
#define TYPE_RGBA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PREMUL_SH(1))
#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
#define TYPE_RGBA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PREMUL_SH(1))
#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
#define TYPE_ARGB_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
#define TYPE_ARGB_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
#define TYPE_ABGR_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
#define TYPE_ABGR_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_BGRA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_BGRA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1))
@ -903,7 +914,7 @@ typedef void* cmsHTRANSFORM;
#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
// Named color index. Only 16 bits allowed (don't check colorspace)
// Named color index. Only 16 bits is allowed (don't check colorspace)
#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2))
// Float formatters.
@ -911,13 +922,19 @@ typedef void* cmsHTRANSFORM;
#define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4))
#define TYPE_GRAYA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1))
#define TYPE_GRAYA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1)|PREMUL_SH(1))
#define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_RGBA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|PREMUL_SH(1))
#define TYPE_ARGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1))
#define TYPE_ARGB_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_BGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1))
#define TYPE_BGRA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_BGRA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1))
#define TYPE_ABGR_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4))
@ -1256,6 +1273,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe);
CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe);
CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe);
CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe);
CMSAPI cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe);
// Sampling
typedef cmsInt32Number (* cmsSAMPLER16) (CMSREGISTER const cmsUInt16Number In[],
@ -1906,6 +1924,8 @@ CMSAPI cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* Blac
// Estimate total area coverage
CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile);
// Estimate gamma space, always positive. Returns -1 on error.
CMSAPI cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold);
// Poor man's gamut mapping
CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -24,7 +24,7 @@
//---------------------------------------------------------------------------------
//
// 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
// It is provided for plug-in writers 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.

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -191,21 +191,21 @@ static
void fromFLTto8(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
}
static
void fromFLTto16(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
}
static
void fromFLTto16SE(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
}
@ -243,7 +243,7 @@ void fromHLFto8(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
@ -256,7 +256,7 @@ void fromHLFto16(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
@ -268,7 +268,7 @@ void fromHLFto16SE(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
#else
cmsUNUSED_PARAMETER(dst);
@ -414,9 +414,9 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number channelSize = trueBytesSize(Format);
cmsUInt32Number pixelSize = channelSize * total_chans;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
memset(channels, 0, sizeof(channels));

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -79,7 +79,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// 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
// is up to the plug-in writer 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.
@ -308,7 +308,7 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe
// Sub allocation takes care of many pointers of small size. The memory allocated in
// this way have be freed at once. Next function allocates a single chunk for linked list
// I prefer this method over realloc due to the big inpact on xput realloc may have if
// I prefer this method over realloc due to the big impact 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)

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -207,7 +207,7 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, i
}
// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the
// no optimization curve is computed. nSegments may also be zero in the inverse case, where only the
// optimization curve is given. Both features simultaneously is an error
static
cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
@ -507,28 +507,31 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=Y/c | Y< (ad+b)^g
case -4:
{
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
fabs(Params[3]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
e = Params[1] * Params[4] + Params[2];
if (e < 0)
disc = 0;
else
{
e = Params[1] * Params[4] + Params[2];
if (e < 0)
disc = 0;
disc = pow(e, Params[0]);
if (R >= disc) {
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
disc = pow(e, Params[0]);
if (R >= disc) {
Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
}
else {
Val = R / Params[3];
}
}
else {
if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = R / Params[3];
}
}
break;
@ -555,26 +558,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=(Y-f)/c | else
case -5:
{
if (fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
fabs(Params[3]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
else
{
disc = Params[3] * Params[4] + Params[6];
if (R >= disc) {
disc = Params[3] * Params[4] + Params[6];
if (R >= disc) {
e = R - Params[5];
if (e < 0)
Val = 0;
else
{
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE)
e = R - Params[5];
if (e < 0)
Val = 0;
else
Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
}
else {
Val = (R - Params[6]) / Params[3];
}
}
else {
if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = (R - Params[6]) / Params[3];
}
}
break;

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2021 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"),
@ -199,15 +199,15 @@ 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
cmsFloat64Number Threshold; // The threshold 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
// values with a transform going back and forth. Values above ERR_THRESHOLD
// of maximum are considered out of gamut.
#define ERR_THERESHOLD 5
#define ERR_THRESHOLD 5
static
@ -246,17 +246,17 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
// if dE1 is small and dE2 is small, value is likely to be in gamut
if (dE1 < t->Thereshold && dE2 < t->Thereshold)
if (dE1 < t->Threshold && dE2 < t->Threshold)
Out[0] = 0;
else {
// if dE1 is small and dE2 is big, undefined. Assume in gamut
if (dE1 < t->Thereshold && dE2 > t->Thereshold)
if (dE1 < t->Threshold && dE2 > t->Threshold)
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);
if (dE1 > t->Threshold && dE2 < t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Threshold) + .5);
else {
// dE1 is big and dE2 is also big, could be due to perceptual mapping
@ -266,8 +266,8 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
else
ErrorRatio = dE1 / dE2;
if (ErrorRatio > t->Thereshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
if (ErrorRatio > t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Threshold) + .5);
else
Out[0] = 0;
}
@ -323,10 +323,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0;
Chain.Threshold = 1.0;
}
else {
Chain.Thereshold = ERR_THERESHOLD;
Chain.Threshold = ERR_THRESHOLD;
}
@ -588,3 +588,67 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
return TRUE;
}
// Detect whatever a given ICC profile works in linear (gamma 1.0) space
// Actually, doing that "well" is quite hard, since every component may behave completely different.
// Since the true point of this function is to detect suitable optimizations, I am imposing some requirements
// that simplifies things: only RGB, and only profiles that can got in both directions.
// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma.
// For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
{
cmsContext ContextID;
cmsHPROFILE hXYZ;
cmsHTRANSFORM xform;
cmsToneCurve* Y_curve;
cmsUInt16Number rgb[256][3];
cmsCIEXYZ XYZ[256];
cmsFloat32Number Y_normalized[256];
cmsFloat64Number gamma;
cmsProfileClassSignature cl;
int i;
if (cmsGetColorSpace(hProfile) != cmsSigRgbData)
return -1;
cl = cmsGetDeviceClass(hProfile);
if (cl != cmsSigInputClass && cl != cmsSigDisplayClass &&
cl != cmsSigOutputClass && cl != cmsSigColorSpaceClass)
return -1;
ContextID = cmsGetProfileContextID(hProfile);
hXYZ = cmsCreateXYZProfileTHR(ContextID);
xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_RGB_16, hXYZ, TYPE_XYZ_DBL,
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE);
if (xform == NULL) { // If not RGB or forward direction is not supported, regret with the previous error
cmsCloseProfile(hXYZ);
return -1;
}
for (i = 0; i < 256; i++) {
rgb[i][0] = rgb[i][1] = rgb[i][2] = FROM_8_TO_16(i);
}
cmsDoTransform(xform, rgb, XYZ, 256);
cmsDeleteTransform(xform);
cmsCloseProfile(hXYZ);
for (i = 0; i < 256; i++) {
Y_normalized[i] = (cmsFloat32Number) XYZ[i].Y;
}
Y_curve = cmsBuildTabulatedToneCurveFloat(ContextID, 256, Y_normalized);
if (Y_curve == NULL)
return -1;
gamma = cmsEstimateGamma(Y_curve, threshold);
cmsFreeToneCurve(Y_curve);
return gamma;
}

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
int val3;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
// if last value...
if (Value[0] == 0xffff) {
// if last value or just one point
if (Value[0] == 0xffff || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[],
val2 = fclamp(Value[0]);
// if last value...
if (val2 == 1.0) {
if (val2 == 1.0 || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
else
@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
cmsUInt32Number OutChan;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
v = Input[0] * p16 -> Domain[0];
fk = _cmsToFixedDomain(v);
k0 = FIXED_TO_INT(fk);
rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
// if last value...
if (Input[0] == 0xffff || p16->Domain[0] == 0) {
k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
Output[OutChan] = LutTable[y0 + OutChan];
}
}
else
{
K0 = p16 -> opta[0] * k0;
K1 = p16 -> opta[0] * k1;
v = Input[0] * p16->Domain[0];
fk = _cmsToFixedDomain(v);
for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
k0 = FIXED_TO_INT(fk);
rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
K0 = p16->opta[0] * k0;
K1 = p16->opta[0] * k1;
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
}
}
}
@ -308,12 +322,12 @@ void Eval1InputFloat(const cmsFloat32Number Value[],
val2 = fclamp(Value[0]);
// if last value...
if (val2 == 1.0) {
if (val2 == 1.0 || p->Domain[0] == 0) {
y0 = LutTable[p->Domain[0]];
cmsUInt32Number start = p->Domain[0] * p->opta[0];
for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
Output[OutChan] = y0;
Output[OutChan] = LutTable[start + OutChan];
}
}
else

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -479,16 +479,15 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
if (Icc == NULL) return NULL;
return Icc->IOhandler;
if (Icc == NULL) return NULL;
return Icc->IOhandler;
}
// Creates an empty structure holding all required parameters
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
{
time_t now = time(NULL);
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
if (Icc == NULL) return NULL;
@ -499,15 +498,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
// Set default version
Icc ->Version = 0x02100000;
// Set creation date/time
memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
if (!_cmsGetTime(&Icc->Created))
goto Error;
// Create a mutex if the user provided proper plugin. NULL otherwise
Icc ->UsrMutex = _cmsCreateMutex(ContextID);
// Return the handle
return (cmsHPROFILE) Icc;
Error:
_cmsFree(ContextID, Icc);
return NULL;
}
cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
@ -1430,7 +1434,25 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn
return rc;
}
// Free one tag contents
static
void freeOneTag(_cmsICCPROFILE* Icc, cmsUInt32Number i)
{
if (Icc->TagPtrs[i]) {
cmsTagTypeHandler* TypeHandler = Icc->TagTypeHandlers[i];
if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc->ContextID;
LocalTypeHandler.ICCVersion = Icc->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc->TagPtrs[i]);
}
else
_cmsFree(Icc->ContextID, Icc->TagPtrs[i]);
}
}
// Closes a profile freeing any involved resources
cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
@ -1450,20 +1472,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
for (i=0; i < Icc -> TagCount; i++) {
if (Icc -> TagPtrs[i]) {
cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters
LocalTypeHandler.ICCVersion = Icc ->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
}
else
_cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
}
freeOneTag(Icc, i);
}
if (Icc ->IOhandler != NULL) {
@ -1503,7 +1512,7 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ
void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
cmsIOHANDLER* io = Icc ->IOhandler;
cmsIOHANDLER* io;
cmsTagTypeHandler* TypeHandler;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor;
@ -1515,8 +1524,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
n = _cmsSearchTag(Icc, sig, TRUE);
if (n < 0) goto Error; // Not found, return NULL
if (n < 0)
{
// Not found, return NULL
_cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
return NULL;
}
// If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) {
@ -1544,6 +1557,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (TagSize < 8) goto Error;
io = Icc ->IOhandler;
// Seek to its location
if (!io -> Seek(io, Offset))
goto Error;
@ -1611,8 +1625,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
return Icc -> TagPtrs[n];
// Return error and unlock tha data
// Return error and unlock the data
Error:
freeOneTag(Icc, n);
Icc->TagPtrs[n] = NULL;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return NULL;
}
@ -1778,7 +1796,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si
// It is already read?
if (Icc -> TagPtrs[i] == NULL) {
// No yet, get original position
// Not yet, get original position
Offset = Icc ->TagOffsets[i];
TagSize = Icc ->TagSizes[i];

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -260,7 +260,7 @@ Error:
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
@ -536,7 +536,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
}
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
@ -661,7 +661,7 @@ Error:
// ---------------------------------------------------------------------------------------------------------------
// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded
// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -1226,6 +1226,11 @@ void* CMSEXPORT cmsStageData(const cmsStage* mpe)
return mpe -> Data;
}
cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe)
{
return mpe -> ContextID;
}
cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe)
{
return mpe -> Next;

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -204,7 +204,7 @@ void strFrom16(char str[3], cmsUInt16Number n)
}
// 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
// In the case the user explicitly 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);
@ -641,7 +641,7 @@ cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColor
return NamedColorList ->nColors;
}
// Info aboout a given color
// Info about a given color
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
char* Name,
char* Prefix,

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -647,7 +647,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
{
cmsPipeline* Src = NULL;
cmsPipeline* Dest = NULL;
cmsStage* mpe;
cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
cmsUInt32Number nGridPoints;
@ -669,7 +668,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (ColorSpace == (cmsColorSpaceSignature)0 ||
OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// For empty LUTs, 2 points are enough
if (cmsPipelineStageCount(*Lut) == 0)
@ -677,13 +676,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
Src = *Lut;
// Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(Src);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE;
@ -1051,7 +1043,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
cmsStage* OptimizedCLUTmpe;
cmsColorSpaceSignature ColorSpace, OutputColorSpace;
cmsStage* OptimizedPrelinMpe;
cmsStage* mpe;
cmsToneCurve** OptimizedPrelinCurves;
_cmsStageCLutData* OptimizedPrelinCLUT;
@ -1072,14 +1063,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
}
OriginalLut = *Lut;
// Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat));
OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
@ -1918,6 +1902,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
cmsStage* mpe;
// A CLUT is being asked, so force this specific optimization
if (*dwFlags & cmsFLAGS_FORCE_CLUT) {
@ -1932,6 +1917,13 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
return TRUE;
}
// Named color pipelines cannot be optimized
for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
// Try to get rid of identities and trivial conversions.
AnySuccess = PreOptimize(*PtrLut);

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -79,6 +79,7 @@ typedef struct {
#define ANYSWAP DOSWAP_SH(1)
#define ANYSWAPFIRST SWAPFIRST_SH(1)
#define ANYFLAVOR FLAVOR_SH(1)
#define ANYPREMUL PREMUL_SH(1)
// Suppress waning about info never being used
@ -102,20 +103,40 @@ cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number v;
cmsUInt32Number i;
cmsUInt32Number v;
cmsUInt32Number i;
cmsUInt32Number alpha_factor = 1;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
accum += Extra;
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[nChan]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = FROM_8_TO_16(*accum);
v = Reverse ? REVERSE_FLAVOR_16(v) : v;
wIn[index] = v;
if (Premul && alpha_factor > 0)
{
v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
if (v > 0xffff) v = 0xffff;
}
wIn[index] = (cmsUInt16Number) v;
accum++;
}
@ -137,6 +158,7 @@ cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
}
// Extra channels are just ignored because come in the next planes
static
cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
@ -149,24 +171,47 @@ cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number i;
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsUInt8Number* Init = accum;
cmsUInt32Number alpha_factor = 1;
if (DoSwap ^ SwapFirst) {
accum += T_EXTRA(info -> InputFormat) * Stride;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
accum += Extra * Stride;
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[(nChan) * Stride]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt16Number v = FROM_8_TO_16(*accum);
cmsUInt32Number v = FROM_8_TO_16(*accum);
v = Reverse ? REVERSE_FLAVOR_16(v) : v;
wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
if (Premul && alpha_factor > 0)
{
v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
if (v > 0xffff) v = 0xffff;
}
wIn[index] = (cmsUInt16Number) v;
accum += Stride;
}
return (Init + 1);
}
// Special cases, provided for performance
static
cmsUInt8Number* Unroll4Bytes(CMSREGISTER _cmsTRANSFORM* info,
@ -517,6 +562,55 @@ cmsUInt8Number* UnrollAnyWords(CMSREGISTER _cmsTRANSFORM* info,
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* UnrollAnyWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wIn[],
CMSREGISTER cmsUInt8Number* accum,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number i;
cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[nChan - 1]);
cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
if (ExtraFirst) {
accum += sizeof(cmsUInt16Number);
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt32Number v = *(cmsUInt16Number*) accum;
if (SwapEndian)
v = CHANGE_ENDIAN(v);
v = (v << 16) / alpha_factor;
if (v > 0xffff) v = 0xffff;
wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
accum += sizeof(cmsUInt16Number);
}
if (!ExtraFirst) {
accum += sizeof(cmsUInt16Number);
}
return accum;
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wIn[],
@ -550,6 +644,46 @@ cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
return (Init + sizeof(cmsUInt16Number));
}
static
cmsUInt8Number* UnrollPlanarWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wIn[],
CMSREGISTER cmsUInt8Number* accum,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
cmsUInt32Number i;
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt8Number* Init = accum;
cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[(nChan - 1) * Stride]);
cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
if (ExtraFirst) {
accum += Stride;
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt32Number v = (cmsUInt32Number) *(cmsUInt16Number*) accum;
if (SwapEndian)
v = CHANGE_ENDIAN(v);
v = (v << 16) / alpha_factor;
if (v > 0xffff) v = 0xffff;
wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
accum += Stride;
}
return (Init + sizeof(cmsUInt16Number));
}
static
cmsUInt8Number* Unroll4Words(CMSREGISTER _cmsTRANSFORM* info,
@ -1087,6 +1221,110 @@ cmsUInt8Number* UnrollDouble1Chan(CMSREGISTER _cmsTRANSFORM* info,
//-------------------------------------------------------------------------------------------------------------------
// For anything going from cmsUInt8Number
static
cmsUInt8Number* Unroll8ToFloat(_cmsTRANSFORM* info,
cmsFloat32Number wIn[],
cmsUInt8Number* accum,
cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
cmsFloat32Number v;
cmsUInt32Number i, start = 0;
Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[(i + start) * Stride];
else
v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[i + start];
v /= 255.0F;
wIn[index] = Reverse ? 1 - v : v;
}
if (Extra == 0 && SwapFirst) {
cmsFloat32Number tmp = wIn[0];
memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
wIn[nChan - 1] = tmp;
}
if (T_PLANAR(info->InputFormat))
return accum + sizeof(cmsUInt8Number);
else
return accum + (nChan + Extra) * sizeof(cmsUInt8Number);
}
// For anything going from cmsUInt16Number
static
cmsUInt8Number* Unroll16ToFloat(_cmsTRANSFORM* info,
cmsFloat32Number wIn[],
cmsUInt8Number* accum,
cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
cmsFloat32Number v;
cmsUInt32Number i, start = 0;
Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number)((cmsUInt16Number*)accum)[(i + start) * Stride];
else
v = (cmsFloat32Number)((cmsUInt16Number*)accum)[i + start];
v /= 65535.0F;
wIn[index] = Reverse ? 1 - v : v;
}
if (Extra == 0 && SwapFirst) {
cmsFloat32Number tmp = wIn[0];
memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
wIn[nChan - 1] = tmp;
}
if (T_PLANAR(info->InputFormat))
return accum + sizeof(cmsUInt16Number);
else
return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
}
// For anything going from cmsFloat32Number
static
cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
@ -1095,19 +1333,30 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsFloat32Number v;
cmsUInt32Number i, start = 0;
cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
cmsFloat32Number maximum = IsInkSpace(info->InputFormat) ? 100.0F : 1.0F;
cmsFloat32Number alpha_factor = 1.0f;
cmsFloat32Number* ptr = (cmsFloat32Number*)accum;
Stride /= PixelSize(info->InputFormat);
if (Premul && Extra)
{
if (Planar)
alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan * Stride]) / maximum;
else
alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
}
if (ExtraFirst)
start = Extra;
@ -1116,9 +1365,12 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
v = ptr[(i + start) * Stride];
else
v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
v = ptr[i + start];
if (Premul && alpha_factor > 0)
v /= alpha_factor;
v /= maximum;
@ -1148,19 +1400,30 @@ cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsFloat64Number v;
cmsUInt32Number i, start = 0;
cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
cmsFloat64Number alpha_factor = 1.0;
cmsFloat64Number* ptr = (cmsFloat64Number*)accum;
Stride /= PixelSize(info->InputFormat);
if (Premul && Extra)
{
if (Planar)
alpha_factor = (ExtraFirst ? ptr[0] : ptr[(nChan) * Stride]) / maximum;
else
alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
}
if (ExtraFirst)
start = Extra;
@ -1173,6 +1436,10 @@ cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
else
v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start];
if (Premul && alpha_factor > 0)
v /= alpha_factor;
v /= maximum;
wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v);
@ -1254,8 +1521,6 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info,
}
}
// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
static
cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
@ -1316,44 +1581,132 @@ cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,
}
cmsINLINE void lab4toFloat(cmsFloat32Number wIn[], cmsUInt16Number lab4[3])
{
cmsFloat32Number L = (cmsFloat32Number) lab4[0] / 655.35F;
cmsFloat32Number a = ((cmsFloat32Number) lab4[1] / 257.0F) - 128.0F;
cmsFloat32Number b = ((cmsFloat32Number) lab4[2] / 257.0F) - 128.0F;
wIn[0] = (L / 100.0F); // from 0..100 to 0..1
wIn[1] = ((a + 128.0F) / 255.0F); // form -128..+127 to 0..1
wIn[2] = ((b + 128.0F) / 255.0F);
}
static
cmsUInt8Number* UnrollLabV2_8ToFloat(_cmsTRANSFORM* info,
cmsFloat32Number wIn[],
cmsUInt8Number* accum,
cmsUInt32Number Stride)
{
cmsUInt16Number lab4[3];
lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
lab4toFloat(wIn, lab4);
return accum;
cmsUNUSED_PARAMETER(info);
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* UnrollALabV2_8ToFloat(_cmsTRANSFORM* info,
cmsFloat32Number wIn[],
cmsUInt8Number* accum,
cmsUInt32Number Stride)
{
cmsUInt16Number lab4[3];
accum++; // A
lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
lab4toFloat(wIn, lab4);
return accum;
cmsUNUSED_PARAMETER(info);
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* UnrollLabV2_16ToFloat(_cmsTRANSFORM* info,
cmsFloat32Number wIn[],
cmsUInt8Number* accum,
cmsUInt32Number Stride)
{
cmsUInt16Number lab4[3];
lab4[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L
lab4[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a
lab4[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b
lab4toFloat(wIn, lab4);
return accum;
cmsUNUSED_PARAMETER(info);
cmsUNUSED_PARAMETER(Stride);
}
// Packing routines -----------------------------------------------------------------------------------------------------------
// Generic chunky for byte
static
cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt8Number* swap1;
cmsUInt8Number v = 0;
cmsUInt16Number v = 0;
cmsUInt32Number i;
cmsUInt32Number alpha_factor = 0;
swap1 = output;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
output += Extra;
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = FROM_16_TO_8(wOut[index]);
v = wOut[index];
if (Reverse)
v = REVERSE_FLAVOR_8(v);
v = REVERSE_FLAVOR_16(v);
*output++ = v;
if (Premul && alpha_factor != 0)
{
v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
}
*output++ = FROM_16_TO_8(v);
}
if (!ExtraFirst) {
@ -1363,39 +1716,47 @@ cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info,
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, nChan-1);
*swap1 = v;
*swap1 = FROM_16_TO_8(v);
}
return output;
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number* swap1;
cmsUInt16Number v = 0;
cmsUInt32Number i;
cmsUInt32Number alpha_factor = 0;
swap1 = (cmsUInt16Number*) output;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(*(cmsUInt16Number*) output);
output += Extra * sizeof(cmsUInt16Number);
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[nChan]);
}
for (i=0; i < nChan; i++) {
@ -1409,6 +1770,11 @@ cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info,
if (Reverse)
v = REVERSE_FLAVOR_16(v);
if (Premul && alpha_factor != 0)
{
v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
}
*(cmsUInt16Number*) output = v;
output += sizeof(cmsUInt16Number);
@ -1424,38 +1790,60 @@ cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info,
*swap1 = v;
}
return output;
cmsUNUSED_PARAMETER(Stride);
}
static
cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number i;
cmsUInt8Number* Init = output;
cmsUInt32Number alpha_factor = 0;
if (DoSwap ^ SwapFirst) {
output += T_EXTRA(info -> OutputFormat) * Stride;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
output += Extra * Stride;
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan * Stride]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
cmsUInt16Number v = wOut[index];
if (Reverse)
v = REVERSE_FLAVOR_16(v);
if (Premul && alpha_factor != 0)
{
v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
}
*(cmsUInt8Number*)output = FROM_16_TO_8(v);
*(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
output += Stride;
}
@ -1471,16 +1859,30 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
cmsUInt32Number i;
cmsUInt8Number* Init = output;
cmsUInt16Number v;
cmsUInt32Number alpha_factor = 0;
if (DoSwap) {
output += T_EXTRA(info -> OutputFormat) * Stride;
if (ExtraFirst) {
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[0]);
output += Extra * Stride;
}
else
{
if (Premul && Extra)
alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*)output)[nChan * Stride]);
}
for (i=0; i < nChan; i++) {
@ -1495,6 +1897,11 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
if (Reverse)
v = REVERSE_FLAVOR_16(v);
if (Premul && alpha_factor != 0)
{
v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
}
*(cmsUInt16Number*) output = v;
output += Stride;
}
@ -2641,10 +3048,6 @@ cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
}
static
cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
cmsFloat32Number wOut[],
@ -3029,12 +3432,12 @@ static const cmsFormatters16 InputFormatters16[] = {
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst},
{ BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|
{ BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYPREMUL|
ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYPREMUL|
ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
{ CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word},
{ CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed},
{ CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3},
@ -3054,6 +3457,10 @@ static const cmsFormatters16 InputFormatters16[] = {
{ BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords},
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords},
{ BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollPlanarWordsPremul},
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollAnyWordsPremul}
};
@ -3069,13 +3476,23 @@ static const cmsFormattersFloat InputFormattersFloat[] = {
{ TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat},
{ FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat},
ANYPREMUL|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat},
{ FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat},
ANYCHANNELS|ANYSPACE|ANYPREMUL, UnrollDoublesToFloat},
{ TYPE_LabV2_8, 0, UnrollLabV2_8ToFloat },
{ TYPE_ALabV2_8, 0, UnrollALabV2_8ToFloat },
{ TYPE_LabV2_16, 0, UnrollLabV2_16ToFloat },
{ BYTES_SH(1), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE, Unroll8ToFloat},
{ BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE, Unroll16ToFloat},
#ifndef CMS_NO_HALF_SUPPORT
{ FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
#endif
};
@ -3169,16 +3586,20 @@ static const cmsFormatters16 OutputFormatters16[] = {
ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst},
{ CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap},
{ CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap},
{ CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes},
{ CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes},
{ CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse},
{ CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst},
{ CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes},
{ CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap},
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
{ BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|
ANYSPACE|ANYPREMUL, PackChunkyBytes},
{ BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarBytes},
{ CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word},
{ CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1},
@ -3203,9 +3624,11 @@ static const cmsFormatters16 OutputFormatters16[] = {
{ CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words},
{ CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap},
{ BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords},
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|
ANYEXTRA|ANYCHANNELS|ANYSPACE|ANYPREMUL, PackChunkyWords},
{ BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|
ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarWords}
};

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -671,17 +671,65 @@ static struct _cmsContext_struct globalContext = {
static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
// Make sure context is initialized (needed on windows)
static
cmsBool InitContextMutex(void)
{
// 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 cmsBool already_initialized = FALSE;
if (!already_initialized)
{
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)
{
cmsSignalError(0, cmsERROR_INTERNAL, "Mutex lock failed");
return FALSE;
}
if (((void**)&_cmsContextPoolHeadMutex)[0] == NULL)
InitializeCriticalSection(&_cmsContextPoolHeadMutex);
if (*mutex == NULL || !ReleaseMutex(*mutex))
{
cmsSignalError(0, cmsERROR_INTERNAL, "Mutex unlock failed");
return FALSE;
}
already_initialized = TRUE;
}
#endif
#endif
#endif
return TRUE;
}
// 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;
InitContextMutex();
// Search
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
@ -784,31 +832,7 @@ 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
if (!InitContextMutex()) return NULL;
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
@ -884,6 +908,8 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
if (ctx == NULL)
return NULL; // Something very wrong happened
if (!InitContextMutex()) return NULL;
// Setup default memory allocators
memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
@ -943,6 +969,9 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
struct _cmsContext_struct fakeContext;
struct _cmsContext_struct* prev;
InitContextMutex();
memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
@ -989,3 +1018,32 @@ void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
}
// Use context mutex to provide thread-safe time
cmsBool _cmsGetTime(struct tm* ptr_time)
{
struct tm* t;
#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
struct tm tm;
#endif
time_t now = time(NULL);
#ifdef HAVE_GMTIME_R
t = gmtime_r(&now, &tm);
#elif defined(HAVE_GMTIME_S)
t = gmtime_s(&tm, &now) == 0 ? &tm : NULL;
#else
if (!InitContextMutex()) return FALSE;
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
t = gmtime(&now);
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
#endif
if (t == NULL)
return FALSE;
else {
*ptr_time = *t;
return TRUE;
}
}

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -134,15 +134,62 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t*
return TRUE;
}
// Try to promote correctly to wchar_t when 32 bits
cmsINLINE cmsBool is_surrogate(cmsUInt32Number uc) { return (uc - 0xd800u) < 2048u; }
cmsINLINE cmsBool is_high_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xd800; }
cmsINLINE cmsBool is_low_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xdc00; }
cmsINLINE cmsUInt32Number surrogate_to_utf32(cmsUInt32Number high, cmsUInt32Number low)
{
return (high << 10) + low - 0x35fdc00;
}
cmsINLINE cmsBool convert_utf16_to_utf32(cmsIOHANDLER* io, cmsInt32Number n, wchar_t* output)
{
cmsUInt16Number uc;
while (n > 0)
{
if (!_cmsReadUInt16Number(io, &uc)) return FALSE;
n--;
if (!is_surrogate(uc))
{
*output++ = (wchar_t)uc;
}
else {
cmsUInt16Number low;
if (!_cmsReadUInt16Number(io, &low)) return FALSE;
n--;
if (is_high_surrogate(uc) && is_low_surrogate(low))
*output++ = (wchar_t)surrogate_to_utf32(uc, low);
else
return FALSE; // Corrupted string, just ignore
}
}
return TRUE;
}
// Auxiliary to read an array of wchar_t
static
cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
{
cmsUInt32Number i;
cmsUInt16Number tmp;
cmsBool is32 = sizeof(wchar_t) > sizeof(cmsUInt16Number);
_cmsAssert(io != NULL);
if (is32 && Array != NULL)
{
return convert_utf16_to_utf32(io, n, Array);
}
for (i=0; i < n; i++) {
if (Array != NULL) {
@ -1307,7 +1354,7 @@ void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
//
// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
// time to UTC when setting these values. Programmes that display these values may show
// time to UTC when setting these values. Programs that display these values may show
// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
// display both UTC and local versions of the dateTimeNumber.
@ -1746,7 +1793,7 @@ cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
// 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust
// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
static
@ -1853,7 +1900,7 @@ Error:
static
cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
cmsUInt32Number j, nTabSize, i, n;
cmsUInt32Number j, nTabSize, i;
cmsUInt8Number val;
cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
cmsStage* mpe;
@ -1902,8 +1949,6 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
n = NewLUT->InputChannels * NewLUT->OutputChannels;
if (MatMPE != NULL) {
for (i = 0; i < 9; i++)
@ -3168,8 +3213,8 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER
if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
memcpy(prefix, (const char*) NamedColorList->Prefix, sizeof(prefix));
memcpy(suffix, (const char*) NamedColorList->Suffix, sizeof(suffix));
suffix[32] = prefix[32] = 0;
@ -3182,6 +3227,10 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER
cmsUInt16Number Colorant[cmsMAXCHANNELS];
char Root[cmsMAX_PATH];
memset(Root, 0, sizeof(Root));
memset(PCS, 0, sizeof(PCS));
memset(Colorant, 0, sizeof(Colorant));
if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
Root[32] = 0;
if (!io ->Write(io, 32 , Root)) return FALSE;
@ -3515,47 +3564,68 @@ void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
{
cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
cmsUInt32Number CountUcr, CountBg;
cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
char* ASCIIString;
*nItems = 0;
if (n == NULL) return NULL;
// First curve is Under color removal
if (SignedSizeOfTag < (cmsInt32Number) sizeof(cmsUInt32Number)) return NULL;
if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
if (n ->Ucr == NULL) return NULL;
if (n ->Ucr == NULL) goto error;
if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
if (SignedSizeOfTag < (cmsInt32Number)(CountUcr * sizeof(cmsUInt16Number))) goto error;
if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) goto error;
SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
// Second curve is Black generation
if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
if (SignedSizeOfTag < (cmsInt32Number)sizeof(cmsUInt32Number)) goto error;
if (!_cmsReadUInt32Number(io, &CountBg)) goto error;
SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
if (n ->Bg == NULL) return NULL;
if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
if (SizeOfTag == UINT_MAX) return NULL;
if (n ->Bg == NULL) goto error;
if (SignedSizeOfTag < (cmsInt32Number) (CountBg * sizeof(cmsUInt16Number))) goto error;
if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) goto error;
SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) goto error;
// Now comes the text. The length is specified by the tag size
n ->Desc = cmsMLUalloc(self ->ContextID, 1);
if (n ->Desc == NULL) return NULL;
if (n ->Desc == NULL) goto error;
ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
ASCIIString[SizeOfTag] = 0;
ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
if (io->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number)SignedSizeOfTag)
{
_cmsFree(self->ContextID, ASCIIString);
goto error;
}
ASCIIString[SignedSizeOfTag] = 0;
cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
_cmsFree(self ->ContextID, ASCIIString);
*nItems = 1;
return (void*) n;
error:
if (n->Ucr) cmsFreeToneCurve(n->Ucr);
if (n->Bg) cmsFreeToneCurve(n->Bg);
if (n->Desc) cmsMLUfree(n->Desc);
_cmsFree(self->ContextID, n);
*nItems = 0;
return NULL;
}
static
@ -3969,41 +4039,44 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
switch (ElementSig) {
case cmsSigFormulaCurveSeg: {
case cmsSigFormulaCurveSeg: {
cmsUInt16Number Type;
cmsUInt32Number ParamsByType[] = {4, 5, 5 };
cmsUInt16Number Type;
cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
if (!_cmsReadUInt16Number(io, &Type)) goto Error;
if (!_cmsReadUInt16Number(io, NULL)) goto Error;
if (!_cmsReadUInt16Number(io, &Type)) goto Error;
if (!_cmsReadUInt16Number(io, NULL)) goto Error;
Segments[i].Type = Type + 6;
if (Type > 2) goto Error;
Segments[i].Type = Type + 6;
if (Type > 2) goto Error;
for (j=0; j < ParamsByType[Type]; j++) {
for (j = 0; j < ParamsByType[Type]; j++) {
cmsFloat32Number f;
if (!_cmsReadFloat32Number(io, &f)) goto Error;
Segments[i].Params[j] = f;
}
}
break;
cmsFloat32Number f;
if (!_cmsReadFloat32Number(io, &f)) goto Error;
Segments[i].Params[j] = f;
}
}
break;
case cmsSigSampledCurveSeg: {
cmsUInt32Number Count;
case cmsSigSampledCurveSeg: {
cmsUInt32Number Count;
if (!_cmsReadUInt32Number(io, &Count)) goto Error;
if (!_cmsReadUInt32Number(io, &Count)) goto Error;
Segments[i].nGridPoints = Count;
Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
if (Segments[i].SampledPoints == NULL) goto Error;
// The first point is implicit in the last stage, we allocate an extra note to be populated latter on
Count++;
Segments[i].nGridPoints = Count;
Segments[i].SampledPoints = (cmsFloat32Number*)_cmsCalloc(self->ContextID, Count, sizeof(cmsFloat32Number));
if (Segments[i].SampledPoints == NULL) goto Error;
for (j=0; j < Count; j++) {
if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
}
}
break;
Segments[i].SampledPoints[0] = 0;
for (j = 1; j < Count; j++) {
if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
}
}
break;
default:
{
@ -4023,6 +4096,17 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
}
_cmsFree(self ->ContextID, Segments);
// Explore for missing implicit points
for (i = 0; i < nSegments; i++) {
// If sampled curve, fix it
if (Curve->Segments[i].Type == 0) {
Curve->Segments[i].SampledPoints[0] = cmsEvalToneCurveFloat(Curve, Curve->Segments[i].x0);
}
}
return Curve;
Error:
@ -4117,12 +4201,12 @@ cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
if (ActualSeg -> Type == 0) {
// This is a sampled curve
// This is a sampled curve. First point is implicit in the ICC format, but not in our representation
if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
if (!_cmsWriteUInt32Number(io, 0)) goto Error;
if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints - 1)) goto Error;
for (j=0; j < g ->Segments[i].nGridPoints; j++) {
for (j=1; j < g ->Segments[i].nGridPoints; j++) {
if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
}
@ -4499,7 +4583,7 @@ Error:
// This one is a liitle bit more complex, so we don't use position tables this time.
// This one is a little bit more complex, so we don't use position tables this time.
static
cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
@ -4931,7 +5015,7 @@ cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUIn
if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
// An offset of zero has special meaning and shal be preserved
// An offset of zero has special meaning and shall be preserved
if (e ->Offsets[i] > 0)
e ->Offsets[i] += BaseOffset;
return TRUE;
@ -4939,27 +5023,41 @@ cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUIn
static
cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a,
cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset,
cmsInt32Number* SignedSizeOfTagPtr)
{
cmsUInt32Number i;
cmsInt32Number SignedSizeOfTag = *SignedSizeOfTagPtr;
// Read column arrays
for (i=0; i < Count; i++) {
if (SignedSizeOfTag < 4 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
SignedSizeOfTag -= 4 * sizeof(cmsUInt32Number);
if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
if (Length > 16) {
if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
SignedSizeOfTag -= 2 * sizeof(cmsUInt32Number);
if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
}
if (Length > 24) {
if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
SignedSizeOfTag -= 2 * (cmsInt32Number) sizeof(cmsUInt32Number);
if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
}
}
*SignedSizeOfTagPtr = SignedSizeOfTag;
return TRUE;
}
@ -5107,26 +5205,31 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _c
static
void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
{
cmsHANDLE hDict;
cmsHANDLE hDict = NULL;
cmsUInt32Number i, Count, Length;
cmsUInt32Number BaseOffset;
_cmsDICarray a;
wchar_t *NameWCS = NULL, *ValueWCS = NULL;
cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
cmsBool rc;
cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
*nItems = 0;
memset(&a, 0, sizeof(a));
// Get actual position as a basis for element offsets
BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
// Get name-value record count
SignedSizeOfTag -= sizeof(cmsUInt32Number);
if (SignedSizeOfTag < 0) goto Error;
if (!_cmsReadUInt32Number(io, &Count)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
// Get rec length
SignedSizeOfTag -= sizeof(cmsUInt32Number);
if (SignedSizeOfTag < 0) goto Error;
if (!_cmsReadUInt32Number(io, &Length)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
// Check for valid lengths
if (Length != 16 && Length != 24 && Length != 32) {
@ -5142,7 +5245,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
// Read column arrays
if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset, &SignedSizeOfTag)) goto Error;
// Seek to each element and read it
for (i=0; i < Count; i++) {
@ -5182,7 +5285,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
Error:
FreeArray(&a);
cmsDictFree(hDict);
if (hDict != NULL) cmsDictFree(hDict);
return NULL;
}

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -368,7 +368,7 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI
InkLimit = (InkLimit * 655.35);
SumCMY = In[0] + In[1] + In[2];
SumCMY = (cmsFloat64Number) In[0] + In[1] + In[2];
SumCMYK = SumCMY + In[3];
if (SumCMYK > InkLimit) {

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -264,16 +264,16 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
// 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
// aspects of the RGB to XYZ process, and assuming that the gamma correction
// has transitive property in the transformation chain.
//
// the alghoritm:
// the algorithm:
//
// - 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
// obtaining the coefficients of the transformation
// - Then, I apply these coefficients to the original matrix
//
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
{

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -284,7 +284,7 @@ void FloatXFORM(_cmsTRANSFORM* p,
accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
// Any gamut chack to do?
// Any gamut check to do?
if (p->GamutCheck != NULL) {
// Evaluate gamut marker.
@ -846,7 +846,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
}
// Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
if (_cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
@ -1081,6 +1081,15 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
return NULL;
}
// Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations
if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE))
{
cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1);
if (gamma > 0 && gamma < 1.6)
dwFlags |= cmsFLAGS_NOOPTIMIZE;
}
// Create a pipeline with all transformations
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) {

View file

@ -1,7 +1,7 @@
//
// Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer
// Copyright (c) 1998-2022 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"),
@ -1118,5 +1118,8 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsC
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
// thread-safe gettime
cmsBool _cmsGetTime(struct tm* ptr_time);
#define _lcms_internal_H
#endif