[gs-cvs] rev 6892 - in trunk/gs: doc lib src

leonardo at ghostscript.com leonardo at ghostscript.com
Wed Jul 5 07:03:52 PDT 2006


Author: leonardo
Date: 2006-07-05 07:03:49 -0700 (Wed, 05 Jul 2006)
New Revision: 6892

Modified:
   trunk/gs/doc/Ps2pdf.htm
   trunk/gs/lib/PDFA_def.ps
   trunk/gs/src/devs.mak
   trunk/gs/src/gdevpdf.c
   trunk/gs/src/gdevpdfe.c
   trunk/gs/src/gdevpdtf.c
Log:
Fix (pdfwrite) : More PDF/A-1b complience.

DETAILS :

Bug 688742 "PDF/A label missing error in Acrobat preflight", part 2.

1. Always embed all fonts when writing a PDF/A document.
2. Provide a precize time and time zone (see the documentation change included).
3. Wrtte an OutputConditionIdentifier.
   
See the documentation change for details.

DIFFERENCES :

None.


Modified: trunk/gs/doc/Ps2pdf.htm
===================================================================
--- trunk/gs/doc/Ps2pdf.htm	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/doc/Ps2pdf.htm	2006-07-05 14:03:49 UTC (rev 6892)
@@ -135,6 +135,43 @@
 different name, you must set <b><tt>GSC</tt></b> to the name of the
 executable.
 
+<p>
+The <b><tt>pdfwrite</tt></b> device uses the value of the environment variable <b><tt>TZ</tt></b>
+for generating values of <b><tt>CreationDate</tt></b> and <b><tt>ModDate</tt></b>
+keys of the <b><tt>Info</tt></b> dictionary, and for 
+<b><tt>CreateDate</tt></b> and <b><tt>ModifyDate</tt></b> keys of the document <b><tt>Metadata</tt></b>.
+If the environment variable is not set, the <b><tt>Info</tt></b> dictionary keys do not
+include a time zone specification, and <b><tt>Metadata</tt></b> (if presents)
+specifies the 0th time zone.
+
+Use the commonly known syntax to set the <b><tt>TZ</tt></b> environment variable:
+
+
+<blockquote><b><tt>
+tzn[+ | -]hh[:mm[:ss] ][dzn] 
+</b></tt></blockquote>
+
+<ul>
+<li><b><tt>tzn</tt></b>
+- Three-letter time-zone name, such as PST. You must specify the correct offset from local time to UTC
+(not unused by <b><tt>pdfwrite</tt></b>).
+
+<li><b><tt>hh</tt></b>
+- Difference in hours between UTC and local time. Optionally signed.
+
+<li><b><tt>mm</tt></b>
+- Minutes. Separated from hh by a colon (:).
+
+<li><b><tt>ss</tt></b>
+- Seconds. Separated from mm by a colon (:)
+(not unused by <b><tt>pdfwrite</tt></b>).
+
+<li><b><tt>dzn</tt></b>
+- Three-letter daylight-saving-time zone such as PDT. If daylight saving time is never in effect in the locality, set TZ without a value for dzn. The C run-time library assumes the United States' rules for implementing the calculation of Daylight Saving Time (DST)
+(not unused by <b><tt>pdfwrite</tt></b>).
+</ul>
+
+
 <hr>
 
 <h2><a name="Orientation"></a>Setting page orientation</h2>
@@ -833,6 +870,9 @@
 gs -dPDFX -dBATCH -dNOPAUSE -dNOOUTERSAVE -dUseCIEColor -sDEVICE=pdfwrite -sOutputFile=out-x3.pdf PDFX_def.ps input.ps
 </tt></b></blockquote>
 
+<p>
+Note that the <b><tt>TZ</tt></b> environment variable is necessary for a proper generation 
+of the document the <b><tt>Metadata</tt></b>. See the <a href="#Usage">Usage</a> for details.
 
 <p>
 <hr>
@@ -855,7 +895,11 @@
 gs -dPDFA -dBATCH -dNOPAUSE -dNOOUTERSAVE -dUseCIEColor -sDEVICE=pdfwrite -sOutputFile=out-a.pdf PDFA_def.ps input.ps
 </tt></b></blockquote>
 
