jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c
changeset 6482 0f6a4442b29e
parent 5506 202f599c92aa
child 14300 117dc9b98a7b
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2008 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"),
@@ -48,22 +49,14 @@
 // 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>
+#include "lcms2_internal.h"
 
 // PostScript ColorRenderingDictionary and ColorSpaceArray
 
-LCMSAPI 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
 
@@ -83,9 +76,9 @@
   Color Space Arrays (CSA)
   ==================================================================================
 
-  In order to obtain precission, code chooses between three ways to implement
+  In order to obtain precision, code chooses between three ways to implement
   the device -> XYZ transform. These cases identifies monochrome profiles (often
-  implemented as a set of curves), matrix-shaper and LUT-based.
+  implemented as a set of curves), matrix-shaper and Pipeline-based.
 
   Monochrome
   -----------
@@ -101,7 +94,7 @@
       <<
             /DecodeA { transfer function } bind
             /MatrixA [D50]
-            /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ]
+            /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
             /WhitePoint [D50]
             /BlackPoint [BP]
             /RenderingIntent (intent)
@@ -115,7 +108,7 @@
    -------------------
 
    This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig
-   of profile implementation. Since here is no interpolation tables, I do
+   of profile implementation. Since here there are no interpolation tables, I do
    the conversion directly to XYZ
 
 
@@ -124,7 +117,7 @@
             <<
                 /DecodeABC [ {transfer1} {transfer2} {transfer3} ]
                 /MatrixABC [Matrix]
-                /RangeLMN [ 0.0 D50X 0.0 D50Y 0.0 D50Z ]
+                /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
                 /DecodeLMN [ { / 2} dup dup ]
                 /WhitePoint [D50]
                 /BlackPoint [BP]
@@ -299,153 +292,66 @@
 
 */
 
-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 {
+    _cmsStageCLutData* Pipeline;
+    cmsIOHANDLER* m;
+
+    int FirstComponent;
+    int SecondComponent;
 
-typedef struct {
-                LPBYTE Block;
-                LPBYTE Ptr;
-                DWORD  dwMax;
-                DWORD  dwUsed;
-                int    MaxCols;
-                int    Col;
-                int    HasError;
+    const char* PreMaj;
+    const char* PostMaj;
+    const char* PreMin;
+    const char* PostMin;
 
-            } MEMSTREAM, FAR* LPMEMSTREAM;
+    int  FixWhite;    // Force mapping of pure white
+
+    cmsColorSpaceSignature  ColorSpace;  // ColorSpace of profile
 
 
-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;
+} cmsPsSamplerCargo;
 
-
-// Creates a ready to use memory stream
-static
-LPMEMSTREAM CreateMemStream(LPBYTE Buffer, DWORD dwMax, int MaxCols)
-{
-    LPMEMSTREAM m = (LPMEMSTREAM) _cmsMalloc(sizeof(MEMSTREAM));
-    if (m == NULL) return NULL;
-
-    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;
-}
-
+static int _cmsPSActualColumn = 0;
 
 
 // Convert to byte
 static
-BYTE Word2Byte(WORD w)
+cmsUInt8Number Word2Byte(cmsUInt16Number w)
 {
-    return (BYTE) floor((double) w / 257.0 + 0.5);
+    return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
 }
 
 
 // Convert to byte (using ICC2 notation)
-
-static
-BYTE 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 space
+/*
 static
-void WriteRawByte(LPMEMSTREAM m, BYTE b)
+cmsUInt8Number L2Byte(cmsUInt16Number w)
 {
-    if (m -> dwUsed + 1 > m -> dwMax) {
-        m -> HasError = 1;
-    }
+        int ww = w + 0x0080;
 
-    if (!m ->HasError && m ->Block) {
-        *m ->Ptr++ = b;
-    }
+        if (ww > 0xFFFF) return 0xFF;
 
-    m -> dwUsed++;
+    return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
 }
+*/
 
 // Write a cooked byte
+
 static
-void WriteByte(LPMEMSTREAM m, BYTE b)
+void WriteByte(cmsIOHANDLER* m, cmsUInt8Number 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;
-        }
-
-}
+    _cmsIOPrintf(m, "%02x", b);
+    _cmsPSActualColumn += 2;
 
-// Does write a formatted string. Guaranteed to be 2048 bytes at most.
-static
-void Writef(LPMEMSTREAM m, const char *frm, ...)
-{
-        va_list args;
-        LPBYTE pt;
-        BYTE Buffer[2048];
-
-        va_start(args, frm);
+    if (_cmsPSActualColumn > MAXPSCOLS) {
 
-        vsnprintf((char*) Buffer, 2048, frm, args);
-
-        for (pt = Buffer; *pt; pt++)  {
-
-            WriteRawByte(m, *pt);
-        }
-
-        va_end(args);
+        _cmsIOPrintf(m, "\n");
+        _cmsPSActualColumn = 0;
+    }
 }
 
-
-
 // ----------------------------------------------------------------- PostScript generation
 
 
@@ -466,21 +372,31 @@
 }
 
 static
-void EmitHeader(LPMEMSTREAM m, const char* Title, cmsHPROFILE hProfile)
+void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
 {
-
     time_t timer;
+    cmsMLU *Description, *Copyright;
+    char DescASCII[256], CopyrightASCII[256];
 
     time(&timer);
 
-    Writef(m, "%%!PS-Adobe-3.0\n");
-    Writef(m, "%%\n");
-    Writef(m, "%% %s\n", Title);
-    Writef(m, "%% Source: %s\n", RemoveCR(cmsTakeProductName(hProfile)));
-    Writef(m, "%% Description: %s\n", RemoveCR(cmsTakeProductDesc(hProfile)));
-    Writef(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!!
-    Writef(m, "%%\n");
-    Writef(m, "%%%%BeginResource\n");
+    Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
+    Copyright   = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
+
+    DescASCII[0] = DescASCII[255] = 0;
+    CopyrightASCII[0] = CopyrightASCII[255] = 0;
+
+    if (Description != NULL) cmsMLUgetASCII(Description,  cmsNoLanguage, cmsNoCountry, DescASCII,       255);
+    if (Copyright != NULL)   cmsMLUgetASCII(Copyright,    cmsNoLanguage, cmsNoCountry, CopyrightASCII,  255);
+
+    _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n");
+    _cmsIOPrintf(m, "%%\n");
+    _cmsIOPrintf(m, "%% %s\n", Title);
+    _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII));
+    _cmsIOPrintf(m, "%%         %s\n", RemoveCR(CopyrightASCII));
+    _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!!
+    _cmsIOPrintf(m, "%%\n");
+    _cmsIOPrintf(m, "%%%%BeginResource\n");
 
 }
 
@@ -489,31 +405,31 @@
 // Black point adapted to D50.
 
 static
-void EmitWhiteBlackD50(LPMEMSTREAM m, LPcmsCIEXYZ BlackPoint)
+void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint)
 {
 
-    Writef(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
+    _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
                                           BlackPoint -> Y,
                                           BlackPoint -> Z);
 
-    Writef(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
+    _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
                                           cmsD50_XYZ()->Y,
                                           cmsD50_XYZ()->Z);
 }
 
 
 static
