mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-26 05:18:21 +01:00
Add pdfioFileCreateOutput API (Issue #21)
This commit is contained in:
parent
9f1cadf78b
commit
d6746c08a4
2
Makefile
2
Makefile
@ -25,7 +25,7 @@ DSONAME =
|
||||
LDFLAGS =
|
||||
LIBS = -lm -lz
|
||||
RANLIB = ranlib
|
||||
VERSION = 1.0b1
|
||||
VERSION = 1.0.0
|
||||
prefix = /usr/local
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
123
pdfio-file.c
123
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.
|
||||
//
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
3
pdfio.h
3
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;
|
||||
|
@ -87,7 +87,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0.0";WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -101,7 +101,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0.0";WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -115,7 +115,7 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0.0";_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -130,7 +130,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0b1";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>PDFIO_VERSION="1.0.0";NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -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;
|
||||
|
524
testpdfio.c
524
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user