From f09105dd3fab2920d6c021b015b4247b79c2268f Mon Sep 17 00:00:00 2001
From: Michael R Sweet
Date: Thu, 20 Feb 2025 18:18:53 -0500
Subject: [PATCH] Add support for writing the PCLm subset of PDF (Issue #99)
---
CHANGES.md | 1 +
doc/pdfio.3 | 22 ++++++++++++++++++----
doc/pdfio.html | 42 +++++++++++++++++++++++++++++++++++++-----
pdfio-file.c | 33 +++++++++++++++++++++++++++------
4 files changed, 83 insertions(+), 15 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 7ec59a7..735ee58 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ v1.5.0 - YYYY-MM-DD
(Issue #10)
- Added `pdfioFileGetModDate()` API (Issue #88)
- Added support for using libpng to embed PNG images in PDF output (Issue #90)
+- Added support for writing the PCLm subset of PDF (Issue #99)
- Now support opening damaged PDF files (Issue #45)
- Updated the pdf2txt example to support font encodings.
diff --git a/doc/pdfio.3 b/doc/pdfio.3
index 837f56c..30aea17 100644
--- a/doc/pdfio.3
+++ b/doc/pdfio.3
@@ -1,4 +1,4 @@
-.TH pdfio 3 "pdf read/write library" "2025-02-13" "pdf read/write library"
+.TH pdfio 3 "pdf read/write library" "2025-02-20" "pdf read/write library"
.SH NAME
pdfio \- pdf read/write library
.SH Introduction
@@ -3561,7 +3561,8 @@ This function creates a new PDF file. The "filename" argument specifies the
name of the PDF file to create.
.PP
The "version" argument specifies the PDF version number for the file or
-\fBNULL\fR for the default ("2.0").
+\fBNULL\fR for the default ("2.0"). The value "PCLm-1.0" can be specified to
+produce the PCLm subset of PDF.
.PP
The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
@@ -3643,8 +3644,19 @@ This function embeds a TrueType/OpenType font into a PDF file. The
characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode.
+.SS pdfioFileCreateICCObjFromData
+Add ICC profile data to a PDF file.
+.PP
+.nf
+pdfio_obj_t * pdfioFileCreateICCObjFromData (
+ pdfio_file_t *pdf,
+ const unsigned char *data,
+ size_t datalen,
+ size_t num_colors
+);
+.fi
.SS pdfioFileCreateICCObjFromFile
-Add an ICC profile object to a PDF file.
+Add an ICC profile file to a PDF file.
.PP
.nf
pdfio_obj_t * pdfioFileCreateICCObjFromFile (
@@ -3767,7 +3779,9 @@ written:
.fi
The "version" argument specifies the PDF version number for the file or
-\fBNULL\fR for the default ("2.0").
+\fBNULL\fR for the default ("2.0"). Unlike \fIpdfioFileCreate\fR and
+\fIpdfioFileCreateTemporary\fR, it is generally not safe to pass the
+"PCLm-1.0" version string.
.PP
The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if \fBNULL\fR then a default "Universal" size
diff --git a/doc/pdfio.html b/doc/pdfio.html
index c3bc4c4..d695b88 100644
--- a/doc/pdfio.html
+++ b/doc/pdfio.html
@@ -400,6 +400,7 @@ span.string {
pdfioFileCreateArrayObj
pdfioFileCreateFontObjFromBase
pdfioFileCreateFontObjFromFile
+pdfioFileCreateICCObjFromData
pdfioFileCreateICCObjFromFile
pdfioFileCreateImageObjFromData
pdfioFileCreateImageObjFromFile
@@ -3814,7 +3815,8 @@ have been iterated.
name of the PDF file to create.
The "version" argument specifies the PDF version number for the file or
-NULL
for the default ("2.0").
+NULL
for the default ("2.0"). The value "PCLm-1.0" can be specified to
+produce the PCLm subset of PDF.
The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if NULL
then a default "Universal" size
@@ -3909,8 +3911,25 @@ Unicode.
characters (potentially full Unicode, but more typically a subset)
or to only support the Windows CP1252 (ISO-8859-1 with additional
characters such as the Euro symbol) subset of Unicode.
+
+Add ICC profile data to a PDF file.
+
+pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors);
+Parameters
+
+pdf |
+PDF file |
+data |
+ICC profile buffer |
+datalen |
+Length of ICC profile |
+num_colors |
+Number of color components (1, 3, or 4) |
+
+Return Value
+Object
-Add an ICC profile object to a PDF file.
+Add an ICC profile file to a PDF file.
pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors);
Parameters
@@ -4071,7 +4090,9 @@ output_cb(void *output_cbdata, const void *buffer, size_t bytes)
The "version" argument specifies the PDF version number for the file or
-NULL
for the default ("2.0").
+NULL
for the default ("2.0"). Unlike pdfioFileCreate
and
+pdfioFileCreateTemporary
, it is generally not safe to pass the
+"PCLm-1.0" version string.
The "media_box" and "crop_box" arguments specify the default MediaBox and
CropBox for pages in the PDF file - if NULL
then a default "Universal" size
@@ -4139,8 +4160,19 @@ You must call pdfioObjClose
to write t
Create a temporary PDF file.
This function creates a PDF file with a unique filename in the current
temporary directory. The temporary file is stored in the string "buffer" an
-will have a ".pdf" extension. Otherwise, this function works the same as
-the pdfioFileCreate
function.
+will have a ".pdf" extension.
+
+The "version" argument specifies the PDF version number for the file or
+NULL
for the default ("2.0"). The value "PCLm-1.0" can be specified to
+produce the PCLm subset of PDF.
+
+The "media_box" and "crop_box" arguments specify the default MediaBox and
+CropBox for pages in the PDF file - if NULL
then a default "Universal" size
+of 8.27x11in (the intersection of US Letter and ISO A4) is used.
+
+The "error_cb" and "error_cbdata" arguments specify an error handler callback
+and its data pointer - if NULL
the default error handler is used that
+writes error messages to stderr
.
diff --git a/pdfio-file.c b/pdfio-file.c
index eba6a95..7af5617 100644
--- a/pdfio-file.c
+++ b/pdfio-file.c
@@ -165,7 +165,8 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
// name of the PDF file to create.
//
// The "version" argument specifies the PDF version number for the file or
-// `NULL` for the default ("2.0").
+// `NULL` for the default ("2.0"). The value "PCLm-1.0" can be specified to
+// produce the PCLm subset of PDF.
//
// The "media_box" and "crop_box" arguments specify the default MediaBox and
// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
@@ -397,7 +398,9 @@ _pdfioFileCreateObj(
// ```
//
// The "version" argument specifies the PDF version number for the file or
-// `NULL` for the default ("2.0").
+// `NULL` for the default ("2.0"). Unlike @link pdfioFileCreate@ and
+// @link pdfioFileCreateTemporary@, it is generally not safe to pass the
+// "PCLm-1.0" version string.
//
// The "media_box" and "crop_box" arguments specify the default MediaBox and
// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
@@ -532,8 +535,19 @@ pdfioFileCreateStringObj(
//
// This function creates a PDF file with a unique filename in the current
// temporary directory. The temporary file is stored in the string "buffer" an
-// will have a ".pdf" extension. Otherwise, this function works the same as
-// the @link pdfioFileCreate@ function.
+// will have a ".pdf" extension.
+//
+// The "version" argument specifies the PDF version number for the file or
+// `NULL` for the default ("2.0"). The value "PCLm-1.0" can be specified to
+// produce the PCLm subset of PDF.
+//
+// The "media_box" and "crop_box" arguments specify the default MediaBox and
+// CropBox for pages in the PDF file - if `NULL` then a default "Universal" size
+// of 8.27x11in (the intersection of US Letter and ISO A4) is used.
+//
+// The "error_cb" and "error_cbdata" arguments specify an error handler callback
+// and its data pointer - if `NULL` the default error handler is used that
+// writes error messages to `stderr`.
//
// @since PDFio v1.1@
//
@@ -1396,7 +1410,7 @@ create_common(
pdf->output_cb = output_cb;
pdf->output_ctx = output_cbdata;
pdf->filename = strdup(filename);
- pdf->version = strdup(version);
+ pdf->version = strdup(!strncmp(version, "PCLm-", 5) ? "1.4" : version);
pdf->mode = _PDFIO_MODE_WRITE;
pdf->error_cb = error_cb;
pdf->error_data = error_cbdata;
@@ -1427,8 +1441,15 @@ create_common(
}
// Write a standard PDF header...
- if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
+ if (!strncmp(version, "PCLm-", 5))
+ {
+ if (!_pdfioFilePrintf(pdf, "%%PDF-1.4\n%%%s\n", version))
+ goto error;
+ }
+ else if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
+ {
goto error;
+ }
// Create the pages object...
if ((dict = pdfioDictCreate(pdf)) == NULL)