diff --git a/Makefile b/Makefile
index dc1d760..cbec156 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ DSONAME =
LDFLAGS =
LIBS = -lm -lz
RANLIB = ranlib
-VERSION = 1.0b1
+VERSION = 1.0.0
prefix = /usr/local
diff --git a/pdfio-common.c b/pdfio-common.c
index 55e247e..5f54d70 100644
--- a/pdfio-common.c
+++ b/pdfio-common.c
@@ -377,6 +377,11 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
// No, reset the read buffer
pdf->bufptr = pdf->bufend = NULL;
}
+ else if (pdf->output_cb)
+ {
+ _pdfioFileError(pdf, "Unable to seek within output stream.");
+ return (-1);
+ }
else
{
// Writing, make sure we write any buffered data...
@@ -530,25 +535,37 @@ write_buffer(pdfio_file_t *pdf, // I - PDF file
ssize_t wbytes; // Bytes written...
- // Write to the file...
- while (bytes > 0)
+ if (pdf->output_cb)
{
- while ((wbytes = write(pdf->fd, bufptr, bytes)) < 0)
+ // Write to a stream...
+ if ((pdf->output_cb)(pdf->output_ctx, buffer, bytes) < 0)
{
- // Stop if we have an error that shouldn't be retried...
- if (errno != EINTR && errno != EAGAIN)
- break;
- }
-
- if (wbytes < 0)
- {
- // Hard error...
- _pdfioFileError(pdf, "Unable to write to file - %s", strerror(errno));
+ _pdfioFileError(pdf, "Unable to write to output callback.");
return (false);
}
+ }
+ else
+ {
+ // Write to the file...
+ while (bytes > 0)
+ {
+ while ((wbytes = write(pdf->fd, bufptr, bytes)) < 0)
+ {
+ // Stop if we have an error that shouldn't be retried...
+ if (errno != EINTR && errno != EAGAIN)
+ break;
+ }
- bufptr += wbytes;
- bytes -= (size_t)wbytes;
+ if (wbytes < 0)
+ {
+ // Hard error...
+ _pdfioFileError(pdf, "Unable to write to file - %s", strerror(errno));
+ return (false);
+ }
+
+ bufptr += wbytes;
+ bytes -= (size_t)wbytes;
+ }
}
return (true);
diff --git a/pdfio-file.c b/pdfio-file.c
index e4128c5..0670f50 100644
--- a/pdfio-file.c
+++ b/pdfio-file.c
@@ -130,7 +130,7 @@ pdfioFileClose(pdfio_file_t *pdf) // I - PDF file
ret = _pdfioFileFlush(pdf);
}
- if (close(pdf->fd) < 0)
+ if (pdf->fd >= 0 && close(pdf->fd) < 0)
ret = false;
// Free all data...
@@ -399,6 +399,127 @@ _pdfioFileCreateObj(
}
+//
+// 'pdfioFileCreateOutput()' - Create a PDF file through an output callback.
+//
+
+pdfio_file_t * // O - PDF file or `NULL` on error
+pdfioFileCreateOutput(
+ pdfio_output_cb_t output_cb, // I - Output callback
+ void *output_ctx, // I - Output context
+ const char *version, // I - PDF version number or `NULL` for default (2.0)
+ pdfio_rect_t *media_box, // I - Default MediaBox for pages
+ pdfio_rect_t *crop_box, // I - Default CropBox for pages
+ pdfio_error_cb_t error_cb, // I - Error callback or `NULL` for default
+ void *error_data) // I - Error callback data, if any
+{
+ pdfio_file_t *pdf; // PDF file
+ pdfio_dict_t *dict; // Dictionary for pages object
+ pdfio_dict_t *info_dict; // Dictionary for information object
+
+
+ // Range check input...
+ if (!output_cb)
+ return (NULL);
+
+ if (!version)
+ version = "2.0";
+
+ if (!error_cb)
+ {
+ error_cb = _pdfioFileDefaultError;
+ error_data = NULL;
+ }
+
+ // Allocate a PDF file structure...
+ if ((pdf = (pdfio_file_t *)calloc(1, sizeof(pdfio_file_t))) == NULL)
+ {
+ pdfio_file_t temp; // Dummy file
+ char message[8192]; // Message string
+
+ temp.filename = (char *)"output.pdf";
+ snprintf(message, sizeof(message), "Unable to allocate memory for PDF file - %s", strerror(errno));
+ (error_cb)(&temp, message, error_data);
+ return (NULL);
+ }
+
+ pdf->filename = strdup("output.pdf");
+ pdf->version = strdup(version);
+ pdf->mode = _PDFIO_MODE_WRITE;
+ pdf->error_cb = error_cb;
+ pdf->error_data = error_data;
+ pdf->bufptr = pdf->buffer;
+ pdf->bufend = pdf->buffer + sizeof(pdf->buffer);
+
+ if (media_box)
+ {
+ pdf->media_box = *media_box;
+ }
+ else
+ {
+ // Default to "universal" size (intersection of A4 and US Letter)
+ pdf->media_box.x2 = 210.0 * 72.0f / 25.4f;
+ pdf->media_box.y2 = 11.0f * 72.0f;
+ }
+
+ if (crop_box)
+ {
+ pdf->crop_box = *crop_box;
+ }
+ else
+ {
+ // Default to "universal" size (intersection of A4 and US Letter)
+ pdf->crop_box.x2 = 210.0 * 72.0f / 25.4f;
+ pdf->crop_box.y2 = 11.0f * 72.0f;
+ }
+
+ // Save output callback...
+ pdf->fd = -1;
+ pdf->output_cb = output_cb;
+ pdf->output_ctx = output_ctx;
+
+ // Write a standard PDF header...
+ if (!_pdfioFilePrintf(pdf, "%%PDF-%s\n%%\342\343\317\323\n", version))
+ {
+ pdfioFileClose(pdf);
+ return (NULL);
+ }
+
+ // Create the pages object...
+ if ((dict = pdfioDictCreate(pdf)) == NULL)
+ {
+ pdfioFileClose(pdf);
+ return (NULL);
+ }
+
+ pdfioDictSetName(dict, "Type", "Pages");
+
+ if ((pdf->pages_root = pdfioFileCreateObj(pdf, dict)) == NULL)
+ {
+ pdfioFileClose(pdf);
+ return (NULL);
+ }
+
+ // Create the info object...
+ if ((info_dict = pdfioDictCreate(pdf)) == NULL)
+ {
+ pdfioFileClose(pdf);
+ return (NULL);
+ }
+
+ pdfioDictSetDate(info_dict, "CreationDate", time(NULL));
+ pdfioDictSetString(info_dict, "Producer", "pdfio/" PDFIO_VERSION);
+
+ if ((pdf->info = pdfioFileCreateObj(pdf, info_dict)) == NULL)
+ {
+ pdfioFileClose(pdf);
+ return (NULL);
+ }
+
+ return (pdf);
+}
+
+
//
// 'pdfioFileCreatePage()' - Create a page in a PDF file.
//
diff --git a/pdfio-object.c b/pdfio-object.c
index fef280c..9059ff8 100644
--- a/pdfio-object.c
+++ b/pdfio-object.c
@@ -143,6 +143,9 @@ pdfioObjCreateStream(
pdfio_obj_t *obj, // I - Object
pdfio_filter_t filter) // I - Type of compression to apply
{
+ pdfio_obj_t *length_obj = NULL; // Length object, if any
+
+
// Range check input
if (!obj || obj->pdf->mode != _PDFIO_MODE_WRITE || obj->value.type != PDFIO_VALTYPE_DICT)
return (NULL);
@@ -162,9 +165,23 @@ pdfioObjCreateStream(
// Write the header...
if (!_pdfioDictGetValue(obj->value.value.dict, "Length"))
{
- // Need a Length key for the stream, add a placeholder that we can fill in
- // later...
- pdfioDictSetNumber(obj->value.value.dict, "Length", 0.0);
+ if (obj->pdf->output_cb)
+ {
+ // Streaming via an output callback, so add a placeholder length object
+ _pdfio_value_t length_value; // Length value
+
+ length_value.type = PDFIO_VALTYPE_NUMBER;
+ length_value.value.number = 0.0f;
+
+ length_obj = _pdfioFileCreateObj(obj->pdf, obj->pdf, &length_value);
+ pdfioDictSetObj(obj->value.value.dict, "Length", length_obj);
+ }
+ else
+ {
+ // Need a Length key for the stream, add a placeholder that we can fill in
+ // later...
+ pdfioDictSetNumber(obj->value.value.dict, "Length", 0.0);
+ }
}
if (!write_obj_header(obj))
@@ -176,7 +193,7 @@ pdfioObjCreateStream(
obj->stream_offset = _pdfioFileTell(obj->pdf);
// Return the new stream...
- return (_pdfioStreamCreate(obj, filter));
+ return (_pdfioStreamCreate(obj, length_obj, filter));
}
diff --git a/pdfio-private.h b/pdfio-private.h
index d2c76f0..34d41c3 100644
--- a/pdfio-private.h
+++ b/pdfio-private.h
@@ -210,6 +210,8 @@ struct _pdfio_file_s // PDF file structure
pdfio_rect_t media_box, // Default MediaBox value
crop_box; // Default CropBox value
_pdfio_mode_t mode; // Read/write mode
+ pdfio_output_cb_t output_cb; // Output callback
+ void *output_ctx; // Context for output callback
pdfio_error_cb_t error_cb; // Error callback
void *error_data; // Data for error callback
@@ -266,6 +268,7 @@ struct _pdfio_stream_s // Stream
{
pdfio_file_t *pdf; // PDF file
pdfio_obj_t *obj; // Object
+ pdfio_obj_t *length_obj; // Length object, if any
pdfio_filter_t filter; // Compression/decompression filter
size_t remaining; // Remaining bytes in stream
char buffer[8192], // Read/write buffer
@@ -319,7 +322,7 @@ extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes
extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL;
extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL;
-extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_filter_t compression) _PDFIO_INTERNAL;
+extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, pdfio_filter_t compression) _PDFIO_INTERNAL;
extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL;
extern bool _pdfioStringIsAllocated(pdfio_file_t *pdf, const char *s) _PDFIO_INTERNAL;
diff --git a/pdfio-stream.c b/pdfio-stream.c
index 96492e3..bd6f832 100644
--- a/pdfio-stream.c
+++ b/pdfio-stream.c
@@ -93,7 +93,12 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
}
// Update the length as needed...
- if (st->obj->length_offset)
+ if (st->length_obj)
+ {
+ st->length_obj->value.value.number = st->obj->stream_length;
+ pdfioObjClose(st->length_obj);
+ }
+ else if (st->obj->length_offset)
{
// Seek back to the "/Length 9999999999" we wrote...
if (_pdfioFileSeek(st->pdf, st->obj->length_offset, SEEK_SET) < 0)
@@ -137,6 +142,7 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
pdfio_stream_t * // O - Stream or `NULL` on error
_pdfioStreamCreate(
pdfio_obj_t *obj, // I - Object
+ pdfio_obj_t *length_obj, // I - Length object, if any
pdfio_filter_t compression) // I - Compression to apply
{
pdfio_stream_t *st; // Stream
@@ -149,9 +155,10 @@ _pdfioStreamCreate(
return (NULL);
}
- st->pdf = obj->pdf;
- st->obj = obj;
- st->filter = compression;
+ st->pdf = obj->pdf;
+ st->obj = obj;
+ st->length_obj = length_obj;
+ st->filter = compression;
if (compression == PDFIO_FILTER_FLATE)
{
diff --git a/pdfio.h b/pdfio.h
index c228ad4..d5de27c 100644
--- a/pdfio.h
+++ b/pdfio.h
@@ -74,6 +74,8 @@ typedef enum pdfio_filter_e // Compression/decompression filters for streams
PDFIO_FILTER_RUNLENGTH, // RunLengthDecode filter (reading only)
} pdfio_filter_t;
typedef struct _pdfio_obj_s pdfio_obj_t;// Numbered object in PDF file
+typedef ssize_t (*pdfio_output_cb_t)(void *ctx, const void *data, size_t datalen);
+ // Output callback for pdfioFileCreateOutput
typedef struct pdfio_rect_s // PDF rectangle
{
double x1; // Lower-left X coordinate
@@ -156,6 +158,7 @@ extern bool pdfioFileClose(pdfio_file_t *pdf) _PDFIO_PUBLIC;
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
+extern pdfio_file_t *pdfioFileCreateOutput(pdfio_output_cb_t output_cb, void *output_ctx, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) _PDFIO_PUBLIC;
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) _PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileFindObj(pdfio_file_t *pdf, size_t number) _PDFIO_PUBLIC;
diff --git a/pdfio.vcxproj b/pdfio.vcxproj
index 257b9b4..aa935ff 100644
--- a/pdfio.vcxproj
+++ b/pdfio.vcxproj
@@ -87,7 +87,7 @@
Level3
true
- PDFIO_VERSION="1.0b1";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ PDFIO_VERSION="1.0.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
@@ -101,7 +101,7 @@
true
true
true
- PDFIO_VERSION="1.0b1";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ PDFIO_VERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
@@ -115,7 +115,7 @@
Level3
true
- PDFIO_VERSION="1.0b1";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ PDFIO_VERSION="1.0.0";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
@@ -130,7 +130,7 @@
true
true
true
- PDFIO_VERSION="1.0b1";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ PDFIO_VERSION="1.0.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
diff --git a/pdfio.xcodeproj/project.pbxproj b/pdfio.xcodeproj/project.pbxproj
index 16bad3f..a80d998 100644
--- a/pdfio.xcodeproj/project.pbxproj
+++ b/pdfio.xcodeproj/project.pbxproj
@@ -241,7 +241,7 @@
273440A8263D6FE200FBFD63 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1250;
+ LastUpgradeCheck = 1300;
TargetAttributes = {
273440AF263D6FE200FBFD63 = {
CreatedOnToolsVersion = 12.5;
@@ -350,9 +350,9 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "Developer ID Application";
+ CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 1.0;
+ CURRENT_PROJECT_VERSION = 1.0.0;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -428,9 +428,9 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "Developer ID Application";
+ CODE_SIGN_IDENTITY = "Apple Development";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 1.0;
+ CURRENT_PROJECT_VERSION = 1.0.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
diff --git a/testpdfio.c b/testpdfio.c
index 94ce9f3..25494bf 100644
--- a/testpdfio.c
+++ b/testpdfio.c
@@ -33,6 +33,8 @@ static int do_test_file(const char *filename, int objnum, bool verbose);
static int do_unit_tests(void);
static int draw_image(pdfio_stream_t *st, const char *name, double x, double y, double w, double h, const char *label);
static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
+static ssize_t output_cb(int *fd, const void *buffer, size_t bytes);
+static int read_unit_file(const char *filename, size_t num_pages, size_t first_image, bool is_output);
static ssize_t token_consume_cb(const char **s, size_t bytes);
static ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes);
static int verify_image(pdfio_file_t *pdf, size_t number);
@@ -46,6 +48,7 @@ static int write_images_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
static int write_jpeg_test(pdfio_file_t *pdf, const char *title, int number, pdfio_obj_t *font, pdfio_obj_t *image);
static int write_png_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
static int write_text_test(pdfio_file_t *pdf, int first_page, pdfio_obj_t *font, const char *filename);
+static int write_unit_file(pdfio_file_t *inpdf, pdfio_file_t *outpdf, size_t *num_pages, size_t *first_image);
//
@@ -249,17 +252,13 @@ do_test_file(const char *filename, // I - PDF filename
static int // O - Exit status
do_unit_tests(void)
{
- int i; // Looping var
- pdfio_file_t *pdf, // Test PDF file
+ pdfio_file_t *inpdf, // Input PDF file
*outpdf; // Output PDF file
+ int outfd; // Output file descriptor
bool error = false; // Error callback data
_pdfio_token_t tb; // Token buffer
const char *s; // String buffer
_pdfio_value_t value; // Value
- pdfio_obj_t *color_jpg, // color.jpg image
- *gray_jpg, // gray.jpg image
- *helvetica, // Helvetica font
- *page; // Page from test PDF file
size_t first_image, // First image object
num_pages; // Number of pages written
static const char *complex_dict = // Complex dictionary value
@@ -716,7 +715,7 @@ do_unit_tests(void)
// First open the test PDF file...
fputs("pdfioFileOpen(\"testfiles/testpdfio.pdf\"): ", stdout);
- if ((pdf = pdfioFileOpen("testfiles/testpdfio.pdf", (pdfio_error_cb_t)error_cb, &error)) != NULL)
+ if ((inpdf = pdfioFileOpen("testfiles/testpdfio.pdf", (pdfio_error_cb_t)error_cb, &error)) != NULL)
puts("PASS");
else
return (1);
@@ -726,8 +725,8 @@ do_unit_tests(void)
// Test the value parsers for edge cases...
fputs("_pdfioValueRead(complex_dict): ", stdout);
s = complex_dict;
- _pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
- if (_pdfioValueRead(pdf, &tb, &value))
+ _pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
+ if (_pdfioValueRead(inpdf, &tb, &value))
{
// TODO: Check value...
fputs("PASS: ", stdout);
@@ -740,8 +739,8 @@ do_unit_tests(void)
// Test the value parsers for edge cases...
fputs("_pdfioValueRead(cid_dict): ", stdout);
s = cid_dict;
- _pdfioTokenInit(&tb, pdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
- if (_pdfioValueRead(pdf, &tb, &value))
+ _pdfioTokenInit(&tb, inpdf, (_pdfio_tconsume_cb_t)token_consume_cb, (_pdfio_tpeek_cb_t)token_peek_cb, (void *)&s);
+ if (_pdfioValueRead(inpdf, &tb, &value))
{
// TODO: Check value...
fputs("PASS: ", stdout);
@@ -758,230 +757,31 @@ do_unit_tests(void)
else
return (1);
- // Set info values...
- fputs("pdfioFileGet/SetAuthor: ", stdout);
- pdfioFileSetAuthor(outpdf, "Michael R Sweet");
- if ((s = pdfioFileGetAuthor(outpdf)) != NULL && !strcmp(s, "Michael R Sweet"))
- {
- puts("PASS");
- }
- else if (s)
- {
- printf("FAIL (got '%s', expected 'Michael R Sweet')\n", s);
+ if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
return (1);
- }
- else
+
+ if (read_unit_file("testpdfio-out.pdf", num_pages, first_image, false))
+ return (1);
+
+ // Create a new PDF file...
+ if ((outfd = open("testpdfio-out2.pdf", O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) < 0)
{
- puts("FAIL (got NULL, expected 'Michael R Sweet')");
+ perror("Unable to open \"testpdfio-out2.pdf\"");
return (1);
}
- fputs("pdfioFileGet/SetCreator: ", stdout);
- pdfioFileSetCreator(outpdf, "testpdfio");
- if ((s = pdfioFileGetCreator(outpdf)) != NULL && !strcmp(s, "testpdfio"))
- {
- puts("PASS");
- }
- else if (s)
- {
- printf("FAIL (got '%s', expected 'testpdfio')\n", s);
- return (1);
- }
- else
- {
- puts("FAIL (got NULL, expected 'testpdfio')");
- return (1);
- }
-
- fputs("pdfioFileGet/SetKeywords: ", stdout);
- pdfioFileSetKeywords(outpdf, "one fish,two fish,red fish,blue fish");
- if ((s = pdfioFileGetKeywords(outpdf)) != NULL && !strcmp(s, "one fish,two fish,red fish,blue fish"))
- {
- puts("PASS");
- }
- else if (s)
- {
- printf("FAIL (got '%s', expected 'one fish,two fish,red fish,blue fish')\n", s);
- return (1);
- }
- else
- {
- puts("FAIL (got NULL, expected 'one fish,two fish,red fish,blue fish')");
- return (1);
- }
-
- fputs("pdfioFileGet/SetSubject: ", stdout);
- pdfioFileSetSubject(outpdf, "Unit test document");
- if ((s = pdfioFileGetSubject(outpdf)) != NULL && !strcmp(s, "Unit test document"))
- {
- puts("PASS");
- }
- else if (s)
- {
- printf("FAIL (got '%s', expected 'Unit test document')\n", s);
- return (1);
- }
- else
- {
- puts("FAIL (got NULL, expected 'Unit test document')");
- return (1);
- }
-
- fputs("pdfioFileGet/SetTitle: ", stdout);
- pdfioFileSetTitle(outpdf, "Test Document");
- if ((s = pdfioFileGetTitle(outpdf)) != NULL && !strcmp(s, "Test Document"))
- {
- puts("PASS");
- }
- else if (s)
- {
- printf("FAIL (got '%s', expected 'Test Document')\n", s);
- return (1);
- }
- else
- {
- puts("FAIL (got NULL, expected 'Test Document')");
- return (1);
- }
-
- // Create some image objects...
- fputs("pdfioFileCreateImageObjFromFile(\"testfiles/color.jpg\"): ", stdout);
- if ((color_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/color.jpg", true)) != NULL)
+ fputs("pdfioFileCreateOutput(...): ", stdout);
+ if ((outpdf = pdfioFileCreateOutput((pdfio_output_cb_t)output_cb, &outfd, NULL, NULL, NULL, (pdfio_error_cb_t)error_cb, &error)) != NULL)
puts("PASS");
else
return (1);
- fputs("pdfioFileCreateImageObjFromFile(\"testfiles/gray.jpg\"): ", stdout);
- if ((gray_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/gray.jpg", true)) != NULL)
- puts("PASS");
- else
+ if (write_unit_file(inpdf, outpdf, &num_pages, &first_image))
return (1);
- // Create fonts...
- fputs("pdfioFileCreateFontObjFromBase(\"Helvetica\"): ", stdout);
- if ((helvetica = pdfioFileCreateFontObjFromBase(outpdf, "Helvetica")) != NULL)
- puts("PASS");
- else
- return (1);
+ close(outfd);
- // Copy the first page from the test PDF file...
- fputs("pdfioFileGetPage(0): ", stdout);
- if ((page = pdfioFileGetPage(pdf, 0)) != NULL)
- puts("PASS");
- else
- return (1);
-
- fputs("pdfioPageCopy(first page): ", stdout);
- if (pdfioPageCopy(outpdf, page))
- puts("PASS");
- else
- return (1);
-
- // Write a page with a color image...
- if (write_jpeg_test(outpdf, "Color JPEG Test", 2, helvetica, color_jpg))
- return (1);
-
- // Copy the third page from the test PDF file...
- fputs("pdfioFileGetPage(2): ", stdout);
- if ((page = pdfioFileGetPage(pdf, 2)) != NULL)
- puts("PASS");
- else
- return (1);
-
- fputs("pdfioPageCopy(third page): ", stdout);
- if (pdfioPageCopy(outpdf, page))
- puts("PASS");
- else
- return (1);
-
- // Write a page with a grayscale image...
- if (write_jpeg_test(outpdf, "Grayscale JPEG Test", 4, helvetica, gray_jpg))
- return (1);
-
- // Write a page with PNG images...
- if (write_png_test(outpdf, 5, helvetica))
- return (1);
-
- // Write a page that tests multiple color spaces...
- if (write_color_test(outpdf, 6, helvetica))
- return (1);
-
- // Write a page with test images...
- first_image = pdfioFileGetNumObjs(outpdf) + 1;
- if (write_images_test(outpdf, 7, helvetica))
- return (1);
-
- // Write a page width alpha (soft masks)...
- if (write_alpha_test(outpdf, 8, helvetica))
- return (1);
-
- // Test TrueType fonts...
- if (write_font_test(outpdf, 9, helvetica, false))
- return (1);
-
- if (write_font_test(outpdf, 10, helvetica, true))
- return (1);
-
- // Print this text file...
- if (write_text_test(outpdf, 11, helvetica, "README.md"))
- return (1);
-
- // Close the test PDF file...
- fputs("pdfioFileClose(\"testfiles/testpdfio.pdf\"): ", stdout);
- if (pdfioFileClose(pdf))
- puts("PASS");
- else
- return (1);
-
- fputs("pdfioFileGetNumPages: ", stdout);
- if ((num_pages = pdfioFileGetNumPages(outpdf)) > 0)
- {
- printf("PASS (%lu)\n", (unsigned long)num_pages);
- }
- else
- {
- puts("FAIL");
- return (1);
- }
-
- // Close the new PDF file...
- fputs("pdfioFileClose(\"testpdfio-out.pdf\"): ", stdout);
- if (pdfioFileClose(outpdf))
- puts("PASS");
- else
- return (1);
-
- // Open the new PDF file to read it...
- fputs("pdfioFileOpen(\"testpdfio-out.pdf\", ...): ", stdout);
- if ((pdf = pdfioFileOpen("testpdfio-out.pdf", (pdfio_error_cb_t)error_cb, &error)) != NULL)
- puts("PASS");
- else
- return (1);
-
- // Verify the number of pages is the same...
- fputs("pdfioFileGetNumPages: ", stdout);
- if (num_pages == pdfioFileGetNumPages(pdf))
- {
- puts("PASS");
- }
- else
- {
- printf("FAIL (%lu != %lu)\n", (unsigned long)num_pages, (unsigned long)pdfioFileGetNumPages(pdf));
- return (1);
- }
-
- // Verify the images
- for (i = 0; i < 7; i ++)
- {
- if (verify_image(pdf, first_image + (size_t)i))
- return (1);
- }
-
- // Close the new PDF file...
- fputs("pdfioFileClose(\"testpdfio-out.pdf\"): ", stdout);
- if (pdfioFileClose(pdf))
- puts("PASS");
- else
+ if (read_unit_file("testpdfio-out2.pdf", num_pages, first_image, true))
return (1);
return (0);
@@ -1068,6 +868,76 @@ error_cb(pdfio_file_t *pdf, // I - PDF file
}
+//
+// 'output_cb()' - Write output to a file.
+//
+
+static ssize_t // O - Number of bytes written
+output_cb(int *fd, // I - File descriptor
+ const void *buffer, // I - Output buffer
+ size_t bytes) // I - Number of bytes to write
+{
+ return (write(*fd, buffer, bytes));
+}
+
+
+//
+// 'read_unit_file()' - Read back a unit test file and confirm its contents.
+//
+
+static int // O - Exit status
+read_unit_file(const char *filename, // I - File to read
+ size_t num_pages, // I - Expected number of pages
+ size_t first_image, // I - First image object
+ bool is_output) // I - File written with output callback?
+{
+ pdfio_file_t *pdf; // PDF file
+ size_t i; // Looping var
+ bool error = false; // Error callback data
+
+
+ // Open the new PDF file to read it...
+ printf("pdfioFileOpen(\"%s\", ...): ", filename);
+ if ((pdf = pdfioFileOpen(filename, (pdfio_error_cb_t)error_cb, &error)) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ // Verify the number of pages is the same...
+ fputs("pdfioFileGetNumPages: ", stdout);
+ if (num_pages == pdfioFileGetNumPages(pdf))
+ {
+ puts("PASS");
+ }
+ else
+ {
+ printf("FAIL (%lu != %lu)\n", (unsigned long)num_pages, (unsigned long)pdfioFileGetNumPages(pdf));
+ return (1);
+ }
+
+ // Verify the images
+ for (i = 0; i < 7; i ++)
+ {
+ if (is_output)
+ {
+ if (verify_image(pdf, first_image + (size_t)i * 2))
+ return (1);
+ }
+ else if (verify_image(pdf, first_image + (size_t)i))
+ return (1);
+ }
+
+ // Close the new PDF file...
+ fputs("pdfioFileClose(\"testpdfio-out.pdf\"): ", stdout);
+ if (pdfioFileClose(pdf))
+ puts("PASS");
+ else
+ return (1);
+
+ return (0);
+}
+
+
//
// 'token_consume_cb()' - Consume bytes from a test string.
//
@@ -2843,3 +2713,211 @@ write_text_test(pdfio_file_t *pdf, // I - PDF file
pdfioStreamClose(st);
return (1);
}
+
+
+//
+// 'write_unit_file()' - Write a unit test file.
+//
+
+static int // O - Exit status
+write_unit_file(
+ pdfio_file_t *inpdf, // I - Input PDF file
+ pdfio_file_t *outpdf, // I - Output PDF file
+ size_t *num_pages, // O - Number of pages
+ size_t *first_image) // O - First image object
+{
+ const char *s; // String buffer
+ pdfio_obj_t *color_jpg, // color.jpg image
+ *gray_jpg, // gray.jpg image
+ *helvetica, // Helvetica font
+ *page; // Page from test PDF file
+
+
+ // Set info values...
+ fputs("pdfioFileGet/SetAuthor: ", stdout);
+ pdfioFileSetAuthor(outpdf, "Michael R Sweet");
+ if ((s = pdfioFileGetAuthor(outpdf)) != NULL && !strcmp(s, "Michael R Sweet"))
+ {
+ puts("PASS");
+ }
+ else if (s)
+ {
+ printf("FAIL (got '%s', expected 'Michael R Sweet')\n", s);
+ return (1);
+ }
+ else
+ {
+ puts("FAIL (got NULL, expected 'Michael R Sweet')");
+ return (1);
+ }
+
+ fputs("pdfioFileGet/SetCreator: ", stdout);
+ pdfioFileSetCreator(outpdf, "testpdfio");
+ if ((s = pdfioFileGetCreator(outpdf)) != NULL && !strcmp(s, "testpdfio"))
+ {
+ puts("PASS");
+ }
+ else if (s)
+ {
+ printf("FAIL (got '%s', expected 'testpdfio')\n", s);
+ return (1);
+ }
+ else
+ {
+ puts("FAIL (got NULL, expected 'testpdfio')");
+ return (1);
+ }
+
+ fputs("pdfioFileGet/SetKeywords: ", stdout);
+ pdfioFileSetKeywords(outpdf, "one fish,two fish,red fish,blue fish");
+ if ((s = pdfioFileGetKeywords(outpdf)) != NULL && !strcmp(s, "one fish,two fish,red fish,blue fish"))
+ {
+ puts("PASS");
+ }
+ else if (s)
+ {
+ printf("FAIL (got '%s', expected 'one fish,two fish,red fish,blue fish')\n", s);
+ return (1);
+ }
+ else
+ {
+ puts("FAIL (got NULL, expected 'one fish,two fish,red fish,blue fish')");
+ return (1);
+ }
+
+ fputs("pdfioFileGet/SetSubject: ", stdout);
+ pdfioFileSetSubject(outpdf, "Unit test document");
+ if ((s = pdfioFileGetSubject(outpdf)) != NULL && !strcmp(s, "Unit test document"))
+ {
+ puts("PASS");
+ }
+ else if (s)
+ {
+ printf("FAIL (got '%s', expected 'Unit test document')\n", s);
+ return (1);
+ }
+ else
+ {
+ puts("FAIL (got NULL, expected 'Unit test document')");
+ return (1);
+ }
+
+ fputs("pdfioFileGet/SetTitle: ", stdout);
+ pdfioFileSetTitle(outpdf, "Test Document");
+ if ((s = pdfioFileGetTitle(outpdf)) != NULL && !strcmp(s, "Test Document"))
+ {
+ puts("PASS");
+ }
+ else if (s)
+ {
+ printf("FAIL (got '%s', expected 'Test Document')\n", s);
+ return (1);
+ }
+ else
+ {
+ puts("FAIL (got NULL, expected 'Test Document')");
+ return (1);
+ }
+
+ // Create some image objects...
+ fputs("pdfioFileCreateImageObjFromFile(\"testfiles/color.jpg\"): ", stdout);
+ if ((color_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/color.jpg", true)) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ fputs("pdfioFileCreateImageObjFromFile(\"testfiles/gray.jpg\"): ", stdout);
+ if ((gray_jpg = pdfioFileCreateImageObjFromFile(outpdf, "testfiles/gray.jpg", true)) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ // Create fonts...
+ fputs("pdfioFileCreateFontObjFromBase(\"Helvetica\"): ", stdout);
+ if ((helvetica = pdfioFileCreateFontObjFromBase(outpdf, "Helvetica")) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ // Copy the first page from the test PDF file...
+ fputs("pdfioFileGetPage(0): ", stdout);
+ if ((page = pdfioFileGetPage(inpdf, 0)) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ fputs("pdfioPageCopy(first page): ", stdout);
+ if (pdfioPageCopy(outpdf, page))
+ puts("PASS");
+ else
+ return (1);
+
+ // Write a page with a color image...
+ if (write_jpeg_test(outpdf, "Color JPEG Test", 2, helvetica, color_jpg))
+ return (1);
+
+ // Copy the third page from the test PDF file...
+ fputs("pdfioFileGetPage(2): ", stdout);
+ if ((page = pdfioFileGetPage(inpdf, 2)) != NULL)
+ puts("PASS");
+ else
+ return (1);
+
+ fputs("pdfioPageCopy(third page): ", stdout);
+ if (pdfioPageCopy(outpdf, page))
+ puts("PASS");
+ else
+ return (1);
+
+ // Write a page with a grayscale image...
+ if (write_jpeg_test(outpdf, "Grayscale JPEG Test", 4, helvetica, gray_jpg))
+ return (1);
+
+ // Write a page with PNG images...
+ if (write_png_test(outpdf, 5, helvetica))
+ return (1);
+
+ // Write a page that tests multiple color spaces...
+ if (write_color_test(outpdf, 6, helvetica))
+ return (1);
+
+ // Write a page with test images...
+ *first_image = pdfioFileGetNumObjs(outpdf) + 1;
+ if (write_images_test(outpdf, 7, helvetica))
+ return (1);
+
+ // Write a page width alpha (soft masks)...
+ if (write_alpha_test(outpdf, 8, helvetica))
+ return (1);
+
+ // Test TrueType fonts...
+ if (write_font_test(outpdf, 9, helvetica, false))
+ return (1);
+
+ if (write_font_test(outpdf, 10, helvetica, true))
+ return (1);
+
+ // Print this text file...
+ if (write_text_test(outpdf, 11, helvetica, "README.md"))
+ return (1);
+
+ fputs("pdfioFileGetNumPages: ", stdout);
+ if ((*num_pages = pdfioFileGetNumPages(outpdf)) > 0)
+ {
+ printf("PASS (%lu)\n", (unsigned long)*num_pages);
+ }
+ else
+ {
+ puts("FAIL");
+ return (1);
+ }
+
+ // Close the new PDF file...
+ fputs("pdfioFileClose(...): ", stdout);
+ if (pdfioFileClose(outpdf))
+ puts("PASS");
+ else
+ return (1);
+
+ return (0);
+}