+<p>
+Note that the <b><tt>TZ</tt></b> environment variable is necessary for a proper generation 
+of the document the <b><tt>Metadata</tt></b>. See the <a href="#Usage">Usage</a> for details.
 
+
 <p>
 <hr>
 

Modified: trunk/gs/lib/PDFA_def.ps
===================================================================
--- trunk/gs/lib/PDFA_def.ps	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/lib/PDFA_def.ps	2006-07-05 14:03:49 UTC (rev 6892)
@@ -38,5 +38,6 @@
   /Type /OutputIntent             % Must be so (the standard requires).
   /S /GTS_PDFA1                   % Must be so (the standard requires).
   /DestOutputProfile {icc_PDFA}            % Must be so (see above).
+  /OutputConditionIdentifier (CGATS TR001)      % Customize
 >> /PUT pdfmark
 [{Catalog} <</OutputIntents [ {OutputIntent_PDFA} ]>> /PUT pdfmark

Modified: trunk/gs/src/devs.mak
===================================================================
--- trunk/gs/src/devs.mak	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/src/devs.mak	2006-07-05 14:03:49 UTC (rev 6892)
@@ -840,7 +840,7 @@
 $(GLOBJ)gdevpdf.$(OBJ) : $(GLSRC)gdevpdf.c $(GDEVH)\
  $(fcntl__h) $(memory__h) $(string__h) $(time__h) $(unistd__h) $(gp_h)\
  $(gdevpdfg_h) $(gdevpdfo_h) $(gdevpdfx_h) $(gdevpdt_h) $(smd5_h) $(sarc4_h)\
- $(gdevpdfb_h)
+ $(gdevpdfb_h) $(gpgetenv_h)
 	$(GLCC) $(GLO_)gdevpdf.$(OBJ) $(C_) $(GLSRC)gdevpdf.c
 
 $(GLOBJ)gdevpdfb.$(OBJ) : $(GLSRC)gdevpdfb.c\

Modified: trunk/gs/src/gdevpdf.c
===================================================================
--- trunk/gs/src/gdevpdf.c	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/src/gdevpdf.c	2006-07-05 14:03:49 UTC (rev 6892)
@@ -28,6 +28,7 @@
 #include "gdevpdt.h"
 #include "smd5.h"
 #include "sarc4.h"
+#include "gpgetenv.h"
 
 /* Define the default language level and PDF compatibility level. */
 /* Acrobat 4 (PDF 1.3) is the default. */
@@ -243,6 +244,39 @@
     return 0;
 }
 
+private void
+write_time_zone(char *buf, int offset)
+{
+    char tz[20];
+    char *p = tz + 3;
+    int zl;
+    int code = gp_getenv("TZ", tz, &zl);
+
+    if (code != 0) {
+	buf[offset] = ')';
+	buf[offset + 1] = 0;
+	return;
+    }
+    p = tz + 3;
+    zl -= 3;
+    if (*p != '+' && *p != '-') {
+	buf[offset] = '+';
+	offset++;
+    } else {
+	buf[offset] = *p;
+	offset++;
+	p++;
+    }
+    memcpy(buf + offset, p, 2);
+    offset += 2;
+    p += 2;
+    if (*p != ':') {
+	memcpy(buf + offset, "'00'", 4); /* Set the default time zone 0. */
+	return;
+    }
+    memcpy(buf + offset, p, 3);
+}
+
 /* Initialize the IDs allocated at startup. */
 void
 pdf_initialize_ids(gx_device_pdf * pdev)
