mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-27 21:58:22 +01:00
Rework pdfioFileCreateImageObjFromData to have a separate alpha argument so
that CMYK images can be supported. Add unit tests.
This commit is contained in:
parent
014c5dccba
commit
3e0507ba6c
@ -1641,8 +1641,9 @@ pdfioFileCreateImageObjFromData(
|
|||||||
const unsigned char *data, // I - Pointer to image data
|
const unsigned char *data, // I - Pointer to image data
|
||||||
size_t width, // I - Width of image
|
size_t width, // I - Width of image
|
||||||
size_t height, // I - Height of image
|
size_t height, // I - Height of image
|
||||||
int num_colors, // I - Number of colors
|
size_t num_colors, // I - Number of colors
|
||||||
pdfio_array_t *color_data, // I - Colorspace data or `NULL` for default
|
pdfio_array_t *color_data, // I - Colorspace data or `NULL` for default
|
||||||
|
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
|
||||||
@ -1652,24 +1653,34 @@ pdfioFileCreateImageObjFromData(
|
|||||||
// Mask image object, if any
|
// Mask image object, if any
|
||||||
pdfio_stream_t *st; // Image stream
|
pdfio_stream_t *st; // Image stream
|
||||||
size_t x, y, // X and Y position in image
|
size_t x, y, // X and Y position in image
|
||||||
|
bpp, // Bytes per pixel
|
||||||
linelen; // Line length
|
linelen; // Line length
|
||||||
const unsigned char *dataptr; // Pointer into image data
|
const unsigned char *dataptr; // Pointer into image data
|
||||||
unsigned char *line = NULL, // Current line
|
unsigned char *line = NULL, // Current line
|
||||||
*lineptr; // Pointer into line
|
*lineptr; // Pointer into line
|
||||||
|
static const char *defcolors[] = // Default ColorSpace values
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
"DeviceGray",
|
||||||
|
NULL,
|
||||||
|
"DeviceRGB",
|
||||||
|
"DeviceCMYK"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!pdf || !data || !width || !height || num_colors < 1 || 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...
|
// Allocate memory for one line of data...
|
||||||
linelen = (num_colors < 3 ? 1 : 3) * width;
|
bpp = alpha ? num_colors + 1 : num_colors;
|
||||||
|
linelen = num_colors * width;
|
||||||
|
|
||||||
if ((line = malloc(linelen)) == NULL)
|
if ((line = malloc(linelen)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
// Generate a mask image, as needed...
|
// Generate a mask image, as needed...
|
||||||
if (!(num_colors & 1))
|
if (alpha)
|
||||||
{
|
{
|
||||||
// Create the image mask dictionary...
|
// Create the image mask dictionary...
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
@ -1711,9 +1722,9 @@ pdfioFileCreateImageObjFromData(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = height, dataptr = data + num_colors - 1; y > 0; y --)
|
for (y = height, dataptr = data + num_colors; y > 0; y --)
|
||||||
{
|
{
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += num_colors)
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
*lineptr++ = *dataptr;
|
*lineptr++ = *dataptr;
|
||||||
|
|
||||||
pdfioStreamWrite(st, line, width);
|
pdfioStreamWrite(st, line, width);
|
||||||
@ -1739,7 +1750,7 @@ pdfioFileCreateImageObjFromData(
|
|||||||
if (color_data)
|
if (color_data)
|
||||||
pdfioDictSetArray(dict, "ColorSpace", color_data);
|
pdfioDictSetArray(dict, "ColorSpace", color_data);
|
||||||
else
|
else
|
||||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromMatrix(pdf, num_colors < 3 ? 1 : 3, pdfioSRGBGamma, pdfioSRGBMatrix, pdfioSRGBWhitePoint));
|
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
|
||||||
|
|
||||||
if (mask_obj)
|
if (mask_obj)
|
||||||
pdfioDictSetObj(dict, "SMask", mask_obj);
|
pdfioDictSetObj(dict, "SMask", mask_obj);
|
||||||
@ -1751,7 +1762,7 @@ pdfioFileCreateImageObjFromData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
|
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
|
||||||
pdfioDictSetNumber(decode, "Colors", num_colors < 3 ? 1 : 3);
|
pdfioDictSetNumber(decode, "Colors", num_colors);
|
||||||
pdfioDictSetNumber(decode, "Columns", width);
|
pdfioDictSetNumber(decode, "Columns", width);
|
||||||
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
|
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
|
||||||
pdfioDictSetDict(dict, "DecodeParms", decode);
|
pdfioDictSetDict(dict, "DecodeParms", decode);
|
||||||
@ -1771,30 +1782,39 @@ pdfioFileCreateImageObjFromData(
|
|||||||
|
|
||||||
for (y = height, dataptr = data; y > 0; y --)
|
for (y = height, dataptr = data; y > 0; y --)
|
||||||
{
|
{
|
||||||
switch (num_colors)
|
if (alpha)
|
||||||
{
|
{
|
||||||
case 1 :
|
switch (num_colors)
|
||||||
pdfioStreamWrite(st, dataptr, linelen);
|
{
|
||||||
dataptr += linelen;
|
case 1 :
|
||||||
break;
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
case 2 :
|
*lineptr++ = *dataptr;
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += num_colors)
|
break;
|
||||||
*lineptr++ = *dataptr;
|
case 3 :
|
||||||
pdfioStreamWrite(st, line, linelen);
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
break;
|
{
|
||||||
case 3 :
|
*lineptr++ = dataptr[0];
|
||||||
pdfioStreamWrite(st, dataptr, linelen);
|
*lineptr++ = dataptr[1];
|
||||||
dataptr += linelen;
|
*lineptr++ = dataptr[2];
|
||||||
break;
|
}
|
||||||
case 4 :
|
break;
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += num_colors)
|
case 4 :
|
||||||
{
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
*lineptr++ = dataptr[0];
|
{
|
||||||
*lineptr++ = dataptr[1];
|
*lineptr++ = dataptr[0];
|
||||||
*lineptr++ = dataptr[2];
|
*lineptr++ = dataptr[1];
|
||||||
}
|
*lineptr++ = dataptr[2];
|
||||||
pdfioStreamWrite(st, line, linelen);
|
*lineptr++ = dataptr[3];
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioStreamWrite(st, line, linelen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pdfioStreamWrite(st, dataptr, linelen);
|
||||||
|
dataptr += linelen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, siz
|
|||||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t width, size_t height, int num_colors, pdfio_array_t *color_data, bool interpolate) PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateImageObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t width, size_t height, size_t num_colors, pdfio_array_t *color_data, bool alpha, bool interpolate) PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateImageObjFromFile(pdfio_file_t *pdf, const char *filename, bool interpolate) PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateImageObjFromFile(pdfio_file_t *pdf, const char *filename, bool interpolate) PDFIO_PUBLIC;
|
||||||
|
|
||||||
// Image object helpers...
|
// Image object helpers...
|
||||||
|
196
testpdfio.c
196
testpdfio.c
@ -33,6 +33,7 @@ static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error);
|
|||||||
static ssize_t token_consume_cb(const char **s, size_t bytes);
|
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 ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes);
|
||||||
static int verify_image(pdfio_file_t *pdf, size_t number);
|
static int verify_image(pdfio_file_t *pdf, size_t number);
|
||||||
|
static int write_alpha_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
static int write_color_patch(pdfio_stream_t *st, bool device);
|
static int write_color_patch(pdfio_stream_t *st, bool device);
|
||||||
static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font);
|
||||||
static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, bool unicode);
|
static int write_font_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font, bool unicode);
|
||||||
@ -417,15 +418,19 @@ do_unit_tests(void)
|
|||||||
if (write_images_test(outpdf, 7, helvetica))
|
if (write_images_test(outpdf, 7, helvetica))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
// Test TrueType fonts...
|
// Write a page width alpha (soft masks)...
|
||||||
if (write_font_test(outpdf, 8, helvetica, false))
|
if (write_alpha_test(outpdf, 8, helvetica))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
if (write_font_test(outpdf, 9, helvetica, true))
|
// Test TrueType fonts...
|
||||||
|
if (write_font_test(outpdf, 9, helvetica, false))
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (write_font_test(outpdf, 10, helvetica, true))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
// Print this text file...
|
// Print this text file...
|
||||||
if (write_text_test(outpdf, 10, helvetica, "README.md"))
|
if (write_text_test(outpdf, 11, helvetica, "README.md"))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
// Close the test PDF file...
|
// Close the test PDF file...
|
||||||
@ -723,6 +728,182 @@ verify_image(pdfio_file_t *pdf, // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'write_alpha_test()' - Write a series of test images with alpha channels.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int // O - 1 on failure, 0 on success
|
||||||
|
write_alpha_test(
|
||||||
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
int number, // I - Page number
|
||||||
|
pdfio_obj_t *font) // I - Text font
|
||||||
|
{
|
||||||
|
pdfio_dict_t *dict; // Page dictionary
|
||||||
|
pdfio_stream_t *st; // Page stream
|
||||||
|
pdfio_obj_t *images[6]; // Images using PNG predictors
|
||||||
|
char iname[32]; // Image name
|
||||||
|
int i, // Image number
|
||||||
|
x, y; // Coordinates in image
|
||||||
|
unsigned char buffer[1280 * 256], // Buffer for image
|
||||||
|
*bufptr; // Pointer into buffer
|
||||||
|
|
||||||
|
|
||||||
|
// Create the images...
|
||||||
|
for (i = 0; i < 6; i ++)
|
||||||
|
{
|
||||||
|
size_t num_colors = 0; // Number of colors
|
||||||
|
|
||||||
|
// Generate test image data...
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0 : // Grayscale
|
||||||
|
case 3 : // Grayscale + alpha
|
||||||
|
num_colors = 1;
|
||||||
|
for (y = 0, bufptr = buffer; y < 256; y ++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < 256; x ++)
|
||||||
|
{
|
||||||
|
unsigned char r = (unsigned char)y;
|
||||||
|
unsigned char g = (unsigned char)(y + x);
|
||||||
|
unsigned char b = (unsigned char)(y - x);
|
||||||
|
|
||||||
|
*bufptr++ = (unsigned char)((r * 30 + g * 59 + b * 11) / 100);
|
||||||
|
|
||||||
|
if (i > 2)
|
||||||
|
{
|
||||||
|
// Add alpha channel
|
||||||
|
*bufptr++ = (unsigned char)((x + y) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1 : // RGB
|
||||||
|
case 4 : // RGB + alpha
|
||||||
|
num_colors = 3;
|
||||||
|
for (y = 0, bufptr = buffer; y < 256; y ++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < 256; x ++)
|
||||||
|
{
|
||||||
|
*bufptr++ = (unsigned char)y;
|
||||||
|
*bufptr++ = (unsigned char)(y + x);
|
||||||
|
*bufptr++ = (unsigned char)(y - x);
|
||||||
|
|
||||||
|
if (i > 2)
|
||||||
|
{
|
||||||
|
// Add alpha channel
|
||||||
|
*bufptr++ = (unsigned char)((x + y) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2 : // CMYK
|
||||||
|
case 5 : // CMYK + alpha
|
||||||
|
num_colors = 4;
|
||||||
|
for (y = 0, bufptr = buffer; y < 256; y ++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < 256; x ++)
|
||||||
|
{
|
||||||
|
unsigned char cc = (unsigned char)y;
|
||||||
|
unsigned char mm = (unsigned char)(y + x);
|
||||||
|
unsigned char yy = (unsigned char)(y - x);
|
||||||
|
unsigned char kk = cc < mm ? cc < yy ? cc : yy : mm < yy ? mm : yy;
|
||||||
|
|
||||||
|
*bufptr++ = (unsigned char)(cc - kk);
|
||||||
|
*bufptr++ = (unsigned char)(mm - kk);
|
||||||
|
*bufptr++ = (unsigned char)(yy - kk);
|
||||||
|
*bufptr++ = (unsigned char)(kk);
|
||||||
|
|
||||||
|
if (i > 2)
|
||||||
|
{
|
||||||
|
// Add alpha channel
|
||||||
|
*bufptr++ = (unsigned char)((x + y) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the image...
|
||||||
|
printf("pdfioFileCreateImageObjFromData(num_colors=%u, alpha=%s): ", (unsigned)num_colors, i > 2 ? "true" : "false");
|
||||||
|
if ((images[i] = pdfioFileCreateImageObjFromData(pdf, buffer, 256, 256, num_colors, NULL, i > 2, false)) != NULL)
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the page dictionary, object, and stream...
|
||||||
|
fputs("pdfioDictCreate: ", stdout);
|
||||||
|
if ((dict = pdfioDictCreate(pdf)) != NULL)
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i ++)
|
||||||
|
{
|
||||||
|
printf("pdfioPageDictAddImage(%d): ", i + 1);
|
||||||
|
snprintf(iname, sizeof(iname), "IM%d", i + 1);
|
||||||
|
if (pdfioPageDictAddImage(dict, pdfioStringCreate(pdf, iname), images[i]))
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("pdfioPageDictAddFont(F1): ", stdout);
|
||||||
|
if (pdfioPageDictAddFont(dict, "F1", font))
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
printf("pdfioFileCreatePage(%d): ", number);
|
||||||
|
|
||||||
|
if ((st = pdfioFileCreatePage(pdf, dict)) != NULL)
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (write_header_footer(st, "Image Writing Test", number))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Draw images
|
||||||
|
for (i = 0; i < 6; i ++)
|
||||||
|
{
|
||||||
|
static const char *labels[] = {
|
||||||
|
"DeviceGray",
|
||||||
|
"DeviceRGB",
|
||||||
|
"DeviceCMYK",
|
||||||
|
"DeviceGray + Alpha",
|
||||||
|
"DeviceRGB + Alpha",
|
||||||
|
"DeviceCMYK + Alpha"
|
||||||
|
};
|
||||||
|
|
||||||
|
snprintf(iname, sizeof(iname), "IM%d", i + 1);
|
||||||
|
|
||||||
|
if (draw_image(st, iname, 36 + 180 * (i % 3), 306 - 216 * (i / 3), 144, 144, labels[i]))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap up...
|
||||||
|
fputs("pdfioStreamClose: ", stdout);
|
||||||
|
if (pdfioStreamClose(st))
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'write_color_patch()' - Write a color patch...
|
// 'write_color_patch()' - Write a color patch...
|
||||||
//
|
//
|
||||||
@ -1594,9 +1775,10 @@ write_image_object(
|
|||||||
//
|
//
|
||||||
|
|
||||||
static int // O - 1 on failure, 0 on success
|
static int // O - 1 on failure, 0 on success
|
||||||
write_images_test(pdfio_file_t *pdf, // I - PDF file
|
write_images_test(
|
||||||
int number, // I - Page number
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
pdfio_obj_t *font) // I - Text font
|
int number, // I - Page number
|
||||||
|
pdfio_obj_t *font) // I - Text font
|
||||||
{
|
{
|
||||||
pdfio_dict_t *dict; // Page dictionary
|
pdfio_dict_t *dict; // Page dictionary
|
||||||
pdfio_stream_t *st; // Page stream
|
pdfio_stream_t *st; // Page stream
|
||||||
|
Loading…
Reference in New Issue
Block a user