mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-02-26 13:52:49 +01:00
Add masking, color space, and variable bit depth support (Issue #90)
This commit is contained in:
parent
7f5fc456bc
commit
990342f2a5
191
pdfio-content.c
191
pdfio-content.c
@ -60,7 +60,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_dict_t *dict, const unsigned char *data, size_t width, size_t height, size_t num_colors, bool alpha);
|
static pdfio_obj_t *create_image(pdfio_dict_t *dict, const unsigned char *data, size_t width, size_t height, size_t depth, size_t num_colors, bool alpha);
|
||||||
#ifdef HAVE_LIBPNG
|
#ifdef HAVE_LIBPNG
|
||||||
static void png_error_func(png_structp pp, png_const_charp message);
|
static void png_error_func(png_structp pp, png_const_charp message);
|
||||||
static void png_read_func(png_structp png_ptr, png_bytep data, size_t length);
|
static void png_read_func(png_structp png_ptr, png_bytep data, size_t length);
|
||||||
@ -2027,7 +2027,7 @@ pdfioFileCreateImageObjFromData(
|
|||||||
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
|
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
|
||||||
|
|
||||||
// Create the image object(s)...
|
// Create the image object(s)...
|
||||||
return (create_image(dict, data, width, height, num_colors, alpha));
|
return (create_image(dict, data, width, height, 8, num_colors, alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2484,6 +2484,11 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
int fd) // I - File descriptor
|
int fd) // I - File descriptor
|
||||||
{
|
{
|
||||||
pdfio_obj_t *obj = NULL; // Object
|
pdfio_obj_t *obj = NULL; // Object
|
||||||
|
double gamma = 2.2, // Gamma value
|
||||||
|
wx = 0.0, wy = 0.0, // White point chromacity
|
||||||
|
rx = 0.0, ry = 0.0, // Red chromacity
|
||||||
|
gx = 0.0, gy = 0.0, // Green chromacity
|
||||||
|
bx = 0.0, by = 0.0; // Blue chromacity
|
||||||
#ifdef HAVE_LIBPNG
|
#ifdef HAVE_LIBPNG
|
||||||
png_structp pp = NULL; // PNG read pointer
|
png_structp pp = NULL; // PNG read pointer
|
||||||
png_infop info = NULL; // PNG info pointers
|
png_infop info = NULL; // PNG info pointers
|
||||||
@ -2493,9 +2498,14 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
color_type, // PNG color mode
|
color_type, // PNG color mode
|
||||||
width, // Width in columns
|
width, // Width in columns
|
||||||
height, // Height in lines
|
height, // Height in lines
|
||||||
|
depth, // Bit depth
|
||||||
num_colors = 0, // Number of colors
|
num_colors = 0, // Number of colors
|
||||||
bpp; // Bytes per pixel
|
linesize; // Bytes per line
|
||||||
bool alpha; // Alpha transparency?
|
bool alpha; // Alpha transparency?
|
||||||
|
png_color *palette; // Color palette information
|
||||||
|
int num_palette; // Number of colors
|
||||||
|
int num_trans; // Number of transparent colors
|
||||||
|
png_color_16 *trans; // Transparent colors
|
||||||
|
|
||||||
|
|
||||||
PDFIO_DEBUG("copy_png(dict=%p, fd=%d)\n", (void *)dict, fd);
|
PDFIO_DEBUG("copy_png(dict=%p, fd=%d)\n", (void *)dict, fd);
|
||||||
@ -2539,51 +2549,28 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
|
|
||||||
width = png_get_image_width(pp, info);
|
width = png_get_image_width(pp, info);
|
||||||
height = png_get_image_height(pp, info);
|
height = png_get_image_height(pp, info);
|
||||||
|
depth = png_get_bit_depth(pp, info);
|
||||||
color_type = png_get_color_type(pp, info);
|
color_type = png_get_color_type(pp, info);
|
||||||
|
|
||||||
if (color_type & PNG_COLOR_MASK_COLOR)
|
if (color_type & PNG_COLOR_MASK_PALETTE)
|
||||||
|
num_colors = 1;
|
||||||
|
else if (color_type & PNG_COLOR_MASK_COLOR)
|
||||||
num_colors = 3;
|
num_colors = 3;
|
||||||
else
|
else
|
||||||
num_colors = 1;
|
num_colors = 1;
|
||||||
|
|
||||||
PDFIO_DEBUG("copy_png: width=%u, height=%u, color_type=%u, num_colors=%d\n", width, height, color_type, num_colors);
|
PDFIO_DEBUG("copy_png: width=%u, height=%u, depth=%u, color_type=%u, num_colors=%d\n", width, height, depth, color_type, num_colors);
|
||||||
|
|
||||||
// Set decoding options...
|
// Set decoding options...
|
||||||
if (png_get_valid(pp, info, PNG_INFO_tRNS))
|
alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;
|
||||||
{
|
linesize = (width * num_colors * depth + 7) / 8;
|
||||||
// Map transparency to alpha
|
if (alpha)
|
||||||
png_set_tRNS_to_alpha(pp);
|
linesize += width;
|
||||||
color_type |= PNG_COLOR_MASK_ALPHA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (png_get_bit_depth(pp, info) > 8)
|
PDFIO_DEBUG("copy_png: alpha=%s, linesize=%u\n", alpha ? "true" : "false", (unsigned)linesize);
|
||||||
{
|
|
||||||
// Strip the bottom bits of 16-bit values
|
|
||||||
png_set_strip_16(pp);
|
|
||||||
}
|
|
||||||
else if (png_get_bit_depth(pp, info) < 8)
|
|
||||||
{
|
|
||||||
// Expand 1, 2, and 4-bit values to 8 bits
|
|
||||||
if (num_colors == 1)
|
|
||||||
png_set_expand_gray_1_2_4_to_8(pp);
|
|
||||||
else
|
|
||||||
png_set_packing(pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
if (color_type & PNG_COLOR_MASK_PALETTE)
|
|
||||||
{
|
|
||||||
// Convert indexed images to RGB...
|
|
||||||
png_set_palette_to_rgb(pp);
|
|
||||||
num_colors = 3;
|
|
||||||
}
|
|
||||||
#endif // 0
|
|
||||||
|
|
||||||
alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;
|
|
||||||
bpp = num_colors + (alpha ? 1 : 0);
|
|
||||||
|
|
||||||
// Allocate memory for the image...
|
// Allocate memory for the image...
|
||||||
if ((pixels = (unsigned char *)calloc(height, width * bpp)) == NULL)
|
if ((pixels = (unsigned char *)calloc(height, linesize)) == NULL)
|
||||||
{
|
{
|
||||||
_pdfioFileError(dict->pdf, "Unable to allocate memory for PNG image: %s", strerror(errno));
|
_pdfioFileError(dict->pdf, "Unable to allocate memory for PNG image: %s", strerror(errno));
|
||||||
goto finish_png;
|
goto finish_png;
|
||||||
@ -2596,7 +2583,7 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < height; i ++)
|
for (i = 0; i < height; i ++)
|
||||||
rows[i] = pixels + i * width * bpp;
|
rows[i] = pixels + i * linesize;
|
||||||
|
|
||||||
// Read the image...
|
// Read the image...
|
||||||
for (i = png_set_interlace_handling(pp); i > 0; i --)
|
for (i = png_set_interlace_handling(pp); i > 0; i --)
|
||||||
@ -2605,13 +2592,67 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
// Add image dictionary information...
|
// Add image dictionary information...
|
||||||
pdfioDictSetNumber(dict, "Width", width);
|
pdfioDictSetNumber(dict, "Width", width);
|
||||||
pdfioDictSetNumber(dict, "Height", height);
|
pdfioDictSetNumber(dict, "Height", height);
|
||||||
pdfioDictSetNumber(dict, "BitsPerComponent", 8);
|
pdfioDictSetNumber(dict, "BitsPerComponent", depth);
|
||||||
|
|
||||||
// Grab any color space/palette information...
|
// Grab any color space/palette information...
|
||||||
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromStandard(dict->pdf, num_colors, PDFIO_CS_SRGB));
|
if (png_get_PLTE(pp, info, &palette, &num_palette))
|
||||||
|
{
|
||||||
|
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPalette(dict->pdf, num_palette, (unsigned char *)palette));
|
||||||
|
}
|
||||||
|
else if (png_get_cHRM(pp, info, &wx, &wy, &rx, &ry, &gx, &gy, &bx, &by) && png_get_gAMA(pp, info, &gamma))
|
||||||
|
{
|
||||||
|
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPrimaries(dict->pdf, num_colors, gamma, wx, wy, rx, ry, gx, gy, bx, by));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default to sRGB...
|
||||||
|
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromStandard(dict->pdf, num_colors, PDFIO_CS_SRGB));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (png_get_tRNS(pp, info, /*trans_alpha*/NULL, &num_trans, &trans))
|
||||||
|
{
|
||||||
|
int m; // Looping var
|
||||||
|
pdfio_array_t *mask; // Mask array
|
||||||
|
|
||||||
|
mask = pdfioArrayCreate(dict->pdf);
|
||||||
|
|
||||||
|
if (color_type & PNG_COLOR_MASK_PALETTE)
|
||||||
|
{
|
||||||
|
// List color indices that are transparent...
|
||||||
|
for (m = 0; m < num_trans; m ++)
|
||||||
|
{
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].index);
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (num_colors == 1)
|
||||||
|
{
|
||||||
|
// List grayscale values that are transparent...
|
||||||
|
for (m = 0; m < num_trans; m ++)
|
||||||
|
{
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].gray >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].gray >> (16 - depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// List RGB color values that are transparent...
|
||||||
|
for (m = 0; m < num_trans; m ++)
|
||||||
|
{
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].red >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].green >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].blue >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].red >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].green >> (16 - depth));
|
||||||
|
pdfioArrayAppendNumber(mask, trans[m].blue >> (16 - depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioDictSetArray(dict, "Mask", mask);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the image object...
|
// Create the image object...
|
||||||
obj = create_image(dict, pixels, width, height, num_colors, alpha);
|
obj = create_image(dict, pixels, width, height, depth, num_colors, alpha);
|
||||||
|
|
||||||
finish_png:
|
finish_png:
|
||||||
|
|
||||||
@ -2648,11 +2689,6 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
unsigned char bit_depth = 0, // Bit depth
|
unsigned char bit_depth = 0, // Bit depth
|
||||||
color_type = 0, // Color type
|
color_type = 0, // Color type
|
||||||
interlace = 0; // Interlace type
|
interlace = 0; // Interlace type
|
||||||
double gamma = 2.2, // Gamma value
|
|
||||||
wx = 0.0, wy = 0.0, // White point chromacity
|
|
||||||
rx = 0.0, ry = 0.0, // Red chromacity
|
|
||||||
gx = 0.0, gy = 0.0, // Green chromacity
|
|
||||||
bx = 0.0, by = 0.0; // Blue chromacity
|
|
||||||
pdfio_array_t *mask = NULL; // Color masking array
|
pdfio_array_t *mask = NULL; // Color masking array
|
||||||
|
|
||||||
|
|
||||||
@ -2803,7 +2839,7 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
num_colors = (color_type == _PDFIO_PNG_TYPE_RGB || color_type == _PDFIO_PNG_TYPE_RGBA) ? 3 : 1;
|
num_colors = color_type == _PDFIO_PNG_TYPE_RGB ? 3 : 1;
|
||||||
|
|
||||||
pdfioDictSetNumber(dict, "Width", width);
|
pdfioDictSetNumber(dict, "Width", width);
|
||||||
pdfioDictSetNumber(dict, "Height", height);
|
pdfioDictSetNumber(dict, "Height", height);
|
||||||
@ -3304,6 +3340,7 @@ create_image(
|
|||||||
const unsigned char *data, // I - Image data
|
const unsigned char *data, // I - Image data
|
||||||
size_t width, // I - Width in columns
|
size_t width, // I - Width in columns
|
||||||
size_t height, // I - Height in lines
|
size_t height, // I - Height in lines
|
||||||
|
size_t depth, // I - Bit depth
|
||||||
size_t num_colors, // I - Number of colors
|
size_t num_colors, // I - Number of colors
|
||||||
bool alpha) // I - `true` if there is transparency
|
bool alpha) // I - `true` if there is transparency
|
||||||
{
|
{
|
||||||
@ -3316,7 +3353,9 @@ create_image(
|
|||||||
// 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
|
bpc = depth / 8,// Bytes per component
|
||||||
|
bpp = num_colors * bpc,
|
||||||
|
// Bytes per pixel (less alpha)
|
||||||
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
|
||||||
@ -3324,8 +3363,7 @@ create_image(
|
|||||||
|
|
||||||
|
|
||||||
// Allocate memory for one line of data...
|
// Allocate memory for one line of data...
|
||||||
bpp = alpha ? num_colors + 1 : num_colors;
|
linelen = (width * num_colors * depth + 7) / 8;
|
||||||
linelen = num_colors * width;
|
|
||||||
|
|
||||||
if ((line = malloc(linelen)) == NULL)
|
if ((line = malloc(linelen)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -3353,7 +3391,7 @@ create_image(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
|
pdfioDictSetNumber(decode, "BitsPerComponent", depth);
|
||||||
pdfioDictSetNumber(decode, "Colors", 1);
|
pdfioDictSetNumber(decode, "Colors", 1);
|
||||||
pdfioDictSetNumber(decode, "Columns", width);
|
pdfioDictSetNumber(decode, "Columns", width);
|
||||||
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
|
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
|
||||||
@ -3373,12 +3411,23 @@ create_image(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = height, dataptr = data + num_colors; y > 0; y --)
|
for (y = height, dataptr = data + bpp; y > 0; y --)
|
||||||
{
|
{
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
if (bpc == 1)
|
||||||
*lineptr++ = *dataptr;
|
{
|
||||||
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
|
*lineptr++ = *dataptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
||||||
|
{
|
||||||
|
*lineptr++ = *dataptr++;
|
||||||
|
*lineptr++ = *dataptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pdfioStreamWrite(st, line, width);
|
pdfioStreamWrite(st, line, width * bpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
@ -3394,7 +3443,7 @@ create_image(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
|
pdfioDictSetNumber(decode, "BitsPerComponent", depth);
|
||||||
pdfioDictSetNumber(decode, "Colors", num_colors);
|
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);
|
||||||
@ -3418,29 +3467,15 @@ create_image(
|
|||||||
{
|
{
|
||||||
if (alpha)
|
if (alpha)
|
||||||
{
|
{
|
||||||
switch (num_colors)
|
if (bpp == 1)
|
||||||
{
|
{
|
||||||
case 1 :
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpc)
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
*lineptr++ = *dataptr++;
|
||||||
*lineptr++ = *dataptr;
|
}
|
||||||
break;
|
else
|
||||||
case 3 :
|
{
|
||||||
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
|
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp + bpc, lineptr += bpp)
|
||||||
{
|
memcpy(lineptr, 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);
|
pdfioStreamWrite(st, line, linelen);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user