mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-26 13:28: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
|
||||
size_t width, // I - Width 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
|
||||
bool alpha, // I - `true` if data contains an alpha channel
|
||||
bool interpolate) // I - Interpolate image data?
|
||||
{
|
||||
pdfio_dict_t *dict, // Image dictionary
|
||||
@ -1652,24 +1653,34 @@ pdfioFileCreateImageObjFromData(
|
||||
// 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
|
||||
{
|
||||
NULL,
|
||||
"DeviceGray",
|
||||
NULL,
|
||||
"DeviceRGB",
|
||||
"DeviceCMYK"
|
||||
};
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
return (NULL);
|
||||
|
||||
// Generate a mask image, as needed...
|
||||
if (!(num_colors & 1))
|
||||
if (alpha)
|
||||
{
|
||||
// Create the image mask dictionary...
|
||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||
@ -1711,9 +1722,9 @@ pdfioFileCreateImageObjFromData(
|
||||
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;
|
||||
|
||||
pdfioStreamWrite(st, line, width);
|
||||
@ -1739,7 +1750,7 @@ pdfioFileCreateImageObjFromData(
|
||||
if (color_data)
|
||||
pdfioDictSetArray(dict, "ColorSpace", color_data);
|
||||
else
|
||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromMatrix(pdf, num_colors < 3 ? 1 : 3, pdfioSRGBGamma, pdfioSRGBMatrix, pdfioSRGBWhitePoint));
|
||||
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
|
||||
|
||||
if (mask_obj)
|
||||
pdfioDictSetObj(dict, "SMask", mask_obj);
|
||||
@ -1751,7 +1762,7 @@ pdfioFileCreateImageObjFromData(
|
||||
}
|
||||
|
||||
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
|
||||
pdfioDictSetNumber(decode, "Colors", num_colors < 3 ? 1 : 3);
|
||||
pdfioDictSetNumber(decode, "Colors", num_colors);
|
||||
pdfioDictSetNumber(decode, "Columns", width);
|
||||
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
|
||||
pdfioDictSetDict(dict, "DecodeParms", decode);
|
||||
@ -1771,30 +1782,39 @@ pdfioFileCreateImageObjFromData(
|
||||
|
||||
for (y = height, dataptr = data; y > 0; y --)
|
||||
{
|
||||
switch (num_colors)
|
||||
if (alpha)
|
||||
{
|
||||
case 1 :
|
||||
pdfioStreamWrite(st, dataptr, linelen);
|
||||
dataptr += linelen;
|
||||
break;
|
||||
case 2 :
|
||||
for (x = width, lineptr = line; x > 0; x --, dataptr += num_colors)
|
||||
*lineptr++ = *dataptr;
|
||||
pdfioStreamWrite(st, line, linelen);
|
||||
break;
|
||||
case 3 :
|
||||
pdfioStreamWrite(st, dataptr, linelen);
|
||||
dataptr += linelen;
|
||||
break;
|
||||
case 4 :
|
||||
for (x = width, lineptr = line; x > 0; x --, dataptr += num_colors)
|
||||
{
|
||||
*lineptr++ = dataptr[0];
|
||||
*lineptr++ = dataptr[1];
|
||||
*lineptr++ = dataptr[2];
|
||||
}
|
||||
pdfioStreamWrite(st, line, linelen);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 *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 *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;
|
||||
|
||||
// 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_peek_cb(const char **s, char *buffer, size_t bytes);
|
||||
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_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);
|
||||
@ -417,15 +418,19 @@ do_unit_tests(void)
|
||||
if (write_images_test(outpdf, 7, helvetica))
|
||||
return (1);
|
||||
|
||||
// Test TrueType fonts...
|
||||
if (write_font_test(outpdf, 8, helvetica, false))
|
||||
// Write a page width alpha (soft masks)...
|
||||
if (write_alpha_test(outpdf, 8, helvetica))
|
||||
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);
|
||||
|
||||
// Print this text file...
|
||||
if (write_text_test(outpdf, 10, helvetica, "README.md"))
|
||||
if (write_text_test(outpdf, 11, helvetica, "README.md"))
|
||||
return (1);
|
||||
|
||||
// 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...
|
||||
//
|
||||
@ -1594,9 +1775,10 @@ write_image_object(
|
||||
//
|
||||
|
||||
static int // O - 1 on failure, 0 on success
|
||||
write_images_test(pdfio_file_t *pdf, // I - PDF file
|
||||
int number, // I - Page number
|
||||
pdfio_obj_t *font) // I - Text font
|
||||
write_images_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
|
||||
|
Loading…
Reference in New Issue
Block a user