@@ -275,14 +309,15 @@
     {
 	struct tm tms;
 	time_t t;
-	char buf[1+2+4+2+2+2+2+2+2+1+1]; /* (D:yyyymmddhhmmss)\0 */
+	char buf[1+2+4+2+2+2+2+2+2+1+1+7]; /* (D:yyyymmddhhmmssZhh'mm')\0 */
 
 	time(&t);
 	tms = *localtime(&t);
 	sprintf(buf,
-		"(D:%04d%02d%02d%02d%02d%02d)",
+		"(D:%04d%02d%02d%02d%02d%02dZhh'mm')",
 		tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
 		tms.tm_hour, tms.tm_min, tms.tm_sec);
+	write_time_zone(buf, 17);
 	cos_dict_put_c_key_string(pdev->Info, "/CreationDate", (byte *)buf,
 				  strlen(buf));
 	cos_dict_put_c_key_string(pdev->Info, "/ModDate", (byte *)buf,

Modified: trunk/gs/src/gdevpdfe.c
===================================================================
--- trunk/gs/src/gdevpdfe.c	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/src/gdevpdfe.c	2006-07-05 14:03:49 UTC (rev 6892)
@@ -153,7 +153,7 @@
 
 /* --------------------------------------------  */
 
-private void
+private int
 pdf_xmp_time(char *buf, int buf_length)
 {
     /* We don't write a day time because we don't have a time zone. */
@@ -167,8 +167,92 @@
 	    "%04d-%02d-%02d",
 	    tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday);
     strncpy(buf, buf1, buf_length);
+    return strlen(buf);
 }
 
+private int
+pdf_xmp_convert_time(char *dt, int dtl, char *buf, int bufl)
+{   /* The 'dt' buffer is of same size as 'buf'. */
+    /* Input  sample : D:199812231952?08'00' */
+    /* Output sample : 1997-07-16T19:20:30+01:00 */
+    int l = dtl;
+
+    if (l > bufl)
+	l = bufl;
+    if (dt[0] == 'D' && dt[1] == ':') {
+	l -= 2;
+	memcpy(buf, dt + 2, l);
+    } else
+	memcpy(buf, dt, l);
+    memcpy(dt, buf, 4); /* year */
+    if (l <= 4)
+	return 4;
+
+    dt[4] = '-';
+    memcpy(dt + 5, buf + 4, 2); /* month */
+    if (l <= 6)
+	return 7;
+
+    dt[7] = '-';
+    memcpy(dt + 8, buf + 6, 2); /* day */
+    if (l <= 8)
+	return 10;
+
+    dt[10] = 'T';
+    memcpy(dt + 11, buf + 8, 2); /* hour */
+    dt[13] = ':';
+    memcpy(dt + 14, buf + 10, 2); /* minute */
+    if (l <= 12) {
+	dt[16] = 'Z'; /* Default time zone 0. */
+	return 17;
+    }
+
+    dt[16] = ':';
+    memcpy(dt + 17, buf + 12, 2); /* second */
+    if (l <= 14) {
+	dt[18] = 'Z'; /* Default time zone 0. */
+	return 19;
+    }
+
+    dt[19] = buf[14]; /* designator */
+    if (l <= 15)
+	return 20;
+    memcpy(dt + 20, buf + 15, 2); /* Time zone hour difference. */
+    if (l <= 17)
+	return 22;
+
+    dt[22] = ':';
+    /* Skipping '\'' in 'buf'. */
+    memcpy(dt + 23, buf + 18, 2); /* Time zone hour difference. */
+    return 25;
+}
+	
+private int
+pdf_get_docinfo_item(gx_device_pdf *pdev, const char *key, char *buf, int buf_length)
+{
+    const cos_value_t *v = cos_dict_find(pdev->Info, (const byte *)key, strlen(key));
+    int l;
+    const byte *s;
+
+    if (v != NULL && (v->value_type == COS_VALUE_SCALAR || 
+			v->value_type == COS_VALUE_CONST)) {
+	if (v->contents.chars.size > 2 && v->contents.chars.data[0] == '(') {
+	    s = v->contents.chars.data + 1;
+	    l = v->contents.chars.size - 2;
+	} else {
+	    s = v->contents.chars.data;
+	    l = v->contents.chars.size;
+	}
+    } else
+	return 0;
+    if (l < 0)
+	l = 0;
+    if (l > buf_length)
+	l = buf_length;
+    memcpy(buf, s, l);
+    return l;
+}
+
 private void
 pdf_xmp_write_docinfo_item(gx_device_pdf *pdev, stream *s, const char *key, const char *default_value,
 			   void(*write)(stream *s, const byte *data, int data_length))
@@ -269,7 +353,8 @@
 private int
 pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
 {
-    char instance_uuid[40], document_uuid[40], date_time[40];
+    char instance_uuid[40], document_uuid[40], cre_date_time[40], mod_date_time[40], date_time_buf[40];
+    int cre_date_time_len, mod_date_time_len;
     int code;
     stream *s = pdev->strm;
 
@@ -279,7 +364,18 @@
     code = pdf_make_document_uuid(pdev, digest, document_uuid, sizeof(document_uuid));
     if (code < 0)
 	return code;
-    pdf_xmp_time(date_time, sizeof(date_time));
+
+    
+    cre_date_time_len = pdf_get_docinfo_item(pdev, "/CreationDate", cre_date_time, sizeof(cre_date_time));
+    if (!cre_date_time_len)
+	cre_date_time_len = pdf_xmp_time(cre_date_time, sizeof(cre_date_time));
+    else
+	cre_date_time_len = pdf_xmp_convert_time(cre_date_time, cre_date_time_len, date_time_buf, sizeof(date_time_buf));
+    mod_date_time_len = pdf_get_docinfo_item(pdev, "/CreationDate", mod_date_time, sizeof(mod_date_time));
+    if (!mod_date_time_len)
+	mod_date_time_len = pdf_xmp_time(mod_date_time, sizeof(mod_date_time));
+    else
+	mod_date_time_len = pdf_xmp_convert_time(mod_date_time, mod_date_time_len, date_time_buf, sizeof(date_time_buf));
     pdf_xml_ins_beg(s, "xpacket");
     pdf_xml_attribute_name(s, "begin");
     pdf_xml_copy(s, dd);
@@ -313,22 +409,15 @@
 	    pdf_xml_attribute_name(s, "xmlns:xap");
 	    pdf_xml_attribute_value(s, "http://ns.adobe.com/xap/1.0/");
 	    pdf_xml_attribute_name(s, "xap:ModifyDate");
-	    pdf_xml_attribute_value(s, date_time);
+	    pdf_xml_attribute_value_data(s, (const byte *)mod_date_time, mod_date_time_len);
 	    pdf_xml_attribute_name(s, "xap:CreateDate");
-	    pdf_xml_attribute_value(s, date_time);
+	    pdf_xml_attribute_value_data(s, (const byte *)cre_date_time, cre_date_time_len);
 	    pdf_xml_tag_end(s);
 	    {
 		pdf_xml_tag_open_beg(s, "xap:CreatorTool");
 		pdf_xml_tag_end(s);
-		{
-		    char buf[10];
-
-		    sprintf(buf, "%d.%02d", (int)(gs_revision / 100), (int)(gs_revision % 100));
-		    pdf_xml_string_write(s, gs_product);
-		    pdf_xml_string_write(s, " ");
-		    pdf_xml_string_write(s, buf);
-		    pdf_xml_string_write(s, " PDF Writer");
-		}
+		pdf_xmp_write_docinfo_item(pdev, s,  "/Creator", "UnknownApplication",
+			pdf_xml_data_write);
 		pdf_xml_tag_close(s, "xap:CreatorTool");
 	    }
 	    pdf_xml_tag_close(s, "rdf:Description");
@@ -403,8 +492,7 @@
 		pdf_xml_attribute_value(s,"1");
 		pdf_xml_attribute_name(s, "pdfaid:conformance");
 		pdf_xml_attribute_value(s,"B");
-		pdf_xml_tag_end(s);
-		pdf_xml_tag_close(s, "rdf:Description");
+		pdf_xml_tag_end_empty(s);
 	   }
 	}
 	pdf_xml_copy(s, "</rdf:RDF>\n");

Modified: trunk/gs/src/gdevpdtf.c
===================================================================
--- trunk/gs/src/gdevpdtf.c	2006-07-05 10:26:03 UTC (rev 6891)
+++ trunk/gs/src/gdevpdtf.c	2006-07-05 14:03:49 UTC (rev 6892)
@@ -676,7 +676,7 @@
      */
     if (pindex)
 	*pindex = index;
-    if (pdev->PDFX)
+    if (pdev->PDFX || pdev->PDFA)
 	return FONT_EMBED_YES;
     if (pdev->CompatibilityLevel < 1.3) {
 	if (index >= 0 && 



More information about the gs-cvs mailing list