Refactor pdfioFileCreateImageObjFromData to do the image writing in a separate

function (Issue #90)
This commit is contained in:
Michael R Sweet 2025-02-10 10:28:28 -05:00
parent 5b5de3aff6
commit 6f4bfe107f
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244

View File

@ -86,6 +86,7 @@ typedef pdfio_obj_t *(*_pdfio_image_func_t)(pdfio_dict_t *dict, int fd);
static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd); static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd);
static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd); static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd);
static bool create_cp1252(pdfio_file_t *pdf); static bool create_cp1252(pdfio_file_t *pdf);
static pdfio_obj_t *create_image(pdfio_file_t *pdf, pdfio_dict_t *dict, const unsigned char *data, size_t width, size_t height, size_t num_colors, bool alpha);
static void ttf_error_cb(pdfio_file_t *pdf, const char *message); static void ttf_error_cb(pdfio_file_t *pdf, const char *message);
static unsigned update_png_crc(unsigned crc, const unsigned char *buffer, size_t length); static unsigned update_png_crc(unsigned crc, const unsigned char *buffer, size_t length);
static bool write_string(pdfio_stream_t *st, bool unicode, const char *s, bool *newline); static bool write_string(pdfio_stream_t *st, bool unicode, const char *s, bool *newline);
@ -1976,18 +1977,7 @@ pdfioFileCreateImageObjFromData(
bool alpha, // I - `true` if data contains an alpha channel bool alpha, // I - `true` if data contains an alpha channel
bool interpolate) // I - Interpolate image data? bool interpolate) // I - Interpolate image data?
{ {
pdfio_dict_t *dict, // Image dictionary pdfio_dict_t *dict; // Image dictionary
*decode; // DecodeParms dictionary
pdfio_obj_t *obj, // Image object
*mask_obj = NULL;
// Mask image object, if any
pdfio_stream_t *st; // Image stream
size_t x, y, // X and Y position in image
bpp, // Bytes per pixel
linelen; // Line length
const unsigned char *dataptr; // Pointer into image data
unsigned char *line = NULL, // Current line
*lineptr; // Pointer into line
static const char *defcolors[] = // Default ColorSpace values static const char *defcolors[] = // Default ColorSpace values
{ {
NULL, NULL,
@ -2002,74 +1992,9 @@ pdfioFileCreateImageObjFromData(
if (!pdf || !data || !width || !height || num_colors < 1 || num_colors == 2 || num_colors > 4) if (!pdf || !data || !width || !height || num_colors < 1 || num_colors == 2 || num_colors > 4)
return (NULL); return (NULL);
// Allocate memory for one line of data... // Create the image dictionary...
bpp = alpha ? num_colors + 1 : num_colors;
linelen = num_colors * width;
if ((line = malloc(linelen)) == NULL)
return (NULL);
// Generate a mask image, as needed...
if (alpha)
{
// Create the image mask dictionary...
if ((dict = pdfioDictCreate(pdf)) == NULL) if ((dict = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL); return (NULL);
}
pdfioDictSetName(dict, "Type", "XObject");
pdfioDictSetName(dict, "Subtype", "Image");
pdfioDictSetNumber(dict, "Width", width);
pdfioDictSetNumber(dict, "Height", height);
pdfioDictSetNumber(dict, "BitsPerComponent", 8);
pdfioDictSetName(dict, "ColorSpace", "DeviceGray");
pdfioDictSetName(dict, "Filter", "FlateDecode");
if ((decode = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL);
}
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
pdfioDictSetNumber(decode, "Colors", 1);
pdfioDictSetNumber(decode, "Columns", width);
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
pdfioDictSetDict(dict, "DecodeParms", decode);
// Create the mask object and write the mask image...
if ((mask_obj = pdfioFileCreateObj(pdf, dict)) == NULL)
{
free(line);
return (NULL);
}
if ((st = pdfioObjCreateStream(mask_obj, PDFIO_FILTER_FLATE)) == NULL)
{
free(line);
pdfioObjClose(mask_obj);
return (NULL);
}
for (y = height, dataptr = data + num_colors; y > 0; y --)
{
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
*lineptr++ = *dataptr;
pdfioStreamWrite(st, line, width);
}
pdfioStreamClose(st);
}
// Now create the image...
if ((dict = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL);
}
pdfioDictSetName(dict, "Type", "XObject"); pdfioDictSetName(dict, "Type", "XObject");
pdfioDictSetName(dict, "Subtype", "Image"); pdfioDictSetName(dict, "Subtype", "Image");
@ -2077,83 +2002,14 @@ pdfioFileCreateImageObjFromData(
pdfioDictSetNumber(dict, "Width", width); pdfioDictSetNumber(dict, "Width", width);
pdfioDictSetNumber(dict, "Height", height); pdfioDictSetNumber(dict, "Height", height);
pdfioDictSetNumber(dict, "BitsPerComponent", 8); pdfioDictSetNumber(dict, "BitsPerComponent", 8);
pdfioDictSetName(dict, "Filter", "FlateDecode");
if (color_data) if (color_data)
pdfioDictSetArray(dict, "ColorSpace", color_data); pdfioDictSetArray(dict, "ColorSpace", color_data);
else else
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]); pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
if (mask_obj) // Create the image object(s)...
pdfioDictSetObj(dict, "SMask", mask_obj); return (create_image(pdf, dict, data, width, height, num_colors, alpha));
if ((decode = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL);
}
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
pdfioDictSetNumber(decode, "Colors", num_colors);
pdfioDictSetNumber(decode, "Columns", width);
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
pdfioDictSetDict(dict, "DecodeParms", decode);
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
{
free(line);
return (NULL);
}
if ((st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE)) == NULL)
{
free(line);
pdfioObjClose(obj);
return (NULL);
}
for (y = height, dataptr = data; y > 0; y --)
{
if (alpha)
{
switch (num_colors)
{
case 1 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
*lineptr++ = *dataptr;
break;
case 3 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
{
*lineptr++ = dataptr[0];
*lineptr++ = dataptr[1];
*lineptr++ = dataptr[2];
}
break;
case 4 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
{
*lineptr++ = dataptr[0];
*lineptr++ = dataptr[1];
*lineptr++ = dataptr[2];
*lineptr++ = dataptr[3];
}
break;
}
pdfioStreamWrite(st, line, linelen);
}
else
{
pdfioStreamWrite(st, dataptr, linelen);
dataptr += linelen;
}
}
free(line);
pdfioStreamClose(st);
return (obj);
} }
@ -3227,6 +3083,170 @@ create_cp1252(pdfio_file_t *pdf) // I - PDF file
} }
//
// 'create_image()' - Create an image object from some data.
//
static pdfio_obj_t * // O - PDF object or `NULL` on error
create_image(
pdfio_file_t *pdf, // I - PDF file
pdfio_dict_t *dict, // I - Image dictionary
const unsigned char *data, // I - Image data
size_t width, // I - Width in columns
size_t height, // I - Height in lines
size_t num_colors, // I - Number of colors
bool alpha) // I - `true` if there is transparency
{
pdfio_dict_t *mask_dict, // Mask image dictionary
*decode; // DecodeParms dictionary
pdfio_obj_t *obj, // Image object
*mask_obj = NULL;
// Mask image object, if any
pdfio_stream_t *st; // Image stream
size_t x, y, // X and Y position in image
bpp, // Bytes per pixel
linelen; // Line length
const unsigned char *dataptr; // Pointer into image data
unsigned char *line = NULL, // Current line
*lineptr; // Pointer into line
// Allocate memory for one line of data...
bpp = alpha ? num_colors + 1 : num_colors;
linelen = num_colors * width;
if ((line = malloc(linelen)) == NULL)
return (NULL);
// Use Flate compression...
pdfioDictSetName(dict, "Filter", "FlateDecode");
// Generate a mask image, as needed...
if (alpha)
{
// Create the image mask dictionary...
if ((mask_dict = pdfioDictCopy(pdf, dict)) == NULL)
{
free(line);
return (NULL);
}
// Transparency masks are always grayscale...
pdfioDictSetName(mask_dict, "ColorSpace", "DeviceGray");
// Set the automatic PNG predictor to optimize compression...
if ((decode = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL);
}
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
pdfioDictSetNumber(decode, "Colors", 1);
pdfioDictSetNumber(decode, "Columns", width);
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
pdfioDictSetDict(mask_dict, "DecodeParms", decode);
// Create the mask object and write the mask image...
if ((mask_obj = pdfioFileCreateObj(pdf, mask_dict)) == NULL)
{
free(line);
return (NULL);
}
if ((st = pdfioObjCreateStream(mask_obj, PDFIO_FILTER_FLATE)) == NULL)
{
free(line);
pdfioObjClose(mask_obj);
return (NULL);
}
for (y = height, dataptr = data + num_colors; y > 0; y --)
{
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
*lineptr++ = *dataptr;
pdfioStreamWrite(st, line, width);
}
pdfioStreamClose(st);
// Use the transparency mask...
pdfioDictSetObj(dict, "SMask", mask_obj);
}
// Set the automatic PNG predictor to optimize compression...
if ((decode = pdfioDictCreate(pdf)) == NULL)
{
free(line);
return (NULL);
}
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
pdfioDictSetNumber(decode, "Colors", num_colors);
pdfioDictSetNumber(decode, "Columns", width);
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
pdfioDictSetDict(dict, "DecodeParms", decode);
// Now create the image...
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
{
free(line);
return (NULL);
}
if ((st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE)) == NULL)
{
free(line);
pdfioObjClose(obj);
return (NULL);
}
for (y = height, dataptr = data; y > 0; y --)
{
if (alpha)
{
switch (num_colors)
{
case 1 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
*lineptr++ = *dataptr;
break;
case 3 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
{
*lineptr++ = dataptr[0];
*lineptr++ = dataptr[1];
*lineptr++ = dataptr[2];
}
break;
case 4 :
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
{
*lineptr++ = dataptr[0];
*lineptr++ = dataptr[1];
*lineptr++ = dataptr[2];
*lineptr++ = dataptr[3];
}
break;
}
pdfioStreamWrite(st, line, linelen);
}
else
{
pdfioStreamWrite(st, dataptr, linelen);
dataptr += linelen;
}
}
free(line);
pdfioStreamClose(st);
return (obj);
}
// //
// 'ttf_error_cb()' - Relay a message from the TTF functions. // 'ttf_error_cb()' - Relay a message from the TTF functions.
// //