2
Copyright (c) 1996-2004 Han The Thanh, <thanh@pdftex.org>
4
This file is part of pdfTeX.
6
pdfTeX is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
pdfTeX is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with pdfTeX; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
$Id: writepng.c,v 1.2 2006/01/06 22:35:43 hahe Exp hahe $
27
static const char perforce_id[] =
28
"$Id: writepng.c,v 1.2 2006/01/06 22:35:43 hahe Exp hahe $";
30
void read_png_info (integer img)
33
FILE *png_file = xfopen (img_name (img), FOPEN_RBIN_MODE);
35
if ((png_ptr (img) = png_create_read_struct (PNG_LIBPNG_VER_STRING,
36
NULL, NULL, NULL)) == NULL)
37
pdftex_fail ("libpng: png_create_read_struct() failed");
38
if ((png_info (img) = png_create_info_struct (png_ptr (img))) == NULL)
39
pdftex_fail ("libpng: png_create_info_struct() failed");
40
if (setjmp (png_ptr (img)->jmpbuf))
41
pdftex_fail ("libpng: internal error");
42
png_init_io (png_ptr (img), png_file);
43
png_read_info (png_ptr (img), png_info (img));
44
/* simple transparency support */
45
if (png_get_valid (png_ptr (img), png_info (img), PNG_INFO_tRNS)) {
46
png_set_tRNS_to_alpha (png_ptr (img));
48
/* alpha channel support */
49
if (fixed_pdf_minor_version < 4
50
&& png_ptr (img)->color_type | PNG_COLOR_MASK_ALPHA)
51
png_set_strip_alpha (png_ptr (img));
52
/* 16bit depth support */
53
if (fixed_pdf_minor_version < 5)
54
fixed_image_hicolor = 0;
55
if (png_info (img)->bit_depth == 16 && !fixed_image_hicolor)
56
png_set_strip_16 (png_ptr (img));
58
if (fixed_image_apply_gamma) {
59
if (png_get_gAMA (png_ptr (img), png_info (img), &gamma))
60
png_set_gamma (png_ptr (img), (fixed_gamma / 1000.0), gamma);
62
png_set_gamma (png_ptr (img), (fixed_gamma / 1000.0),
63
(1000.0 / fixed_image_gamma));
66
png_read_update_info (png_ptr (img), png_info (img));
67
/* resolution support */
68
img_width (img) = png_info (img)->width;
69
img_height (img) = png_info (img)->height;
70
if (png_info (img)->valid & PNG_INFO_pHYs) {
73
png_get_x_pixels_per_meter (png_ptr (img), png_info (img)));
76
png_get_y_pixels_per_meter (png_ptr (img), png_info (img)));
78
switch (png_info (img)->color_type) {
79
case PNG_COLOR_TYPE_PALETTE:
80
img_color (img) = IMAGE_COLOR_C | IMAGE_COLOR_I;
82
case PNG_COLOR_TYPE_GRAY:
83
case PNG_COLOR_TYPE_GRAY_ALPHA:
84
img_color (img) = IMAGE_COLOR_B;
86
case PNG_COLOR_TYPE_RGB:
87
case PNG_COLOR_TYPE_RGB_ALPHA:
88
img_color (img) = IMAGE_COLOR_C;
91
pdftex_fail ("unsupported type of color_type <%i>",
92
png_info (img)->color_type);
97
#define write_gray_pixel_16(r) \
98
if (j % 4 == 0||j % 4 == 1) pdf_buf[pdf_ptr++] = *r++; \
99
else smask[smask_ptr++] = *r++
101
#define write_gray_pixel_8(r) \
102
if (j % 2 == 0) pdf_buf[pdf_ptr++] = *r++; \
103
else smask[smask_ptr++] = *r++
106
#define write_rgb_pixel_16(r) \
107
if (!(j % 8 == 6||j % 8 == 7)) pdf_buf[pdf_ptr++] = *r++; \
108
else smask[smask_ptr++] = *r++
110
#define write_rgb_pixel_8(r) \
111
if (j % 4 != 3) pdf_buf[pdf_ptr++] = *r++; \
112
else smask[smask_ptr++] = *r++
114
#define write_simple_pixel(r) pdf_buf[pdf_ptr++] = *r++
117
#define write_noninterlaced(outmac) \
118
for (i = 0; (unsigned) i < (int)png_info(img)->height; i++) { \
119
png_read_row(png_ptr(img), row, NULL); \
121
k = png_info(img)->rowbytes; \
123
l = (k > pdf_buf_size)? pdf_buf_size : k; \
125
for (j = 0; j < l; j++) { \
132
#define write_interlaced(outmac) \
133
for (i = 0; (unsigned) i < (int)png_info(img)->height; i++) { \
135
k = png_info(img)->rowbytes; \
137
l = (k > pdf_buf_size)? pdf_buf_size : k; \
139
for (j = 0; j < l; j++) { \
148
void write_png_palette (integer img)
151
png_bytep row, r, *rows;
152
integer palette_objnum = 0;
153
pdf_create_obj (0, 0);
154
palette_objnum = obj_ptr;
155
if (img_colorspace_ref (img) != 0) {
156
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
158
pdf_printf ("[/Indexed /DeviceRGB %i %i 0 R]\n",
159
(int) (png_info (img)->num_palette - 1),
160
(int) palette_objnum);
163
if (png_info (img)->interlace_type == PNG_INTERLACE_NONE) {
164
row = xtalloc (png_info (img)->rowbytes, png_byte);
165
write_noninterlaced (write_simple_pixel (r));
168
if (png_info (img)->height * png_info (img)->rowbytes >= 10240000L)
170
("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)");
171
rows = xtalloc (png_info (img)->height, png_bytep);
172
for (i = 0; (unsigned) i < png_info (img)->height; i++)
173
rows[i] = xtalloc (png_info (img)->rowbytes, png_byte);
174
png_read_image (png_ptr (img), rows);
175
write_interlaced (write_simple_pixel (row));
179
if (palette_objnum > 0) {
180
pdf_begin_dict (palette_objnum, 0);
182
for (i = 0; (unsigned) i < png_info (img)->num_palette; i++) {
184
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].red;
185
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].green;
186
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].blue;
192
void write_png_gray (integer img)
195
png_bytep row, r, *rows;
196
if (img_colorspace_ref (img) != 0) {
197
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
199
pdf_puts ("/DeviceGray\n");
202
if (png_info (img)->interlace_type == PNG_INTERLACE_NONE) {
203
row = xtalloc (png_info (img)->rowbytes, png_byte);
204
write_noninterlaced (write_simple_pixel (r));
207
if (png_info (img)->height * png_info (img)->rowbytes >= 10240000L)
209
("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)");
210
rows = xtalloc (png_info (img)->height, png_bytep);
211
for (i = 0; (unsigned) i < png_info (img)->height; i++)
212
rows[i] = xtalloc (png_info (img)->rowbytes, png_byte);
213
png_read_image (png_ptr (img), rows);
214
write_interlaced (write_simple_pixel (row));
222
void write_png_gray_alpha (integer img)
225
png_bytep row, r, *rows;
226
integer smask_objnum = 0;
228
integer smask_ptr = 0;
229
integer smask_size = 0;
231
if (img_colorspace_ref (img) != 0) {
232
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
234
pdf_puts ("/DeviceGray\n");
236
pdf_create_obj (0, 0);
237
smask_objnum = obj_ptr;
238
pdf_printf ("/SMask %i 0 R\n", (int) smask_objnum);
239
smask_size = (png_info (img)->rowbytes / 2) * png_info (img)->height;
240
smask = xtalloc (smask_size, png_byte);
242
if (png_info (img)->interlace_type == PNG_INTERLACE_NONE) {
243
row = xtalloc (png_info (img)->rowbytes, png_byte);
244
if ((png_info (img)->bit_depth == 16) && fixed_image_hicolor) {
245
write_noninterlaced (write_gray_pixel_16 (r));
247
write_noninterlaced (write_gray_pixel_8 (r));
251
if (png_info (img)->height * png_info (img)->rowbytes >= 10240000L)
253
("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)");
254
rows = xtalloc (png_info (img)->height, png_bytep);
255
for (i = 0; (unsigned) i < png_info (img)->height; i++)
256
rows[i] = xtalloc (png_info (img)->rowbytes, png_byte);
257
png_read_image (png_ptr (img), rows);
258
if ((png_info (img)->bit_depth == 16) && fixed_image_hicolor) {
259
write_interlaced (write_gray_pixel_16 (row));
261
write_interlaced (write_gray_pixel_8 (row));
267
/* now write the Smask object */
268
if (smask_objnum > 0) {
269
bitdepth = (int) png_info (img)->bit_depth;
270
pdf_begin_dict (smask_objnum, 0);
271
pdf_puts ("/Type /XObject\n/Subtype /Image\n");
272
pdf_printf ("/Width %i\n/Height %i\n/BitsPerComponent %i\n",
273
(int) png_info (img)->width,
274
(int) png_info (img)->height,
275
(bitdepth == 16 ? 8 : bitdepth));
276
pdf_puts ("/ColorSpace /DeviceGray\n");
278
for (i = 0; i < smask_size; i++) {
281
pdf_buf[pdf_ptr++] = smask[i];
290
void write_png_rgb (integer img)
293
png_bytep row, r, *rows;
294
if (img_colorspace_ref (img) != 0) {
295
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
297
pdf_puts ("/DeviceRGB\n");
300
if (png_info (img)->interlace_type == PNG_INTERLACE_NONE) {
301
row = xtalloc (png_info (img)->rowbytes, png_byte);
302
write_noninterlaced (write_simple_pixel (r));
305
if (png_info (img)->height * png_info (img)->rowbytes >= 10240000L)
307
("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)");
308
rows = xtalloc (png_info (img)->height, png_bytep);
309
for (i = 0; (unsigned) i < png_info (img)->height; i++)
310
rows[i] = xtalloc (png_info (img)->rowbytes, png_byte);
311
png_read_image (png_ptr (img), rows);
312
write_interlaced (write_simple_pixel (row));
318
void write_png_rgb_alpha (integer img)
321
png_bytep row, r, *rows;
322
integer smask_objnum = 0;
324
integer smask_ptr = 0;
325
integer smask_size = 0;
327
if (img_colorspace_ref (img) != 0) {
328
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
330
pdf_puts ("/DeviceRGB\n");
332
pdf_create_obj (0, 0);
333
smask_objnum = obj_ptr;
334
pdf_printf ("/SMask %i 0 R\n", (int) smask_objnum);
335
smask_size = (png_info (img)->rowbytes / 2) * png_info (img)->height;
336
smask = xtalloc (smask_size, png_byte);
338
if (png_info (img)->interlace_type == PNG_INTERLACE_NONE) {
339
row = xtalloc (png_info (img)->rowbytes, png_byte);
340
if ((png_info (img)->bit_depth == 16) && fixed_image_hicolor) {
341
write_noninterlaced (write_rgb_pixel_16 (r));
343
write_noninterlaced (write_rgb_pixel_8 (r));
347
if (png_info (img)->height * png_info (img)->rowbytes >= 10240000L)
349
("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)");
350
rows = xtalloc (png_info (img)->height, png_bytep);
351
for (i = 0; (unsigned) i < png_info (img)->height; i++)
352
rows[i] = xtalloc (png_info (img)->rowbytes, png_byte);
353
png_read_image (png_ptr (img), rows);
354
if ((png_info (img)->bit_depth == 16) && fixed_image_hicolor) {
355
write_interlaced (write_rgb_pixel_16 (row));
357
write_interlaced (write_rgb_pixel_8 (row));
363
/* now write the Smask object */
364
if (smask_objnum > 0) {
365
bitdepth = (int) png_info (img)->bit_depth;
366
pdf_begin_dict (smask_objnum, 0);
367
pdf_puts ("/Type /XObject\n/Subtype /Image\n");
368
pdf_printf ("/Width %i\n/Height %i\n/BitsPerComponent %i\n",
369
(int) png_info (img)->width,
370
(int) png_info (img)->height,
371
(bitdepth == 16 ? 8 : bitdepth));
372
pdf_puts ("/ColorSpace /DeviceGray\n");
374
for (i = 0; i < smask_size; i++) {
377
pdf_buf[pdf_ptr++] = smask[i];
387
/**********************************************************************/
390
* The |copy_png| function is from Hartmut Henkel. The goal is to use
391
* pdf's native FlateDecode support if that is possible.
393
* Only a subset of the png files allows this, but when possible it
394
* greatly improves inclusion speed.
398
/* Code cheerfully gleaned from Thomas Merz' PDFlib, file p_png.c "SPNG - Simple PNG" */
400
static int spng_getint (FILE * fp)
402
unsigned char buf[4];
403
if (fread (buf, 1, 4, fp) != 4)
404
pdftex_fail ("writepng: reading chunk type failed");
405
return ((((((int) buf[0] << 8) + buf[1]) << 8) + buf[2]) << 8) + buf[3];
408
#define SPNG_CHUNK_IDAT 0x49444154
409
#define SPNG_CHUNK_IEND 0x49454E44
411
void copy_png (integer img)
413
FILE *fp = (FILE *) png_ptr (img)->io_ptr;
414
int i, len, type, streamlength = 0;
415
boolean endflag = false;
416
int idat = 0; /* flag to check continuous IDAT chunks sequence */
417
/* 1st pass to find overall stream /Length */
418
if (fseek (fp, 8, SEEK_SET) != 0)
419
pdftex_fail ("writepng: fseek in PNG file failed");
421
len = spng_getint (fp);
422
type = spng_getint (fp);
424
case SPNG_CHUNK_IEND:
427
case SPNG_CHUNK_IDAT:
430
if (fseek (fp, len + 4, SEEK_CUR) != 0)
431
pdftex_fail ("writepng: fseek in PNG file failed");
433
} while (endflag == false);
434
pdf_printf ("/Length %d\n", streamlength);
435
pdf_printf ("/Filter /FlateDecode\n");
436
pdf_printf ("/DecodeParms << ");
437
pdf_printf ("/Colors %d ", png_info (img)->color_type == 2 ? 3 : 1);
438
pdf_printf ("/Columns %d ", (int) png_info (img)->width);
439
pdf_printf ("/BitsPerComponent %i ", (int) png_info (img)->bit_depth);
440
pdf_printf ("/Predictor %d ", 10); /* actual predictor defined on line basis */
441
pdf_printf (">>\n>>\nstream\n");
442
/* 2nd pass to copy data */
444
if (fseek (fp, 8, SEEK_SET) != 0)
445
pdftex_fail ("writepng: fseek in PNG file failed");
447
len = spng_getint (fp);
448
type = spng_getint (fp);
450
case SPNG_CHUNK_IDAT: /* do copy */
452
pdftex_fail ("writepng: IDAT chunk sequence broken");
455
i = (len > pdf_buf_size) ? pdf_buf_size : len;
457
fread (&pdf_buf[pdf_ptr], 1, i, fp);
461
if (fseek (fp, 4, SEEK_CUR) != 0)
462
pdftex_fail ("writepng: fseek in PNG file failed");
464
case SPNG_CHUNK_IEND: /* done */
471
if (fseek (fp, len + 4, SEEK_CUR) != 0)
472
pdftex_fail ("writepng: fseek in PNG file failed");
474
} while (endflag == false);
477
void write_png (integer img)
480
double gamma, checked_gamma;
482
integer palette_objnum = 0;
483
if (fixed_pdf_minor_version < 5)
484
fixed_image_hicolor = 0;
486
pdf_puts ("/Type /XObject\n/Subtype /Image\n");
487
pdf_printf ("/Width %i\n/Height %i\n/BitsPerComponent %i\n",
488
(int) png_info (img)->width,
489
(int) png_info (img)->height, (int) png_info (img)->bit_depth);
490
pdf_puts ("/ColorSpace ");
492
if (fixed_image_apply_gamma) {
493
if (png_get_gAMA (png_ptr (img), png_info (img), &gamma)) {
494
checked_gamma = (fixed_gamma / 1000.0) * gamma;
496
checked_gamma = (fixed_gamma / 1000.0) * (1000.0 / fixed_image_gamma);
499
/* the switching between |png_info| and |png_ptr| queries has been trial and error.
501
if (fixed_pdf_minor_version > 1 && png_info (img)->interlace_type == PNG_INTERLACE_NONE && (png_ptr (img)->transformations == 0 || png_ptr (img)->transformations == 0x2000) /* gamma */
502
&&!(png_ptr (img)->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
503
png_ptr (img)->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
504
&& (fixed_image_hicolor || (png_ptr (img)->bit_depth <= 8))
505
&& (checked_gamma <= 1.01 && checked_gamma > 0.99)
507
if (img_colorspace_ref (img) != 0) {
508
pdf_printf ("%i 0 R\n", (int) img_colorspace_ref (img));
510
switch (png_info (img)->color_type) {
511
case PNG_COLOR_TYPE_PALETTE:
512
pdf_create_obj (0, 0);
513
palette_objnum = obj_ptr;
514
pdf_printf ("[/Indexed /DeviceRGB %i %i 0 R]\n",
515
(int) (png_info (img)->num_palette - 1),
516
(int) palette_objnum);
518
case PNG_COLOR_TYPE_GRAY:
519
pdf_puts ("/DeviceGray\n");
522
pdf_puts ("/DeviceRGB\n");
526
tex_printf (" (PNG copy)");
528
if (palette_objnum > 0) {
529
pdf_begin_dict (palette_objnum, 0);
531
for (i = 0; (unsigned) i < png_info (img)->num_palette; i++) {
533
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].red;
534
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].green;
535
pdf_buf[pdf_ptr++] = png_info (img)->palette[i].blue;
541
tex_printf (" PNG copy skipped because: ");
542
if (fixed_image_apply_gamma &&
543
(checked_gamma > 1.01 || checked_gamma < 0.99))
544
tex_printf ("gamma delta=%lf ", checked_gamma);
545
if (png_ptr (img)->transformations != PNG_TRANSFORM_IDENTITY)
546
tex_printf ("transform=%lu", (long)png_ptr (img)->transformations);
547
if ((png_info (img)->color_type != PNG_COLOR_TYPE_GRAY) &&
548
(png_info (img)->color_type != PNG_COLOR_TYPE_RGB) &&
549
(png_info (img)->color_type != PNG_COLOR_TYPE_PALETTE))
550
tex_printf ("colortype ");
551
if (fixed_pdf_minor_version <= 1)
552
tex_printf ("version=%d ", (int)fixed_pdf_minor_version);
553
if (png_info (img)->interlace_type != PNG_INTERLACE_NONE)
554
tex_printf ("interlaced ");
555
if (png_info (img)->bit_depth > 8)
556
tex_printf ("bitdepth=%d ", png_info (img)->bit_depth);
557
if (png_get_valid (png_ptr (img), png_info (img), PNG_INFO_tRNS))
558
tex_printf ("simple transparancy ");
560
switch (png_info (img)->color_type) {
561
case PNG_COLOR_TYPE_PALETTE:
562
write_png_palette (img);
564
case PNG_COLOR_TYPE_GRAY:
565
write_png_gray (img);
567
case PNG_COLOR_TYPE_GRAY_ALPHA:
568
if (fixed_pdf_minor_version >= 4)
569
write_png_gray_alpha (img);
571
write_png_gray (img);
573
case PNG_COLOR_TYPE_RGB:
576
case PNG_COLOR_TYPE_RGB_ALPHA:
577
if (fixed_pdf_minor_version >= 4)
578
write_png_rgb_alpha (img);
583
pdftex_fail ("unsupported type of color_type <%i>",
584
png_info (img)->color_type);