Skip to content

Commit 990342f

Browse files
committed
Add masking, color space, and variable bit depth support (Issue #90)
1 parent 7f5fc45 commit 990342f

File tree

1 file changed

+113
-78
lines changed

1 file changed

+113
-78
lines changed

pdfio-content.c

Lines changed: 113 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ typedef pdfio_obj_t *(*_pdfio_image_func_t)(pdfio_dict_t *dict, int fd);
6060
static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd);
6161
static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd);
6262
static bool create_cp1252(pdfio_file_t *pdf);
63-
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);
63+
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);
6464
#ifdef HAVE_LIBPNG
6565
static void png_error_func(png_structp pp, png_const_charp message);
6666
static void png_read_func(png_structp png_ptr, png_bytep data, size_t length);
@@ -2027,7 +2027,7 @@ pdfioFileCreateImageObjFromData(
20272027
pdfioDictSetName(dict, "ColorSpace", defcolors[num_colors]);
20282028

20292029
// Create the image object(s)...
2030-
return (create_image(dict, data, width, height, num_colors, alpha));
2030+
return (create_image(dict, data, width, height, 8, num_colors, alpha));
20312031
}
20322032

20332033

@@ -2484,6 +2484,11 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
24842484
int fd) // I - File descriptor
24852485
{
24862486
pdfio_obj_t *obj = NULL; // Object
2487+
double gamma = 2.2, // Gamma value
2488+
wx = 0.0, wy = 0.0, // White point chromacity
2489+
rx = 0.0, ry = 0.0, // Red chromacity
2490+
gx = 0.0, gy = 0.0, // Green chromacity
2491+
bx = 0.0, by = 0.0; // Blue chromacity
24872492
#ifdef HAVE_LIBPNG
24882493
png_structp pp = NULL; // PNG read pointer
24892494
png_infop info = NULL; // PNG info pointers
@@ -2493,9 +2498,14 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
24932498
color_type, // PNG color mode
24942499
width, // Width in columns
24952500
height, // Height in lines
2501+
depth, // Bit depth
24962502
num_colors = 0, // Number of colors
2497-
bpp; // Bytes per pixel
2503+
linesize; // Bytes per line
24982504
bool alpha; // Alpha transparency?
2505+
png_color *palette; // Color palette information
2506+
int num_palette; // Number of colors
2507+
int num_trans; // Number of transparent colors
2508+
png_color_16 *trans; // Transparent colors
24992509

25002510

25012511
PDFIO_DEBUG("copy_png(dict=%p, fd=%d)\n", (void *)dict, fd);
@@ -2539,51 +2549,28 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
25392549

25402550
width = png_get_image_width(pp, info);
25412551
height = png_get_image_height(pp, info);
2552+
depth = png_get_bit_depth(pp, info);
25422553
color_type = png_get_color_type(pp, info);
25432554

2544-
if (color_type & PNG_COLOR_MASK_COLOR)
2555+
if (color_type & PNG_COLOR_MASK_PALETTE)
2556+
num_colors = 1;
2557+
else if (color_type & PNG_COLOR_MASK_COLOR)
25452558
num_colors = 3;
25462559
else
25472560
num_colors = 1;
25482561

2549-
PDFIO_DEBUG("copy_png: width=%u, height=%u, color_type=%u, num_colors=%d\n", width, height, color_type, num_colors);
2562+
PDFIO_DEBUG("copy_png: width=%u, height=%u, depth=%u, color_type=%u, num_colors=%d\n", width, height, depth, color_type, num_colors);
25502563

25512564
// Set decoding options...
2552-
if (png_get_valid(pp, info, PNG_INFO_tRNS))
2553-
{
2554-
// Map transparency to alpha
2555-
png_set_tRNS_to_alpha(pp);
2556-
color_type |= PNG_COLOR_MASK_ALPHA;
2557-
}
2558-
2559-
if (png_get_bit_depth(pp, info) > 8)
2560-
{
2561-
// Strip the bottom bits of 16-bit values
2562-
png_set_strip_16(pp);
2563-
}
2564-
else if (png_get_bit_depth(pp, info) < 8)
2565-
{
2566-
// Expand 1, 2, and 4-bit values to 8 bits
2567-
if (num_colors == 1)
2568-
png_set_expand_gray_1_2_4_to_8(pp);
2569-
else
2570-
png_set_packing(pp);
2571-
}
2572-
2573-
#if 1
2574-
if (color_type & PNG_COLOR_MASK_PALETTE)
2575-
{
2576-
// Convert indexed images to RGB...
2577-
png_set_palette_to_rgb(pp);
2578-
num_colors = 3;
2579-
}
2580-
#endif // 0
2565+
alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;
2566+
linesize = (width * num_colors * depth + 7) / 8;
2567+
if (alpha)
2568+
linesize += width;
25812569

2582-
alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;
2583-
bpp = num_colors + (alpha ? 1 : 0);
2570+
PDFIO_DEBUG("copy_png: alpha=%s, linesize=%u\n", alpha ? "true" : "false", (unsigned)linesize);
25842571

25852572
// Allocate memory for the image...
2586-
if ((pixels = (unsigned char *)calloc(height, width * bpp)) == NULL)
2573+
if ((pixels = (unsigned char *)calloc(height, linesize)) == NULL)
25872574
{
25882575
_pdfioFileError(dict->pdf, "Unable to allocate memory for PNG image: %s", strerror(errno));
25892576
goto finish_png;
@@ -2596,7 +2583,7 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
25962583
}
25972584

25982585
for (i = 0; i < height; i ++)
2599-
rows[i] = pixels + i * width * bpp;
2586+
rows[i] = pixels + i * linesize;
26002587

26012588
// Read the image...
26022589
for (i = png_set_interlace_handling(pp); i > 0; i --)
@@ -2605,13 +2592,67 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
26052592
// Add image dictionary information...
26062593
pdfioDictSetNumber(dict, "Width", width);
26072594
pdfioDictSetNumber(dict, "Height", height);
2608-
pdfioDictSetNumber(dict, "BitsPerComponent", 8);
2595+
pdfioDictSetNumber(dict, "BitsPerComponent", depth);
26092596

26102597
// Grab any color space/palette information...
2611-
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromStandard(dict->pdf, num_colors, PDFIO_CS_SRGB));
2598+
if (png_get_PLTE(pp, info, &palette, &num_palette))
2599+
{
2600+
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPalette(dict->pdf, num_palette, (unsigned char *)palette));
2601+
}
2602+
else if (png_get_cHRM(pp, info, &wx, &wy, &rx, &ry, &gx, &gy, &bx, &by) && png_get_gAMA(pp, info, &gamma))
2603+
{
2604+
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromPrimaries(dict->pdf, num_colors, gamma, wx, wy, rx, ry, gx, gy, bx, by));
2605+
}
2606+
else
2607+
{
2608+
// Default to sRGB...
2609+
pdfioDictSetArray(dict, "ColorSpace", pdfioArrayCreateColorFromStandard(dict->pdf, num_colors, PDFIO_CS_SRGB));
2610+
}
2611+
2612+
if (png_get_tRNS(pp, info, /*trans_alpha*/NULL, &num_trans, &trans))
2613+
{
2614+
int m; // Looping var
2615+
pdfio_array_t *mask; // Mask array
2616+
2617+
mask = pdfioArrayCreate(dict->pdf);
2618+
2619+
if (color_type & PNG_COLOR_MASK_PALETTE)
2620+
{
2621+
// List color indices that are transparent...
2622+
for (m = 0; m < num_trans; m ++)
2623+
{
2624+
pdfioArrayAppendNumber(mask, trans[m].index);
2625+
pdfioArrayAppendNumber(mask, trans[m].index);
2626+
}
2627+
}
2628+
else if (num_colors == 1)
2629+
{
2630+
// List grayscale values that are transparent...
2631+
for (m = 0; m < num_trans; m ++)
2632+
{
2633+
pdfioArrayAppendNumber(mask, trans[m].gray >> (16 - depth));
2634+
pdfioArrayAppendNumber(mask, trans[m].gray >> (16 - depth));
2635+
}
2636+
}
2637+
else
2638+
{
2639+
// List RGB color values that are transparent...
2640+
for (m = 0; m < num_trans; m ++)
2641+
{
2642+
pdfioArrayAppendNumber(mask, trans[m].red >> (16 - depth));
2643+
pdfioArrayAppendNumber(mask, trans[m].green >> (16 - depth));
2644+
pdfioArrayAppendNumber(mask, trans[m].blue >> (16 - depth));
2645+
pdfioArrayAppendNumber(mask, trans[m].red >> (16 - depth));
2646+
pdfioArrayAppendNumber(mask, trans[m].green >> (16 - depth));
2647+
pdfioArrayAppendNumber(mask, trans[m].blue >> (16 - depth));
2648+
}
2649+
}
2650+
2651+
pdfioDictSetArray(dict, "Mask", mask);
2652+
}
26122653

