[gs-commits] rev 11849 - trunk/gs/base

ken at ghostscript.com ken at ghostscript.com
Mon Oct 25 15:59:11 UTC 2010


Author: ken
Date: 2010-10-25 15:59:10 +0000 (Mon, 25 Oct 2010)
New Revision: 11849

Modified:
   trunk/gs/base/gdevpdfc.c
Log:
Fix pdfwrite : Do not emit DeviceRGB/CMYK as an Alternate when disallowed by PDF/A or X

If a /Separation colour space had an /Alternate of /DeviceRGB or DeviceCMYK it was not 
checked to see if it was valid for PDF/A or PDF/X production, if these were set.

As a result invalid PDF/A or PDF/X files could be written.

The code now tests these flags and if the base space is not valid, converts to an 
appropriate base space by; sampling the tint transform function at 0 and 1, converting
the resulting colours to the appropriate base space (using the Red Book methods for
DeviceRGB/DeviceCMYK conversion), creating a new linear interpolation function for
the new base space, using the converted sampled values for /Co and C1.

The new base space is then written to the PDF file.

No differences expected as we don't test PDF/A and PDF/X on the cluster.

Modified: trunk/gs/base/gdevpdfc.c
===================================================================
--- trunk/gs/base/gdevpdfc.c	2010-10-25 06:23:22 UTC (rev 11848)
+++ trunk/gs/base/gdevpdfc.c	2010-10-25 15:59:10 UTC (rev 11849)
@@ -24,6 +24,8 @@
 #include "stream.h"
 #include "gsicc.h"
 #include "gserrors.h"
+#include "gsfunc.h"		/* required for colour space function evaluation */
+#include "gsfunc3.h"		/* Required to create a replacement lineat interpolation function */
 #include "gdevpdfx.h"
 #include "gdevpdfg.h"
 #include "gdevpdfc.h"
@@ -331,6 +333,121 @@
     return 0;
 }
 