-void EmitRangeCheck(LPMEMSTREAM m)
+void EmitRangeCheck(cmsIOHANDLER* m)
 {
-    Writef(m, "dup 0.0 lt { pop 0.0 } if "
-              "dup 1.0 gt { pop 1.0 } if ");
+    _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if "
+                    "dup 1.0 gt { pop 1.0 } if ");
 
 }
 
 // Does write the intent
 
 static
-void EmitIntent(LPMEMSTREAM m, int RenderingIntent)
+void EmitIntent(cmsIOHANDLER* m, int RenderingIntent)
 {
     const char *intent;
 
@@ -527,7 +443,7 @@
         default: intent = "Undefined"; break;
     }
 
-    Writef(m, "/RenderingIntent (%s)\n", intent );
+    _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
 }
 
 //
@@ -539,9 +455,9 @@
 
 /*
 static
-void EmitL2Y(LPMEMSTREAM m)
+void EmitL2Y(cmsIOHANDLER* m)
 {
-    Writef(m,
+    _cmsIOPrintf(m,
             "{ "
                 "100 mul 16 add 116 div "               // (L * 100 + 16) / 116
                  "dup 6 29 div ge "                     // >= 6 / 29 ?
@@ -555,21 +471,21 @@
 // Lab -> XYZ, see the discussion above
 
 static
-void EmitLab2XYZ(LPMEMSTREAM m)
+void EmitLab2XYZ(cmsIOHANDLER* m)
 {
-    Writef(m, "/RangeABC [ 0 1 0 1 0 1]\n");
-    Writef(m, "/DecodeABC [\n");
-    Writef(m, "{100 mul  16 add 116 div } bind\n");
-    Writef(m, "{255 mul 128 sub 500 div } bind\n");
-    Writef(m, "{255 mul 128 sub 200 div } bind\n");
-    Writef(m, "]\n");
-    Writef(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
-    Writef(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
-    Writef(m, "/DecodeLMN [\n");
-    Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
-    Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
-    Writef(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
-    Writef(m, "]\n");
+    _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
+    _cmsIOPrintf(m, "/DecodeABC [\n");
+    _cmsIOPrintf(m, "{100 mul  16 add 116 div } bind\n");
+    _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
+    _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
+    _cmsIOPrintf(m, "]\n");
+    _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
+    _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
+    _cmsIOPrintf(m, "/DecodeLMN [\n");
+    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
+    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
+    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
+    _cmsIOPrintf(m, "]\n");
 }
 
 
@@ -577,29 +493,25 @@
 // Outputs a table of words. It does use 16 bits
 
 static
-void Emit1Gamma(LPMEMSTREAM m, LPWORD Table, int nEntries)
+void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
 {
-    int i;
-    double gamma;
+    cmsUInt32Number i;
+    cmsFloat64Number gamma;
 
 
-    if (nEntries <= 0) return;  // Empty table
+    if (Table ->nEntries <= 0) return;  // Empty table
 
     // Suppress whole if identity
-    if (cmsIsLinear(Table, nEntries)) {
-            Writef(m, "{} ");
-            return;
-    }
-
+    if (cmsIsToneCurveLinear(Table)) return;
 
     // Check if is really an exponential. If so, emit "exp"
-     gamma = cmsEstimateGammaEx(Table, nEntries, 0.001);
+    gamma = cmsEstimateGamma(Table, 0.001);
      if (gamma > 0) {
-            Writef(m, "{ %g exp } bind ", gamma);
+            _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
             return;
      }
 
-    Writef(m, "{ ");
+    _cmsIOPrintf(m, "{ ");
 
     // Bounds check
     EmitRangeCheck(m);
@@ -609,94 +521,74 @@
     // PostScript code                      Stack
     // ===============                      ========================
                                             // v
-    Writef(m, " [");
+    _cmsIOPrintf(m, " [");
 
-    // TODO: Check for endianess!!!
-
-    for (i=0; i < nEntries; i++) {
-            Writef(m, "%d ", Table[i]);
+    for (i=0; i < Table->nEntries; i++) {
+        _cmsIOPrintf(m, "%d ", Table->Table16[i]);
     }
 
-    Writef(m, "] ");                        // v tab
+    _cmsIOPrintf(m, "] ");                        // v tab
 
-    Writef(m, "dup ");                      // v tab tab
-    Writef(m, "length 1 sub ");             // v tab dom
-    Writef(m, "3 -1 roll ");                // tab dom v
-    Writef(m, "mul ");                      // tab val2
-    Writef(m, "dup ");                      // tab val2 val2
-    Writef(m, "dup ");                      // tab val2 val2 val2
-    Writef(m, "floor cvi ");                // tab val2 val2 cell0
-    Writef(m, "exch ");                     // tab val2 cell0 val2
-    Writef(m, "ceiling cvi ");              // tab val2 cell0 cell1
-    Writef(m, "3 index ");                  // tab val2 cell0 cell1 tab
-    Writef(m, "exch ");                     // tab val2 cell0 tab cell1
-    Writef(m, "get ");                      // tab val2 cell0 y1
-    Writef(m, "4 -1 roll ");                // val2 cell0 y1 tab
-    Writef(m, "3 -1 roll ");                // val2 y1 tab cell0
-    Writef(m, "get ");                      // val2 y1 y0
-    Writef(m, "dup ");                      // val2 y1 y0 y0
-    Writef(m, "3 1 roll ");                 // val2 y0 y1 y0
-    Writef(m, "sub ");                      // val2 y0 (y1-y0)
-    Writef(m, "3 -1 roll ");                // y0 (y1-y0) val2
-    Writef(m, "dup ");                      // y0 (y1-y0) val2 val2
-    Writef(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
-    Writef(m, "sub ");                      // y0 (y1-y0) rest
-    Writef(m, "mul ");                      // y0 t1
-    Writef(m, "add ");                      // y
-    Writef(m, "65535 div ");                // result
+    _cmsIOPrintf(m, "dup ");                      // v tab tab
+    _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
+    _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
+    _cmsIOPrintf(m, "mul ");                      // tab val2
+    _cmsIOPrintf(m, "dup ");                      // tab val2 val2
+    _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
+    _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
+    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
+    _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
+    _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab
+    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
+    _cmsIOPrintf(m, "get ");                      // tab val2 cell0 y1
+    _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
+    _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0
+    _cmsIOPrintf(m, "get ");                      // val2 y1 y0
+    _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
+    _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0
+    _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
+    _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
+    _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
+    _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
+    _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
+    _cmsIOPrintf(m, "mul ");                      // y0 t1
+    _cmsIOPrintf(m, "add ");                      // y
+    _cmsIOPrintf(m, "65535 div ");                // result
 
-    Writef(m, " } bind ");
+    _cmsIOPrintf(m, " } bind ");
 }
 
 
 // Compare gamma table
 
 static
-LCMSBOOL GammaTableEquals(LPWORD g1, LPWORD g2, int nEntries)
+cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
 {
-    return memcmp(g1, g2, nEntries* sizeof(WORD)) == 0;
+    return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
 }
 
 
 // Does write a set of gamma curves
 
 static
-void EmitNGamma(LPMEMSTREAM m, int n, LPWORD g[], int nEntries)
+void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
 {
     int i;
 
     for( i=0; i < n; i++ )
     {
-        if (i > 0 && GammaTableEquals(g[i-1], g[i], nEntries)) {
+        if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
 
-            Writef(m, "dup ");
+            _cmsIOPrintf(m, "dup ");
         }
         else {
-            Emit1Gamma(m, g[i], nEntries);
+            Emit1Gamma(m, g[i]);
         }
     }
 
 }
 
 
-// Check whatever a profile has CLUT tables (only on input)
-
-static
-LCMSBOOL IsLUTbased(cmsHPROFILE hProfile, int Intent)
-{
-    icTagSignature Tag;
-
-    // Check if adequate tag is present
-    Tag = Device2PCSTab[Intent];
-
-    if (cmsIsTag(hProfile, Tag)) return 1;
-
-    // If not present, revert to default (perceptual)
-    Tag = icSigAToB0Tag;
-
-    // If no tag present, try matrix-shaper
-    return cmsIsTag(hProfile, Tag);
-}
 
 
 
@@ -707,19 +599,19 @@
 // that is, the callback will be called for each knot with
 //
 //          In[]  The grid location coordinates, normalized to 0..ffff
-//          Out[] The LUT values, normalized to 0..ffff
+//          Out[] The Pipeline values, normalized to 0..ffff
 //
 //  Returning a value other than 0 does terminate the sampling process
 //
-//  Each row contains LUT values for all but first component. So, I
+//  Each row contains Pipeline values for all but first component. So, I
 //  detect row changing by keeping a copy of last value of first
 //  component. -1 is used to mark begining of whole block.
 
 static
-int OutputValueSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
 {
-    LPSAMPLERCARGO sc = (LPSAMPLERCARGO) Cargo;
-    unsigned int i;
+    cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
+    cmsUInt32Number i;
 
 
     if (sc -> FixWhite) {
@@ -729,14 +621,14 @@
             if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
                 (In[2] >= 0x7800 && In[2] <= 0x8800)) {
 
-                WORD* Black;
-                WORD* White;
-                int nOutputs;
+                cmsUInt16Number* Black;
+                cmsUInt16Number* White;
+                cmsUInt32Number nOutputs;
 
                 if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
                         return 0;
 
-                for (i=0; i < (unsigned int) nOutputs; i++)
+                for (i=0; i < nOutputs; i++)
                         Out[i] = White[i];
             }
 
@@ -751,15 +643,15 @@
 
             if (sc ->FirstComponent != -1) {
 
-                    Writef(sc ->m, sc ->PostMin);
+                    _cmsIOPrintf(sc ->m, sc ->PostMin);
                     sc ->SecondComponent = -1;
-                    Writef(sc ->m, sc ->PostMaj);
+                    _cmsIOPrintf(sc ->m, sc ->PostMaj);
             }
 
             // Begin block
-            sc->m->Col = 0;
+            _cmsPSActualColumn = 0;
 
-            Writef(sc ->m, sc ->PreMaj);
+            _cmsIOPrintf(sc ->m, sc ->PreMaj);
             sc ->FirstComponent = In[0];
     }
 
@@ -768,96 +660,66 @@
 
             if (sc ->SecondComponent != -1) {
 
-                    Writef(sc ->m, sc ->PostMin);
+                    _cmsIOPrintf(sc ->m, sc ->PostMin);
             }
 
-            Writef(sc ->m, sc ->PreMin);
+            _cmsIOPrintf(sc ->m, sc ->PreMin);
             sc ->SecondComponent = In[1];
     }
 
-
-
-    // Dump table. Could be Word or byte based on
-    // depending on bps member (16 bps mode is not currently
-    // being used at all, but is here for future ampliations)
-
-    for (i=0; i < sc -> Lut ->OutputChan; i++) {
+      // Dump table.
 
-        WORD wWordOut = Out[i];
-
-        if (sc ->bps == 8) {
+      for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) {
 
-            // Value as byte
-            BYTE wByteOut;
-
-            // If is input, convert from Lab2 to Lab4 (just divide by 256)
+          cmsUInt16Number wWordOut = Out[i];
+          cmsUInt8Number wByteOut;           // Value as byte
 
-            if (sc ->lIsInput) {
-
-
-                wByteOut = L2Byte(wWordOut);
-            }
-            else
-                wByteOut = Word2Byte(wWordOut);
+          // We always deal with Lab4
 
-            WriteByte(sc -> m, wByteOut);
-        }
-        else {
+          wByteOut = Word2Byte(wWordOut);
+          WriteByte(sc -> m, wByteOut);
+      }
 
-            // Value as word
-            WriteByte(sc -> m, (BYTE) (wWordOut & 0xFF));
-            WriteByte(sc -> m, (BYTE) ((wWordOut >> 8) & 0xFF));
-        }
-     }
-
-    return 1;
+      return 1;
 }
 
-// Writes a LUT on memstream. Could be 8 or 16 bits based
+// Writes a Pipeline on memstream. Could be 8 or 16 bits based
 
 static
-void WriteCLUT(LPMEMSTREAM m, LPLUT Lut, int bps, const char* PreMaj,
-                                                  const char* PostMaj,
-                                                  const char* PreMin,
-                                                  const char* PostMin,
-                                                  int lIsInput,
-                                                  int FixWhite,
-                                                  icColorSpaceSignature ColorSpace)
+void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
+                                             const char* PostMaj,
+                                             const char* PreMin,
+                                             const char* PostMin,
+                                             int FixWhite,
+                                             cmsColorSpaceSignature ColorSpace)
 {
-    unsigned int i;
-    SAMPLERCARGO sc;
+    cmsUInt32Number i;
+    cmsPsSamplerCargo sc;
 
     sc.FirstComponent = -1;
     sc.SecondComponent = -1;
-    sc.Lut = Lut;
+    sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
     sc.m   = m;
-    sc.bps = bps;
     sc.PreMaj = PreMaj;
     sc.PostMaj= PostMaj;
 
     sc.PreMin   = PreMin;
     sc.PostMin  = PostMin;
-    sc.lIsInput = lIsInput;
     sc.FixWhite = FixWhite;
     sc.ColorSpace = ColorSpace;
 
-    Writef(m, "[");
+    _cmsIOPrintf(m, "[");
 
-    for (i=0; i < Lut ->InputChan; i++)
-            Writef(m, " %d ", Lut ->cLutPoints);
-
-    Writef(m, " [\n");
-
-
+    for (i=0; i < sc.Pipeline->Params->nInputs; i++)
+        _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
 
-    cmsSample3DGrid(Lut, OutputValueSampler, (LPVOID) &sc, SAMPLER_INSPECT);
+    _cmsIOPrintf(m, " [\n");
 
+    cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
 
-    Writef(m, PostMin);
-    Writef(m, PostMaj);
-    Writef(m, "] ");
-
-
+    _cmsIOPrintf(m, PostMin);
+    _cmsIOPrintf(m, PostMaj);
+    _cmsIOPrintf(m, "] ");
 
 }
 
@@ -865,89 +727,92 @@
 // Dumps CIEBasedA Color Space Array
 
 static
-int EmitCIEBasedA(LPMEMSTREAM m, LPWORD Tab, int nEntries, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
 {
 
-        Writef(m, "[ /CIEBasedA\n");
-        Writef(m, "  <<\n");
+    _cmsIOPrintf(m, "[ /CIEBasedA\n");
+    _cmsIOPrintf(m, "  <<\n");
 
-        Writef(m, "/DecodeA ");
+    _cmsIOPrintf(m, "/DecodeA ");
 
-        Emit1Gamma(m,Tab, nEntries);
+    Emit1Gamma(m, Curve);
 
-        Writef(m, " \n");
+    _cmsIOPrintf(m, " \n");
 
-        Writef(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
-        Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
+    _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
+    _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 
-        EmitWhiteBlackD50(m, BlackPoint);
-        EmitIntent(m, INTENT_PERCEPTUAL);
+    EmitWhiteBlackD50(m, BlackPoint);
+    EmitIntent(m, INTENT_PERCEPTUAL);
 
-        Writef(m, ">>\n");
-        Writef(m, "]\n");
+    _cmsIOPrintf(m, ">>\n");
+    _cmsIOPrintf(m, "]\n");
 
-        return 1;
+    return 1;
 }
 
 
 // Dumps CIEBasedABC Color Space Array
 
 static
-int EmitCIEBasedABC(LPMEMSTREAM m, LPWORD L[], int nEntries, LPWMAT3 Matrix, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
 {
     int i;
 
-        Writef(m, "[ /CIEBasedABC\n");
-        Writef(m, "<<\n");
-        Writef(m, "/DecodeABC [ ");
+    _cmsIOPrintf(m, "[ /CIEBasedABC\n");
+    _cmsIOPrintf(m, "<<\n");
+    _cmsIOPrintf(m, "/DecodeABC [ ");
 
-        EmitNGamma(m, 3, L, nEntries);
+    EmitNGamma(m, 3, CurveSet);
 
-        Writef(m, "]\n");
+    _cmsIOPrintf(m, "]\n");
 
-        Writef(m, "/MatrixABC [ " );
+    _cmsIOPrintf(m, "/MatrixABC [ " );
 
-        for( i=0; i < 3; i++ ) {
+    for( i=0; i < 3; i++ ) {
 
-            Writef(m, "%.6f %.6f %.6f ",
-                        FIXED_TO_DOUBLE(Matrix->v[0].n[i]),
-                        FIXED_TO_DOUBLE(Matrix->v[1].n[i]),
-                        FIXED_TO_DOUBLE(Matrix->v[2].n[i]));
-        }
+        _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[0 + 3*i],
+                     Matrix[1 + 3*i],
+                     Matrix[2 + 3*i]);
+    }
 
 
-        Writef(m, "]\n");
+    _cmsIOPrintf(m, "]\n");
 
-        Writef(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
+    _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 
-        EmitWhiteBlackD50(m, BlackPoint);
-        EmitIntent(m, INTENT_PERCEPTUAL);
+    EmitWhiteBlackD50(m, BlackPoint);
+    EmitIntent(m, INTENT_PERCEPTUAL);
 
-        Writef(m, ">>\n");
-        Writef(m, "]\n");
+    _cmsIOPrintf(m, ">>\n");
+    _cmsIOPrintf(m, "]\n");
 
 
-        return 1;
+    return 1;
 }
 
 
 static
-int EmitCIEBasedDEF(LPMEMSTREAM m, LPLUT Lut, int Intent, LPcmsCIEXYZ BlackPoint)
+int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint)
 {
     const char* PreMaj;
     const char* PostMaj;
     const char* PreMin, *PostMin;
+    cmsStage* mpe;
 
-    switch (Lut ->InputChan) {
+    mpe = Pipeline ->Elements;
+
+
+    switch (cmsStageInputChannels(mpe)) {
     case 3:
 
-            Writef(m, "[ /CIEBasedDEF\n");
+            _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
             PreMaj ="<";
             PostMaj= ">\n";
             PreMin = PostMin = "";
             break;
     case 4:
-            Writef(m, "[ /CIEBasedDEFG\n");
+            _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
             PreMaj = "[";
             PostMaj = "]\n";
             PreMin = "<";
@@ -958,30 +823,32 @@
 
     }
 
-    Writef(m, "<<\n");
+    _cmsIOPrintf(m, "<<\n");
 
-    if (Lut ->wFlags & LUT_HASTL1) {
+    if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 
-        Writef(m, "/DecodeDEF [ ");
-        EmitNGamma(m, Lut ->InputChan, Lut ->L1, Lut ->CLut16params.nSamples);
-        Writef(m, "]\n");
+        _cmsIOPrintf(m, "/DecodeDEF [ ");
+        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
+        _cmsIOPrintf(m, "]\n");
+
+        mpe = mpe ->Next;
     }
 
 
 
-    if (Lut ->wFlags & LUT_HAS3DGRID) {
+    if (cmsStageType(mpe) == cmsSigCLutElemType) {
 
-            Writef(m, "/Table ");
-            WriteCLUT(m, Lut, 8, PreMaj, PostMaj, PreMin, PostMin, TRUE, FALSE, (icColorSpaceSignature) 0);
-            Writef(m, "]\n");
+            _cmsIOPrintf(m, "/Table ");
+            WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
+            _cmsIOPrintf(m, "]\n");
     }
 
     EmitLab2XYZ(m);
     EmitWhiteBlackD50(m, BlackPoint);
     EmitIntent(m, Intent);
 
-    Writef(m, "   >>\n");
-    Writef(m, "]\n");
+    _cmsIOPrintf(m, "   >>\n");
+    _cmsIOPrintf(m, "]\n");
 
 
     return 1;
@@ -990,21 +857,21 @@
 // Generates a curve from a gray profile
 
 static
-LPGAMMATABLE ExtractGray2Y(cmsHPROFILE hProfile, int Intent)
+cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
 {
-    LPGAMMATABLE Out = cmsAllocGamma(256);
-    cmsHPROFILE hXYZ = cmsCreateXYZProfile();
-    cmsHTRANSFORM xform = cmsCreateTransform(hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOTPRECALC);
+    cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
+    cmsHPROFILE hXYZ  = cmsCreateXYZProfile();
+    cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
     int i;
 
     for (i=0; i < 256; i++) {
 
-      BYTE Gray = (BYTE) i;
+      cmsUInt8Number Gray = (cmsUInt8Number) i;
       cmsCIEXYZ XYZ;
 
         cmsDoTransform(xform, &Gray, &XYZ, 1);
 
-        Out ->GammaTable[i] =_cmsClampWord((int) floor(XYZ.Y * 65535.0 + 0.5));
+        Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
     }
 
     cmsDeleteTransform(xform);
@@ -1014,17 +881,16 @@
 
 
 
-// Because PostScrip has only 8 bits in /Table, we should use
+// Because PostScript has only 8 bits in /Table, we should use
 // a more perceptually uniform space... I do choose Lab.
 
 static
-int WriteInputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent)
+int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
 {
     cmsHPROFILE hLab;
     cmsHTRANSFORM xform;
-    icColorSpaceSignature ColorSpace;
-    int nChannels;
-    DWORD InputFormat;
+    cmsUInt32Number nChannels;
+    cmsUInt32Number InputFormat;
     int rc;
     cmsHPROFILE Profiles[2];
     cmsCIEXYZ BlackPointAdaptedToD50;
@@ -1032,49 +898,25 @@
     // Does create a device-link based transform.
     // The DeviceLink is next dumped as working CSA.
 
-    hLab        = cmsCreateLabProfile(NULL);
-    ColorSpace  =  cmsGetColorSpace(hProfile);
-    nChannels   = _cmsChannelsOf(ColorSpace);
-    InputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2);
-
-    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent,LCMS_BPFLAGS_D50_ADAPTED);
-
-    // Is a devicelink profile?
-    if (cmsGetDeviceClass(hProfile) == icSigLinkClass) {
-
-        // if devicelink output already Lab, use it directly
-
-        if (cmsGetPCS(hProfile) == icSigLabData) {
-
-            xform = cmsCreateTransform(hProfile, InputFormat, NULL,
-                            TYPE_Lab_DBL, Intent, 0);
-        }
-        else {
-
-            // Nope, adjust output to Lab if possible
-
-            Profiles[0] = hProfile;
-            Profiles[1] = hLab;
-
-            xform = cmsCreateMultiprofileTransform(Profiles, 2,  InputFormat,
-                                    TYPE_Lab_DBL, Intent, 0);
-        }
+    InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
+    nChannels   = T_CHANNELS(InputFormat);
 
 
-    }
-    else {
+    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
+
+    // Adjust output to Lab4
+    hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
 
-        // This is a normal profile
-        xform = cmsCreateTransform(hProfile, InputFormat, hLab,
-                            TYPE_Lab_DBL, Intent, 0);
-    }
+    Profiles[0] = hProfile;
+    Profiles[1] = hLab;
 
-
+    xform = cmsCreateMultiprofileTransform(Profiles, 2,  InputFormat, TYPE_Lab_DBL, Intent, 0);
+    cmsCloseProfile(hLab);
 
     if (xform == NULL) {
 
-            cmsSignalError(LCMS_ERRC_ABORTED, "Cannot create transform Profile -> Lab");
-            return 0;
+        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab");
+        return 0;
     }
 
     // Only 1, 3 and 4 channels are allowed
@@ -1082,86 +924,82 @@
     switch (nChannels) {
 
     case 1: {
-            LPGAMMATABLE Gray2Y = ExtractGray2Y(hProfile, Intent);
-            EmitCIEBasedA(m, Gray2Y->GammaTable, Gray2Y ->nEntries, &BlackPointAdaptedToD50);
-            cmsFreeGamma(Gray2Y);
+        cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
+            EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
+            cmsFreeToneCurve(Gray2Y);
             }
             break;
 
     case 3:
     case 4: {
-            LPLUT DeviceLink;
-            _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform;
+        cmsUInt32Number OutFrm = TYPE_Lab_16;
+            cmsPipeline* DeviceLink;
+            _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
 
-            if (v ->DeviceLink)
-                rc = EmitCIEBasedDEF(m, v->DeviceLink, Intent, &BlackPointAdaptedToD50);
-            else {
-                DeviceLink = _cmsPrecalculateDeviceLink(xform, 0);
-                rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
-                cmsFreeLUT(DeviceLink);
-            }
+            DeviceLink = cmsPipelineDup(v ->Lut);
+            if (DeviceLink == NULL) return 0;
+
+            dwFlags |= cmsFLAGS_FORCE_CLUT;
+            _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
+
+            rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
+            cmsPipelineFree(DeviceLink);
             }
             break;
 
     default:
 
-            cmsSignalError(LCMS_ERRC_ABORTED, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
-            return 0;
+        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
+        return 0;
     }
 
 
     cmsDeleteTransform(xform);
-    cmsCloseProfile(hLab);
+
     return 1;
 }
 
+static
+cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
+{
+    _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+
+    return Data -> Double;
+}
 
 
 // Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
 
 static
-int WriteInputMatrixShaper(LPMEMSTREAM m, cmsHPROFILE hProfile)
+int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper)
 {
-    icColorSpaceSignature ColorSpace;
-    LPMATSHAPER MatShaper;
+    cmsColorSpaceSignature ColorSpace;
     int rc;
     cmsCIEXYZ BlackPointAdaptedToD50;
 
-
     ColorSpace = cmsGetColorSpace(hProfile);
-    MatShaper  = cmsBuildInputMatrixShaper(hProfile);
 
-    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_BPFLAGS_D50_ADAPTED);
-
-    if (MatShaper == NULL) {
+    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
 
-                cmsSignalError(LCMS_ERRC_ABORTED, "This profile is not suitable for input");
-                return 0;
-    }
+    if (ColorSpace == cmsSigGrayData) {
 
-    if (ColorSpace == icSigGrayData) {
-
-            rc = EmitCIEBasedA(m, MatShaper ->L[0],
-                                  MatShaper ->p16.nSamples,
-                                  &BlackPointAdaptedToD50);
+        cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
+            rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
 
     }
     else
-        if (ColorSpace == icSigRgbData) {
-
+        if (ColorSpace == cmsSigRgbData) {
 
-            rc = EmitCIEBasedABC(m, MatShaper->L,
-                                        MatShaper ->p16.nSamples,
-                                        &MatShaper ->Matrix,
-                                        &BlackPointAdaptedToD50);
+            rc = EmitCIEBasedABC(m,  GetPtrToMatrix(Matrix),
+                                 _cmsStageGetPtrToCurveSet(Shaper),
+                                 &BlackPointAdaptedToD50);
         }
         else  {
 
-            cmsSignalError(LCMS_ERRC_ABORTED, "Profile is not suitable for CSA. Unsupported colorspace.");
+            cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
             return 0;
         }
 
-    cmsFreeMatShaper(MatShaper);
     return rc;
 }
 
@@ -1171,45 +1009,46 @@
 // This is a HP extension, and it works in Lab instead of XYZ
 
 static
-int WriteNamedColorCSA(LPMEMSTREAM m, cmsHPROFILE hNamedColor, int Intent)
+int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent)
 {
     cmsHTRANSFORM xform;
     cmsHPROFILE   hLab;
     int i, nColors;
     char ColorName[32];
-
+    cmsNAMEDCOLORLIST* NamedColorList;
 
-    hLab  = cmsCreateLabProfile(NULL);
-    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX,
-                        hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOTPRECALC);
+    hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
+    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
     if (xform == NULL) return 0;
 
+    NamedColorList = cmsGetNamedColorList(xform);
+    if (NamedColorList == NULL) return 0;
 
-    Writef(m, "<<\n");
-    Writef(m, "(colorlistcomment) (%s)\n", "Named color CSA");
-    Writef(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
-    Writef(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
+    _cmsIOPrintf(m, "<<\n");
+    _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
+    _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
+    _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
 
-    nColors   = cmsNamedColorCount(xform);
+    nColors   = cmsNamedColorCount(NamedColorList);
 
 
     for (i=0; i < nColors; i++) {
 
-        WORD In[1];
+        cmsUInt16Number In[1];
         cmsCIELab Lab;
 
-        In[0] = (WORD) i;
+        In[0] = (cmsUInt16Number) i;
 
-        if (!cmsNamedColorInfo(xform, i, ColorName, NULL, NULL))
+        if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
                 continue;
 
         cmsDoTransform(xform, In, &Lab, 1);
-        Writef(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
+        _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
     }
 
 
 
-    Writef(m, ">>\n");
+    _cmsIOPrintf(m, ">>\n");
 
     cmsDeleteTransform(xform);
     cmsCloseProfile(hLab);
@@ -1218,75 +1057,68 @@
 
 
 // Does create a Color Space Array on XYZ colorspace for PostScript usage
-
-DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile,
-                              int Intent,
-                              LPVOID Buffer, DWORD dwBufferLen)
+static
+cmsUInt32Number GenerateCSA(cmsContext ContextID,
+                            cmsHPROFILE hProfile,
+                            cmsUInt32Number Intent,
+                            cmsUInt32Number dwFlags,
+                            cmsIOHANDLER* mem)
 {
-
-    LPMEMSTREAM mem;
-    DWORD dwBytesUsed;
-
-    // Set up the serialization engine
-    mem = CreateMemStream((LPBYTE) Buffer, dwBufferLen, MAXPSCOLS);
-    if (!mem) return 0;
+    cmsUInt32Number dwBytesUsed;
+    cmsPipeline* lut = NULL;
+    cmsStage* Matrix, *Shaper;
 
 
     // Is a named color profile?
-    if (cmsGetDeviceClass(hProfile) == icSigNamedColorClass) {
-
-        if (!WriteNamedColorCSA(mem, hProfile, Intent)) {
+    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
 
-                    _cmsFree((void*) mem);
-                    return 0;
-        }
+        if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error;
     }
     else {
 
 
-    // Any profile class are allowed (including devicelink), but
-    // output (PCS) colorspace must be XYZ or Lab
-    icColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
-
-    if (ColorSpace != icSigXYZData &&
-        ColorSpace != icSigLabData) {
+        // Any profile class are allowed (including devicelink), but
+        // output (PCS) colorspace must be XYZ or Lab
+        cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
 
-            cmsSignalError(LCMS_ERRC_ABORTED, "Invalid output color space");
-            _cmsFree((void*) mem);
-            return 0;
-    }
+        if (ColorSpace != cmsSigXYZData &&
+            ColorSpace != cmsSigLabData) {
 
-    // Is there any CLUT?
-    if (IsLUTbased(hProfile, Intent)) {
+            cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
+            goto Error;
+        }
+
 
-        // Yes, so handle as LUT-based
-        if (!WriteInputLUT(mem, hProfile, Intent)) {
+        // Read the lut with all necessary conversion stages
+        lut = _cmsReadInputLUT(hProfile, Intent);
+        if (lut == NULL) goto Error;
 
-                    _cmsFree((void*) mem);
-                    return 0;
-        }
-    }
-    else {
+
+        // Tone curves + matrix can be implemented without any LUT
+        if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) {
 
-        // No, try Matrix-shaper (this only works on XYZ)
-
-        if (!WriteInputMatrixShaper(mem, hProfile)) {
+            if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error;
 
-                    _cmsFree((void*) mem);  // Something went wrong
-                    return 0;
         }
-    }
+        else {
+            // We need a LUT for the rest
+            if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
+        }
     }
 
 
     // Done, keep memory usage
-    dwBytesUsed = mem ->dwUsed;
+    dwBytesUsed = mem ->UsedSpace;
 
-    // Get rid of memory stream
-    _cmsFree((void*) mem);
+    // Get rid of LUT
+    if (lut != NULL) cmsPipelineFree(lut);
 
     // Finally, return used byte count
     return dwBytesUsed;
+
+Error:
+    if (lut != NULL) cmsPipelineFree(lut);
+    return 0;
 }
 
 // ------------------------------------------------------ Color Rendering Dictionary (CRD)
@@ -1356,45 +1188,45 @@
 
 
 static
-void EmitPQRStage(LPMEMSTREAM m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
+void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
 {
 
 
         if (lIsAbsolute) {
 
             // For absolute colorimetric intent, encode back to relative
-            // and generate a relative LUT
+            // and generate a relative Pipeline
 
             // Relative encoding is obtained across XYZpcs*(D50/WhitePoint)
 
             cmsCIEXYZ White;
 
-            cmsTakeMediaWhitePoint(&White, hProfile);
+            _cmsReadMediaWhitePoint(&White, hProfile);
 
-            Writef(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
-            Writef(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
+            _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
+            _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
 
-            Writef(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
+            _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
                       "/TransformPQR [\n"
                       "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n"
                       "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n"
                       "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n",
-                      White.X, White.Y, White.Z);
+                         White.X, White.Y, White.Z);
             return;
         }
 
 
-        Writef(m,"%% Bradford Cone Space\n"
+        _cmsIOPrintf(m,"%% Bradford Cone Space\n"
                  "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n");
 
-        Writef(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
+        _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
 
 
         // No BPC
 
         if (!DoBPC) {
 
-            Writef(m, "%% VonKries-like transform in Bradford Cone Space\n"
+            _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n"
                       "/TransformPQR [\n"
                       "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n"
                       "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n"
@@ -1403,22 +1235,22 @@
 
             // BPC
 
-            Writef(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
+            _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
                       "/TransformPQR [\n");
 
-            Writef(m, "{4 index 3 get div 2 index 3 get mul "
+            _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
                     "2 index 3 get 2 index 3 get sub mul "
                     "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
                     "3 index 3 get 3 index 3 get exch sub div "
                     "exch pop exch pop exch pop exch pop } bind\n");
 
-            Writef(m, "{4 index 4 get div 2 index 4 get mul "
+            _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
                     "2 index 4 get 2 index 4 get sub mul "
                     "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
                     "3 index 4 get 3 index 4 get exch sub div "
                     "exch pop exch pop exch pop exch pop } bind\n");
 
-            Writef(m, "{4 index 5 get div 2 index 5 get mul "
+            _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
                     "2 index 5 get 2 index 5 get sub mul "
                     "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
                     "3 index 5 get 3 index 5 get exch sub div "
@@ -1431,24 +1263,24 @@
 
 
 static
-void EmitXYZ2Lab(LPMEMSTREAM m)
+void EmitXYZ2Lab(cmsIOHANDLER* m)
 {
-    Writef(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
-    Writef(m, "/EncodeLMN [\n");
-    Writef(m, "{ 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
-    Writef(m, "{ 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
-    Writef(m, "{ 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
-    Writef(m, "]\n");
-    Writef(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
-    Writef(m, "/EncodeABC [\n");
+    _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
+    _cmsIOPrintf(m, "/EncodeLMN [\n");
+    _cmsIOPrintf(m, "{ 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+    _cmsIOPrintf(m, "{ 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+    _cmsIOPrintf(m, "{ 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
+    _cmsIOPrintf(m, "]\n");
+    _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
+    _cmsIOPrintf(m, "/EncodeABC [\n");
 
 
-    Writef(m, "{ 116 mul  16 sub 100 div  } bind\n");
-    Writef(m, "{ 500 mul 128 add 256 div  } bind\n");
-    Writef(m, "{ 200 mul 128 add 256 div  } bind\n");
+    _cmsIOPrintf(m, "{ 116 mul  16 sub 100 div  } bind\n");
+    _cmsIOPrintf(m, "{ 500 mul 128 add 256 div  } bind\n");
+    _cmsIOPrintf(m, "{ 200 mul 128 add 256 div  } bind\n");
 
 
-    Writef(m, "]\n");
+    _cmsIOPrintf(m, "]\n");
 
 
 }
@@ -1460,104 +1292,74 @@
 // 8 bits.
 
 static
-int WriteOutputLUT(LPMEMSTREAM m, cmsHPROFILE hProfile, int Intent, DWORD dwFlags)
+int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
 {
     cmsHPROFILE hLab;
     cmsHTRANSFORM xform;
-    icColorSpaceSignature ColorSpace;
     int i, nChannels;
-    DWORD OutputFormat;
-    _LPcmsTRANSFORM v;
-    LPLUT DeviceLink;
+    cmsUInt32Number OutputFormat;
+    _cmsTRANSFORM* v;
+    cmsPipeline* DeviceLink;
     cmsHPROFILE Profiles[3];
     cmsCIEXYZ BlackPointAdaptedToD50;
-    LCMSBOOL lFreeDeviceLink = FALSE;
-    LCMSBOOL lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
-    LCMSBOOL lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
+    cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
+    cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
+    cmsUInt32Number InFrm = TYPE_Lab_16;
     int RelativeEncodingIntent;
-
+    cmsColorSpaceSignature ColorSpace;
 
 
-    hLab = cmsCreateLabProfile(NULL);
+    hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
+    if (hLab == NULL) return 0;
 
-    ColorSpace  =  cmsGetColorSpace(hProfile);
-    nChannels   = _cmsChannelsOf(ColorSpace);
-    OutputFormat = CHANNELS_SH(nChannels) | BYTES_SH(2);
+    OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
+    nChannels    = T_CHANNELS(OutputFormat);
 
-    // For absolute colorimetric, the LUT is encoded as relative
-    // in order to preserve precission.
+    ColorSpace = cmsGetColorSpace(hProfile);
+
+    // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision.
 
     RelativeEncodingIntent = Intent;
     if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
         RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
 
 
-    // Is a devicelink profile?
-    if (cmsGetDeviceClass(hProfile) == icSigLinkClass) {
-
-        // if devicelink input already in Lab
-
-        if (ColorSpace == icSigLabData) {
-
-              // adjust input to Lab to our v4
-
-            Profiles[0] = hLab;
-            Profiles[1] = hProfile;
+    // Use V4 Lab always
+    Profiles[0] = hLab;
+    Profiles[1] = hProfile;
 
-            xform = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_Lab_DBL,
-                                                        OutputFormat, RelativeEncodingIntent,
-                                                        dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION);
-
-        }
-        else {
-          cmsSignalError(LCMS_ERRC_ABORTED, "Cannot use devicelink profile for CRD creation");
-          return 0;
-        }
-
-
-    }
-    else {
-
-        // This is a normal profile
-        xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hProfile,
-                            OutputFormat, RelativeEncodingIntent, dwFlags|cmsFLAGS_NOWHITEONWHITEFIXUP|cmsFLAGS_NOPRELINEARIZATION);
-    }
+    xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
+                                              Profiles, 2, TYPE_Lab_DBL,
+                                              OutputFormat, RelativeEncodingIntent, 0);
+    cmsCloseProfile(hLab);
 
     if (xform == NULL) {
 
-            cmsSignalError(LCMS_ERRC_ABORTED, "Cannot create transform Lab -> Profile in CRD creation");
-            return 0;
+        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
+        return 0;
     }
 
-    // Get the internal precalculated devicelink
-
-    v = (_LPcmsTRANSFORM) xform;
-    DeviceLink = v ->DeviceLink;
-
-    if (!DeviceLink) {
-
-        DeviceLink = _cmsPrecalculateDeviceLink(xform, cmsFLAGS_NOPRELINEARIZATION);
-        lFreeDeviceLink = TRUE;
-    }
-
-    Writef(m, "<<\n");
-    Writef(m, "/ColorRenderingType 1\n");
+    // Get a copy of the internal devicelink
+    v = (_cmsTRANSFORM*) xform;
+    DeviceLink = cmsPipelineDup(v ->Lut);
+    if (DeviceLink == NULL) return 0;
 
 
-    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, LCMS_BPFLAGS_D50_ADAPTED);
+    // We need a CLUT
+    dwFlags |= cmsFLAGS_FORCE_CLUT;
+    _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
+
+    _cmsIOPrintf(m, "<<\n");
+    _cmsIOPrintf(m, "/ColorRenderingType 1\n");
+
+
+    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
 
     // Emit headers, etc.
     EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
     EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
     EmitXYZ2Lab(m);
 
-    if (DeviceLink ->wFlags & LUT_HASTL1) {
-
-        // Shouldn't happen
-        cmsSignalError(LCMS_ERRC_ABORTED, "Internal error (prelinearization on CRD)");
-        return 0;
-    }
-
 
     // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab
     // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127,
@@ -1568,31 +1370,30 @@
     if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
             lFixWhite = FALSE;
 
-    Writef(m, "/RenderTable ");
+    _cmsIOPrintf(m, "/RenderTable ");
+
 
-    WriteCLUT(m, DeviceLink, 8, "<", ">\n", "", "", FALSE,
-                lFixWhite, ColorSpace);
+    WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
 
-    Writef(m, " %d {} bind ", nChannels);
+    _cmsIOPrintf(m, " %d {} bind ", nChannels);
 
     for (i=1; i < nChannels; i++)
-            Writef(m, "dup ");
+            _cmsIOPrintf(m, "dup ");
 
-    Writef(m, "]\n");
+    _cmsIOPrintf(m, "]\n");
 
 
     EmitIntent(m, Intent);
 
-    Writef(m, ">>\n");
+    _cmsIOPrintf(m, ">>\n");
 
     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
 
-        Writef(m, "/Current exch /ColorRendering defineresource pop\n");
+        _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
     }
 
-    if (lFreeDeviceLink) cmsFreeLUT(DeviceLink);
+    cmsPipelineFree(DeviceLink);
     cmsDeleteTransform(xform);
-    cmsCloseProfile(hLab);
 
     return 1;
 }
@@ -1600,14 +1401,14 @@
 
 // Builds a ASCII string containing colorant list in 0..1.0 range
 static
-void BuildColorantList(char *Colorant, int nColorant, WORD Out[])
+void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
 {
     char Buff[32];
     int j;
 
     Colorant[0] = 0;
-    if (nColorant > MAXCHANNELS)
-        nColorant = MAXCHANNELS;
+    if (nColorant > cmsMAXCHANNELS)
+        nColorant = cmsMAXCHANNELS;
 
     for (j=0; j < nColorant; j++) {
 
@@ -1624,50 +1425,54 @@
 // This is a HP extension.
 
 static
-int WriteNamedColorCRD(LPMEMSTREAM m, cmsHPROFILE hNamedColor, int Intent, DWORD dwFlags)
+int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags)
 {
     cmsHTRANSFORM xform;
     int i, nColors, nColorant;
-    DWORD OutputFormat;
+    cmsUInt32Number OutputFormat;
     char ColorName[32];
     char Colorant[128];
+    cmsNAMEDCOLORLIST* NamedColorList;
 
-    nColorant = _cmsChannelsOf(cmsGetColorSpace(hNamedColor));
-    OutputFormat = CHANNELS_SH(nColorant) | BYTES_SH(2);
 
-    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX,
-                        NULL, OutputFormat, Intent, cmsFLAGS_NOTPRECALC);
+    OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
+    nColorant    = T_CHANNELS(OutputFormat);
+
+
+    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
     if (xform == NULL) return 0;
 
 
-    Writef(m, "<<\n");
-    Writef(m, "(colorlistcomment) (%s) \n", "Named profile");
-    Writef(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
-    Writef(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
+    NamedColorList = cmsGetNamedColorList(xform);
+    if (NamedColorList == NULL) return 0;
 
-    nColors   = cmsNamedColorCount(xform);
+    _cmsIOPrintf(m, "<<\n");
+    _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
+    _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
+    _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
 
+    nColors   = cmsNamedColorCount(NamedColorList);
 
     for (i=0; i < nColors; i++) {
 
-        WORD In[1];
-        WORD Out[MAXCHANNELS];
+        cmsUInt16Number In[1];
+        cmsUInt16Number Out[cmsMAXCHANNELS];
 
-        In[0] = (WORD) i;
+        In[0] = (cmsUInt16Number) i;
 
-        if (!cmsNamedColorInfo(xform, i, ColorName, NULL, NULL))
+        if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
                 continue;
 
         cmsDoTransform(xform, In, Out, 1);
         BuildColorantList(Colorant, nColorant, Out);
-        Writef(m, "  (%s) [ %s ]\n", ColorName, Colorant);
+        _cmsIOPrintf(m, "  (%s) [ %s ]\n", ColorName, Colorant);
     }
 
-    Writef(m, "   >>");
+    _cmsIOPrintf(m, "   >>");
 
     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
 
-    Writef(m, " /Current exch /HPSpotTable defineresource pop\n");
+    _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n");
     }
 
     cmsDeleteTransform(xform);
@@ -1680,67 +1485,129 @@
 // CRD are always LUT-Based, no matter if profile is
 // implemented as matrix-shaper.
 
-DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile,
-                              int Intent, DWORD dwFlags,
-                              LPVOID Buffer, DWORD dwBufferLen)
+static
+cmsUInt32Number  GenerateCRD(cmsContext ContextID,
+                             cmsHPROFILE hProfile,
+                             cmsUInt32Number Intent, cmsUInt32Number dwFlags,
+                             cmsIOHANDLER* mem)
 {
-
-    LPMEMSTREAM mem;
-    DWORD dwBytesUsed;
-
-    // Set up the serialization artifact
-    mem = CreateMemStream((LPBYTE) Buffer, dwBufferLen, MAXPSCOLS);
-    if (!mem) return 0;
-
+    cmsUInt32Number dwBytesUsed;
 
     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
 
-    EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
+        EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
     }
 
 
     // Is a named color profile?
-    if (cmsGetDeviceClass(hProfile) == icSigNamedColorClass) {
+    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
 
         if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) {
-
-                    _cmsFree((void*) mem);
-                    return 0;
+            return 0;
         }
     }
     else {
 
-    // CRD are always implemented as LUT.
-
+        // CRD are always implemented as LUT
 
-    if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
-        _cmsFree((void*) mem);
-        return 0;
-    }
+        if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
+            return 0;
+        }
     }
 
     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
 
-    Writef(mem, "%%%%EndResource\n");
-    Writef(mem, "\n%% CRD End\n");
+        _cmsIOPrintf(mem, "%%%%EndResource\n");
+        _cmsIOPrintf(mem, "\n%% CRD End\n");
     }
 
     // Done, keep memory usage
-    dwBytesUsed = mem ->dwUsed;
+    dwBytesUsed = mem ->UsedSpace;
+
+    // Finally, return used byte count
+    return dwBytesUsed;
+
+    cmsUNUSED_PARAMETER(ContextID);
+}
+
+
+
+
+cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
+                                                        cmsPSResourceType Type,
+                                                        cmsHPROFILE hProfile,
+                                                        cmsUInt32Number Intent,
+                                                        cmsUInt32Number dwFlags,
+                                                        cmsIOHANDLER* io)
+{
+    cmsUInt32Number  rc;
+
+
+    switch (Type) {
+
+      case cmsPS_RESOURCE_CSA:
+          rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
+          break;
+      default:
+      case cmsPS_RESOURCE_CRD:
+          rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
+          break;
+    }
+
+    return rc;
+}
+
+
+
+cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID,
+                                              cmsHPROFILE hProfile,
+                              cmsUInt32Number Intent, cmsUInt32Number dwFlags,
+                              void* Buffer, cmsUInt32Number dwBufferLen)
+{
+    cmsIOHANDLER* mem;
+    cmsUInt32Number dwBytesUsed;
+
+    // Set up the serialization engine
+    if (Buffer == NULL)
+        mem = cmsOpenIOhandlerFromNULL(ContextID);
+    else
+        mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
+
+    if (!mem) return 0;
+
+    dwBytesUsed =  cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem);
 
     // Get rid of memory stream
-    _cmsFree((void*) mem);
+    cmsCloseIOhandler(mem);
 
-    // Finally, return used byte count
     return dwBytesUsed;
 }
 
 
-// For compatibility with previous versions
+
+// Does create a Color Space Array on XYZ colorspace for PostScript usage
+cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID,
+                                              cmsHPROFILE hProfile,
+                                              cmsUInt32Number Intent,
+                                              cmsUInt32Number dwFlags,
+                                              void* Buffer,
+                                              cmsUInt32Number dwBufferLen)
+{
+    cmsIOHANDLER* mem;
+    cmsUInt32Number dwBytesUsed;
 
-DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile,
-                              int Intent,
-                              LPVOID Buffer, DWORD dwBufferLen)
-{
-    return cmsGetPostScriptCRDEx(hProfile, Intent, 0, Buffer, dwBufferLen);
+    if (Buffer == NULL)
+        mem = cmsOpenIOhandlerFromNULL(ContextID);
+    else
+        mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
+
+    if (!mem) return 0;
+
+    dwBytesUsed =  cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem);
+
+    // Get rid of memory stream
+    cmsCloseIOhandler(mem);
+
+    return dwBytesUsed;
+
 }