26132654
// Create the image object...
2614-
obj = create_image(dict, pixels, width, height, num_colors, alpha);
2655+
obj = create_image(dict, pixels, width, height, depth, num_colors, alpha);
26152656

26162657
finish_png:
26172658

@@ -2648,11 +2689,6 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
26482689
unsigned char bit_depth = 0, // Bit depth
26492690
color_type = 0, // Color type
26502691
interlace = 0; // Interlace type
2651-
double gamma = 2.2, // Gamma value
2652-
wx = 0.0, wy = 0.0, // White point chromacity
2653-
rx = 0.0, ry = 0.0, // Red chromacity
2654-
gx = 0.0, gy = 0.0, // Green chromacity
2655-
bx = 0.0, by = 0.0; // Blue chromacity
26562692
pdfio_array_t *mask = NULL; // Color masking array
26572693

26582694

@@ -2803,7 +2839,7 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
28032839
return (NULL);
28042840
}
28052841

2806-
num_colors = (color_type == _PDFIO_PNG_TYPE_RGB || color_type == _PDFIO_PNG_TYPE_RGBA) ? 3 : 1;
2842+
num_colors = color_type == _PDFIO_PNG_TYPE_RGB ? 3 : 1;
28072843

28082844
pdfioDictSetNumber(dict, "Width", width);
28092845
pdfioDictSetNumber(dict, "Height", height);
@@ -3304,6 +3340,7 @@ create_image(
33043340
const unsigned char *data, // I - Image data
33053341
size_t width, // I - Width in columns
33063342
size_t height, // I - Height in lines
3343+
size_t depth, // I - Bit depth
33073344
size_t num_colors, // I - Number of colors
33083345
bool alpha) // I - `true` if there is transparency
33093346
{
@@ -3316,16 +3353,17 @@ create_image(
33163353
// Mask image object, if any
33173354
pdfio_stream_t *st; // Image stream
33183355
size_t x, y, // X and Y position in image
3319-
bpp, // Bytes per pixel
3356+
bpc = depth / 8,// Bytes per component
3357+
bpp = num_colors * bpc,
3358+
// Bytes per pixel (less alpha)
33203359
linelen; // Line length
33213360
const unsigned char *dataptr; // Pointer into image data
33223361
unsigned char *line = NULL, // Current line
33233362
*lineptr; // Pointer into line
33243363

33253364

33263365
// Allocate memory for one line of data...
3327-
bpp = alpha ? num_colors + 1 : num_colors;
3328-
linelen = num_colors * width;
3366+
linelen = (width * num_colors * depth + 7) / 8;
33293367

33303368
if ((line = malloc(linelen)) == NULL)
33313369
return (NULL);
@@ -3353,7 +3391,7 @@ create_image(
33533391
return (NULL);
33543392
}
33553393

3356-
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
3394+
pdfioDictSetNumber(decode, "BitsPerComponent", depth);
33573395
pdfioDictSetNumber(decode, "Colors", 1);
33583396
pdfioDictSetNumber(decode, "Columns", width);
33593397
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
@@ -3373,12 +3411,23 @@ create_image(
33733411
return (NULL);
33743412
}
33753413

3376-
for (y = height, dataptr = data + num_colors; y > 0; y --)
3414+
for (y = height, dataptr = data + bpp; y > 0; y --)
33773415
{
3378-
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3379-
*lineptr++ = *dataptr;
3416+
if (bpc == 1)
3417+
{
3418+
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3419+
*lineptr++ = *dataptr++;
3420+
}
3421+
else
3422+
{
3423+
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3424+
{
3425+
*lineptr++ = *dataptr++;
3426+
*lineptr++ = *dataptr++;
3427+
}
3428+
}
33803429

3381-
pdfioStreamWrite(st, line, width);
3430+
pdfioStreamWrite(st, line, width * bpc);
33823431
}
33833432

33843433
pdfioStreamClose(st);
@@ -3394,7 +3443,7 @@ create_image(
33943443
return (NULL);
33953444
}
33963445

3397-
pdfioDictSetNumber(decode, "BitsPerComponent", 8);
3446+
pdfioDictSetNumber(decode, "BitsPerComponent", depth);
33983447
pdfioDictSetNumber(decode, "Colors", num_colors);
33993448
pdfioDictSetNumber(decode, "Columns", width);
34003449
pdfioDictSetNumber(decode, "Predictor", _PDFIO_PREDICTOR_PNG_AUTO);
@@ -3418,29 +3467,15 @@ create_image(
34183467
{
34193468
if (alpha)
34203469
{
3421-
switch (num_colors)
3470+
if (bpp == 1)
34223471
{
3423-
case 1 :
3424-
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3425-
*lineptr++ = *dataptr;
3426-
break;
3427-
case 3 :
3428-
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3429-
{
3430-
*lineptr++ = dataptr[0];
3431-
*lineptr++ = dataptr[1];
3432-
*lineptr++ = dataptr[2];
3433-
}
3434-
break;
3435-
case 4 :
3436-
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp)
3437-
{
3438-
*lineptr++ = dataptr[0];
3439-
*lineptr++ = dataptr[1];
3440-
*lineptr++ = dataptr[2];
3441-
*lineptr++ = dataptr[3];
3442-
}
3443-
break;
3472+
for (x = width, lineptr = line; x > 0; x --, dataptr += bpc)
3473+
*lineptr++ = *dataptr++;
3474+
}
3475+
else
3476+
{
3477+
for (x = width, lineptr = line; x > 0; x --, dataptr += bpp + bpc, lineptr += bpp)
3478+
memcpy(lineptr, dataptr, bpp);
34443479
}
34453480

34463481
pdfioStreamWrite(st, line, linelen);

0 commit comments

Comments
 (0)