+static int pdf_delete_base_space_function(gx_device_pdf *pdev, gs_function_t *pfn)
+{
+    gs_function_ElIn_params_t *params = (gs_function_ElIn_params_t *)&pfn->params;
+
+    gs_free_object(pdev->memory, (void *)params->Domain, "pdf_delete_function");
+    gs_free_object(pdev->memory, (void *)params->Range, "pdf_delete_function");
+    gs_free_object(pdev->memory, (void *)params->C0, "pdf_delete_function");
+    gs_free_object(pdev->memory, (void *)params->C1, "pdf_delete_function");
+    gs_free_object(pdev->memory, (void *)pfn, "pdf_delete_function");
+    return 0;
+}
+
+static int pdf_make_base_space_function(gx_device_pdf *pdev, gs_function_t **pfn,
+					int ncomp, float *data_low, float *data_high)
+{
+    gs_function_ElIn_params_t params;
+    float *ptr1, *ptr2;
+    int i, code;
+
+    ptr1 = (float *)
+        gs_alloc_byte_array(pdev->memory, 2, sizeof(float), "pdf_make_function(Domain)");
+    if (ptr1 == 0) {
+	return gs_note_error(gs_error_VMerror);
+    }
+    ptr2 = (float *)
+        gs_alloc_byte_array(pdev->memory, 2 * ncomp, sizeof(float), "pdf_make_function(Range)");
+    if (ptr2 == 0) {
+	gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(Range)");
+	return gs_note_error(gs_error_VMerror);
+    }
+    params.m = 1;
+    params.n = ncomp;
+    params.N = 1.0f;
+    ptr1[0] = 0.0f;
+    ptr1[1] = 1.0f;
+    for (i=0;i<ncomp;i++) {
+        ptr2[i*2] = 0.0f;
+        ptr2[(i*2) + 1] = 1.0f;
+    }
+    params.Domain = ptr1;
+    params.Range = ptr2;
+
+    ptr1 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C0)");
+    if (ptr1 == 0) {
+	gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C0)");
+	gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C0)");
+	return gs_note_error(gs_error_VMerror);
+    }
+    ptr2 = (float *)gs_alloc_byte_array(pdev->memory, ncomp, sizeof(float), "pdf_make_function(C1)");
+    if (ptr2 == 0) {
+	gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function(C1)");
+	gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function(C1)");
+	gs_free_object(pdev->memory, (void *)ptr1, "pdf_make_function(C1)");
+	return gs_note_error(gs_error_VMerror);
+    }
+
+    for (i=0;i<ncomp;i++) {
+	ptr1[i] = data_low[i];
+	ptr2[i] = data_high[i];
+    }
+    params.C0 = ptr1;
+    params.C1 = ptr2;
+    code = gs_function_ElIn_init(pfn, &params, pdev->memory);
+    if (code < 0) {
+	gs_free_object(pdev->memory, (void *)params.Domain, "pdf_make_function");
+	gs_free_object(pdev->memory, (void *)params.Range, "pdf_make_function");
+	gs_free_object(pdev->memory, (void *)params.C0, "pdf_make_function");
+	gs_free_object(pdev->memory, (void *)params.C1, "pdf_make_function");
+    }
+    return code;
+}
+
+static void pdf_SepRGB_ConvertToCMYK (float *in, float *out)
+{
+    float CMYK[4];
+    int i;
+
+    if (in[0] <= in[1] && in[0] <= in[2]) {
+        CMYK[3] = 1.0 - in[0];
+    } else {
+        if (in[1]<= in[0] && in[1] <= in[2]) {
+    	    CMYK[3] = 1.0 - in[1];
+	} else {
+	    CMYK[3] = 1.0 - in[2];
+	}
+    }
+    CMYK[0] = 1.0 - in[0] - CMYK[3];
+    CMYK[1] = 1.0 - in[1] - CMYK[3];
+    CMYK[2] = 1.0 - in[2] - CMYK[3];
+    for (i=0;i<4;i++)
+        out[i] = CMYK[i];
+}
+
+static void pdf_SepCMYK_ConvertToRGB (float *in, float *out)
+{
+    float RGB[3];
+
+    RGB[0] = in[0] + in[4];
+    RGB[1] = in[1] + in[4];
+    RGB[2] = in[2] + in[4];
+
+    if (RGB[0] > 1)
+	out[0] = 0.0f;
+    else
+	out[0] = 1 - RGB[0];
+    if (RGB[1] > 1)
+	out[1] = 0.0f;
+    else
+	out[1] = 1 - RGB[1];
+    if (RGB[2] > 1)
+	out[2] = 0.0f;
+    else
+	out[2] = 1 - RGB[2];
+}
+
 /* Create a Separation or DeviceN color space (internal). */
 static int
 pdf_separation_color_space(gx_device_pdf *pdev,
@@ -343,10 +460,103 @@
 {
     cos_value_t v;
     const gs_range_t *ranges;
-    int code;
+    int code, csi;
 
+    /* We need to think about the alternate space. If we are producing 
+     * PDF/X or PDF/A we can't produce some device spaces, and the code in 
+     * pdf_color_space_named always allows device spaces. We could alter
+     * that code, but by then we don't know its an Alternate space, and have
+     * lost the tin transform procedure. So instead we check here.
+     */
+    csi = gs_color_space_get_index(alt_space);
+    /* Note that if csi is ICC, check to see if this was one of 
+       the default substitutes that we introduced for DeviceGray,
+       DeviceRGB or DeviceCMYK.  If it is, then just write
+       the default color.  Depending upon the flavor of PDF,
+       or other options, we may want to actually have all
+       the colors defined by ICC profiles and not do the following
+       substituion of the Device space. */
+    if (csi == gs_color_space_index_ICC) {
+        csi = gsicc_get_default_type(alt_space->cmm_icc_profile_data);
+    }
+    if (csi == gs_color_space_index_DeviceRGB && (pdev->PDFX || 
+	(pdev->PDFA && (pdev->pcm_color_info_index == gs_color_space_index_DeviceCMYK)))) {
+
+	/* We have a DeviceRGB alternate, but are producing either PDF/X or
+	 * PDF/A with a DeviceCMYK process color model. So we need to convert
+	 * the alternate space into CMYK. We do this by evaluating the function
+	 * at each end of the Separation space (0 and 1), convert the resulting
+	 * RGB colours into CMYK and create a new function which linearly 
+	 * interpolates between these points.
+	 */
+	gs_function_t *new_pfn = 0;
+        float in[1] = {0.0f};
+	float out_low[4];
+	float out_high[4];
+
+	code = gs_function_evaluate(pfn, in, out_low);
+	if (code < 0)
+	    return code;
+	pdf_SepRGB_ConvertToCMYK((float *)&out_low, (float *)&out_low);
+
+	in[0] = 1.0f;
+	code = gs_function_evaluate(pfn, in, out_high);
+	if (code < 0)
+	    return code;
+	pdf_SepRGB_ConvertToCMYK((float *)&out_high, (float *)&out_high);
+	
+	code = pdf_make_base_space_function(pdev, &new_pfn, 4, out_low, out_high);
+	if (code < 0)
+	    return code;
     if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
 	(code = cos_array_add_no_copy(pca, snames)) < 0 ||
+	    (code = (int)cos_c_string_value(&v, (const char *)pcsn->DeviceCMYK)) < 0 ||
+	    (code = cos_array_add(pca, &v)) < 0 ||
+	    (code = pdf_function_scaled(pdev, new_pfn, 0x00, &v)) < 0 ||
+	    (code = cos_array_add(pca, &v)) < 0 ||
+	    (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
+	    ) {}
+	pdf_delete_base_space_function(pdev, new_pfn);
+	return code;
+    }
+    if (csi == gs_color_space_index_DeviceCMYK &&
+	(pdev->PDFA && (pdev->pcm_color_info_index == gs_color_space_index_DeviceRGB))) {
+	/* We have a DeviceCMYK alternate, but are producingPDF/A with a 
+	 * DeviceRGB process color model. See comment above re DviceRGB.
+	 */
+	gs_function_t *new_pfn = 0;
+        float in[1] = {0.0f};
+	float out_low[4];
+	float out_high[4];
+
+	code = gs_function_evaluate(pfn, in, out_low);
+	if (code < 0)
+	    return code;
+	pdf_SepCMYK_ConvertToRGB((float *)&out_low, (float *)&out_low);
+
+        in[0] = 1.0f;
+	code = gs_function_evaluate(pfn, in, out_high);
+	if (code < 0)
+	    return code;
+	pdf_SepCMYK_ConvertToRGB((float *)&out_high, (float *)&out_high);
+
+	code = pdf_make_base_space_function(pdev, &new_pfn, 3, out_low, out_high);
+	if (code < 0)
+	    return code;
+	if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
+	    (code = cos_array_add_no_copy(pca, snames)) < 0 ||
+	    (code = (int)cos_c_string_value(&v, pcsn->DeviceRGB)) < 0 ||
+	    (code = cos_array_add(pca, &v)) < 0 ||
+	    (code = pdf_function_scaled(pdev, new_pfn, 0x00, &v)) < 0 ||
+	    (code = cos_array_add(pca, &v)) < 0 ||
+	    (v_attributes != NULL ? code = cos_array_add(pca, v_attributes) : 0) < 0
+	    ) {}
+	pdf_delete_base_space_function(pdev, new_pfn);
+	return code;
+    }
+
+    if ((code = cos_array_add(pca, cos_c_string_value(&v, csname))) < 0 ||
+	(code = cos_array_add_no_copy(pca, snames)) < 0 ||
 	(code = pdf_color_space_named(pdev, &v, &ranges, alt_space, pcsn, false, NULL, 0)) < 0 ||
 	(code = cos_array_add(pca, &v)) < 0 ||
 	(code = pdf_function_scaled(pdev, pfn, ranges, &v)) < 0 ||
@@ -951,6 +1161,7 @@
     default:
 	return_error(gs_error_rangecheck);
     }
+
     /*
      * Register the color space as a resource, since it must be referenced
      * by name rather than directly.



More information about the gs-commits mailing list