📄 cmsps2.c
字号:
//// Little cms// Copyright (C) 1998-2005 Marti Maria//// 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.// Postscript level 2 operators#include "lcms.h"#include <time.h>#include <stdarg.h>// PostScript ColorRenderingDictionary and ColorSpaceArrayLCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen);LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, DWORD dwFlags, LPVOID Buffer, DWORD dwBufferLen);// -------------------------------------------------------------------- Implementation#define MAXPSCOLS 60 // Columns on tables/* Implementation -------------- PostScript does use XYZ as its internal PCS. But since PostScript interpolation tables are limited to 8 bits, I use Lab as a way to improve the accuracy, favoring perceptual results. So, for the creation of each CRD, CSA the profiles are converted to Lab via a device link between profile -> Lab or Lab -> profile. The PS code necessary to convert Lab <-> XYZ is also included. Color Space Arrays (CSA) ================================================================================== In order to obtain precission, code chooses between three ways to implement the device -> XYZ transform. These cases identifies monochrome profiles (often implemented as a set of curves), matrix-shaper and LUT-based. Monochrome ----------- This is implemented as /CIEBasedA CSA. The prelinearization curve is placed into /DecodeA section, and matrix equals to D50. Since here is no interpolation tables, I do the conversion directly to XYZ NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT flag is forced on such profiles. [ /CIEBasedA << /DecodeA { transfer function } bind /MatrixA [D50] /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ] /WhitePoint [D50] /BlackPoint [BP] /RenderingIntent (intent) >> ] On simpler profiles, the PCS is already XYZ, so no conversion is required. Matrix-shaper based ------------------- This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig of profile implementation. Since here is no interpolation tables, I do the conversion directly to XYZ [ /CIEBasedABC << /DecodeABC [ {transfer1} {transfer2} {transfer3} ] /MatrixABC [Matrix] /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ] /DecodeLMN [ { / 2} dup dup ] /WhitePoint [D50] /BlackPoint [BP] /RenderingIntent (intent) >> ] CLUT based ---------- Lab is used in such cases. [ /CIEBasedDEF << /DecodeDEF [ <prelinearization> ] /Table [ p p p [<...>]] /RangeABC [ 0 1 0 1 0 1] /DecodeABC[ <postlinearization> ] /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /WhitePoint [D50] /BlackPoint [BP] /RenderingIntent (intent) ] Color Rendering Dictionaries (CRD) ================================== These are always implemented as CLUT, and always are using Lab. Since CRD are expected to be used as resources, the code adds the definition as well. << /ColorRenderingType 1 /WhitePoint [ D50 ] /BlackPoint [BP] /MatrixPQR [ Bradford ] /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ] /TransformPQR [ {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind ] /MatrixABC <...> /EncodeABC <...> /RangeABC <.. used for XYZ -> Lab> /EncodeLMN /RenderTable [ p p p [<...>]] /RenderingIntent (Perceptual) >> /Current exch /ColorRendering defineresource pop The following stages are used to convert from XYZ to Lab -------------------------------------------------------- Input is given at LMN stage on X, Y, Z Encode LMN gives us f(X/Xn), f(Y/Yn), f(Z/Zn) /EncodeLMN [ { 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind { 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind { 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind ] MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn) | 0 1 0| | 1 -1 0| | 0 1 -1| /MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ] EncodeABC finally gives Lab values. /EncodeABC [ { 116 mul 16 sub 100 div } bind { 500 mul 128 add 255 div } bind { 200 mul 128 add 255 div } bind ] The following stages are used to convert Lab to XYZ ---------------------------------------------------- /RangeABC [ 0 1 0 1 0 1] /DecodeABC [ { 100 mul 16 add 116 div } bind { 255 mul 128 sub 500 div } bind { 255 mul 128 sub 200 div } bind ] /MatrixABC [ 1 1 1 1 0 0 0 0 -1] /DecodeLMN [ {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind ]*//* PostScript algorithms discussion. ========================================================================================================= 1D interpolation algorithm 1D interpolation (float) ------------------------ val2 = Domain * Value; cell0 = (int) floor(val2); cell1 = (int) ceil(val2); rest = val2 - cell0; y0 = LutTable[cell0] ; y1 = LutTable[cell1] ; y = y0 + (y1 - y0) * rest; PostScript code Stack ================================================ { % v <check 0..1.0> [array] % v tab dup % v tab tab length 1 sub % v tab dom 3 -1 roll % tab dom v mul % tab val2 dup % tab val2 val2 dup % tab val2 val2 val2 floor cvi % tab val2 val2 cell0 exch % tab val2 cell0 val2 ceiling cvi % tab val2 cell0 cell1 3 index % tab val2 cell0 cell1 tab exch % tab val2 cell0 tab cell1 get % tab val2 cell0 y1 4 -1 roll % val2 cell0 y1 tab 3 -1 roll % val2 y1 tab cell0 get % val2 y1 y0 dup % val2 y1 y0 y0 3 1 roll % val2 y0 y1 y0 sub % val2 y0 (y1-y0) 3 -1 roll % y0 (y1-y0) val2 dup % y0 (y1-y0) val2 val2 floor cvi % y0 (y1-y0) val2 floor(val2) sub % y0 (y1-y0) rest mul % y0 t1 add % y 65535 div % result } bind*/static icTagSignature Device2PCSTab[] = {icSigAToB0Tag, // Perceptual icSigAToB1Tag, // Relative colorimetric icSigAToB2Tag, // Saturation icSigAToB1Tag }; // Absolute colorimetric // (Relative/WhitePoint)// --------------------------------------------------------------- Memory Stream//// This struct holds the memory block currently being write//typedef struct { LPBYTE Block; LPBYTE Ptr; DWORD dwMax; DWORD dwUsed; int MaxCols; int Col; int HasError; } MEMSTREAM, FAR* LPMEMSTREAM;typedef struct { LPLUT Lut; LPMEMSTREAM m; int FirstComponent; int SecondComponent; int bps; const char* PreMaj; const char* PostMaj; const char* PreMin; const char* PostMin; int lIsInput; // Handle L* encoding int FixWhite; // Force mapping of pure white icColorSpaceSignature ColorSpace; // ColorSpace of profile } SAMPLERCARGO, FAR* LPSAMPLERCARGO;// Creates a ready to use memory streamstaticLPMEMSTREAM CreateMemStream(LPBYTE Buffer, DWORD dwMax, int MaxCols){ LPMEMSTREAM m = (LPMEMSTREAM) malloc(sizeof(MEMSTREAM)); ZeroMemory(m, sizeof(MEMSTREAM)); m -> Block = m -> Ptr = Buffer; m -> dwMax = dwMax; m -> dwUsed = 0; m -> MaxCols = MaxCols; m -> Col = 0; m -> HasError = 0; return m;}// Convert to bytestaticBYTE Word2Byte(WORD w){ return (BYTE) floor((double) w / 257.0 + 0.5);}// Convert to byte (using ICC2 notation)staticBYTE L2Byte(WORD w){ int ww = w + 0x0080; if (ww > 0xFFFF) return 0xFF; return (BYTE) ((WORD) (ww >> 8) & 0xFF);}// Write a raw, uncooked byte. Check for spacestaticvoid WriteRawByte(LPMEMSTREAM m, BYTE b){ if (m -> dwUsed + 1 > m -> dwMax) { m -> HasError = 1; } if (!m ->HasError && m ->Block) { *m ->Ptr++ = b; } m -> dwUsed++;}// Write a cooked bytestaticvoid WriteByte(LPMEMSTREAM m, BYTE b){ static const BYTE Hex[] = "0123456789ABCDEF"; BYTE c; c = Hex[(b >> 4) & 0x0f]; WriteRawByte(m, c); c = Hex[b & 0x0f]; WriteRawByte(m, c); m -> Col += 2; if (m -> Col > m -> MaxCols) { WriteRawByte(m, '\n'); m -> Col = 0; } }// Does write a formatted stringstaticvoid Writef(LPMEMSTREAM m, const char *frm, ...){ va_list args; LPBYTE pt; BYTE Buffer[2048]; va_start(args, frm); vsprintf((char*) Buffer, frm, args); for (pt = Buffer; *pt; pt++) { WriteRawByte(m, *pt); } va_end(args); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -