1% writepng.w 2% 3% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org> 4% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org> 5% 6% This file is part of LuaTeX. 7% 8% LuaTeX is free software; you can redistribute it and/or modify it under 9% the terms of the GNU General Public License as published by the Free 10% Software Foundation; either version 2 of the License, or (at your 11% option) any later version. 12% 13% LuaTeX is distributed in the hope that it will be useful, but WITHOUT 14% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16% License for more details. 17% 18% You should have received a copy of the GNU General Public License along 19% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. 20 21@ @c 22 23 24#include "ptexlib.h" 25#include <assert.h> 26#include "image/image.h" 27#include "image/writepng.h" 28 29@ @c 30static int transparent_page_group = -1; 31 32static void close_and_cleanup_png(image_dict * idict) 33{ 34 assert(idict != NULL); 35 assert(img_file(idict) != NULL); 36 assert(img_filepath(idict) != NULL); 37 xfclose(img_file(idict), img_filepath(idict)); 38 img_file(idict) = NULL; 39 assert(img_png_ptr(idict) != NULL); 40 png_destroy_read_struct(&(img_png_png_ptr(idict)), 41 &(img_png_info_ptr(idict)), NULL); 42 xfree(img_png_ptr(idict)); 43} 44 45@ @c 46static void warn(png_structp png_ptr, png_const_charp msg) 47{ 48 (void)png_ptr; (void)msg; /* Make compiler happy */ 49} 50 51void read_png_info(image_dict * idict, img_readtype_e readtype) 52{ 53 png_structp png_p; 54 png_infop info_p; 55 assert(idict != NULL); 56 assert(img_type(idict) == IMG_TYPE_PNG); 57 img_totalpages(idict) = 1; 58 img_pagenum(idict) = 1; 59 img_xres(idict) = img_yres(idict) = 0; 60 assert(img_file(idict) == NULL); 61 img_file(idict) = xfopen(img_filepath(idict), FOPEN_RBIN_MODE); 62 assert(img_png_ptr(idict) == NULL); 63 img_png_ptr(idict) = xtalloc(1, png_img_struct); 64 if ((png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 65 NULL, NULL, warn)) == NULL) 66 luatex_fail("libpng: png_create_read_struct() failed"); 67 img_png_png_ptr(idict) = png_p; 68 if ((info_p = png_create_info_struct(png_p)) == NULL) 69 luatex_fail("libpng: png_create_info_struct() failed"); 70 img_png_info_ptr(idict) = info_p; 71 if (setjmp(png_jmpbuf(png_p))) 72 luatex_fail("libpng: internal error"); 73#if PNG_LIBPNG_VER >= 10603 74 /* ignore possibly incorrect CMF bytes */ 75 png_set_option(png_p, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON); 76#endif 77 png_init_io(png_p, img_file(idict)); 78 png_read_info(png_p, info_p); 79 /* resolution support */ 80 img_xsize(idict) = (int) png_get_image_width(png_p, info_p); 81 img_ysize(idict) = (int) png_get_image_height(png_p, info_p); 82 if (png_get_valid(png_p, info_p, PNG_INFO_pHYs)) { 83 img_xres(idict) = 84 round(0.0254 * (double) png_get_x_pixels_per_meter(png_p, info_p)); 85 img_yres(idict) = 86 round(0.0254 * (double) png_get_y_pixels_per_meter(png_p, info_p)); 87 } 88 switch (png_get_color_type(png_p, info_p)) { 89 case PNG_COLOR_TYPE_PALETTE: 90 img_procset(idict) |= PROCSET_IMAGE_C | PROCSET_IMAGE_I; 91 break; 92 case PNG_COLOR_TYPE_GRAY: 93 case PNG_COLOR_TYPE_GRAY_ALPHA: 94 img_procset(idict) |= PROCSET_IMAGE_B; 95 break; 96 case PNG_COLOR_TYPE_RGB: 97 case PNG_COLOR_TYPE_RGB_ALPHA: 98 img_procset(idict) |= PROCSET_IMAGE_C; 99 break; 100 default: 101 luatex_fail("unsupported type of color_type <%i>", 102 (int) png_get_color_type(png_p, info_p)); 103 } 104 img_colordepth(idict) = png_get_bit_depth(png_p, info_p); 105 if (readtype == IMG_CLOSEINBETWEEN) 106 close_and_cleanup_png(idict); 107} 108 109@ @c 110#define write_gray_pixel_16(r) \ 111 if (j % 4 == 0 || j % 4 == 1) \ 112 pdf_quick_out(pdf, *r++); \ 113 else \ 114 smask[smask_ptr++] = *r++ \ 115 116#define write_gray_pixel_8(r) \ 117 if (j % 2 == 0) \ 118 pdf_quick_out(pdf, *r++); \ 119 else \ 120 smask[smask_ptr++] = *r++ 121 122#define write_rgb_pixel_16(r) \ 123 if (!(j % 8 == 6 || j % 8 == 7)) \ 124 pdf_quick_out(pdf, *r++); \ 125 else \ 126 smask[smask_ptr++] = *r++ 127 128#define write_rgb_pixel_8(r) \ 129 if (j % 4 != 3) \ 130 pdf_quick_out(pdf, *r++); \ 131 else \ 132 smask[smask_ptr++] = *r++ 133 134#define write_simple_pixel(r) pdf_quick_out(pdf,*r++) 135 136#define write_noninterlaced(outmac) \ 137 for (i = 0; i < (int) png_get_image_height(png_p, info_p); i++) { \ 138 png_read_row(png_p, row, NULL); \ 139 r = row; \ 140 k = (size_t) png_get_rowbytes(png_p, info_p); \ 141 while (k > 0) { \ 142 l = (k > pdf->buf->size) ? pdf->buf->size : k; \ 143 pdf_room(pdf, l); \ 144 for (j = 0; j < l; j++) { \ 145 outmac; \ 146 } \ 147 k -= l; \ 148 } \ 149 } 150 151#define write_interlaced(outmac) \ 152 for (i = 0; i < (int) png_get_image_height(png_p, info_p); i++) { \ 153 row = rows[i]; \ 154 k = (size_t) png_get_rowbytes(png_p, info_p); \ 155 while (k > 0) { \ 156 l = (k > pdf->buf->size) ? pdf->buf->size : k; \ 157 pdf_room(pdf, l); \ 158 for (j = 0; j < l; j++) { \ 159 outmac; \ 160 } \ 161 k -= l; \ 162 } \ 163 xfree(rows[i]); \ 164 } 165 166@ @c 167static void write_palette_streamobj(PDF pdf, int palette_objnum, 168 png_colorp palette, int num_palette) 169{ 170 int i; 171 if (palette_objnum == 0) 172 return; 173 assert(palette != NULL); 174 pdf_begin_obj(pdf, palette_objnum, OBJSTM_NEVER); 175 pdf_begin_dict(pdf); 176 pdf_dict_add_streaminfo(pdf); 177 pdf_end_dict(pdf); 178 pdf_begin_stream(pdf); 179 for (i = 0; i < num_palette; i++) { 180 pdf_room(pdf, 3); 181 pdf_quick_out(pdf, palette[i].red); 182 pdf_quick_out(pdf, palette[i].green); 183 pdf_quick_out(pdf, palette[i].blue); 184 } 185 pdf_end_stream(pdf); 186 pdf_end_obj(pdf); 187} 188 189@ @c 190static void write_smask_streamobj(PDF pdf, image_dict * idict, int smask_objnum, 191 png_bytep smask, int smask_size) 192{ 193 int i; 194 png_structp png_p = img_png_png_ptr(idict); 195 png_infop info_p = img_png_info_ptr(idict); 196 png_byte bitdepth = png_get_bit_depth(png_p, info_p); 197 pdf_begin_obj(pdf, smask_objnum, OBJSTM_NEVER); 198 pdf_begin_dict(pdf); 199 pdf_dict_add_name(pdf, "Type", "XObject"); 200 pdf_dict_add_name(pdf, "Subtype", "Image"); 201 pdf_dict_add_img_filename(pdf, idict); 202 if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) 203 pdf_printf(pdf, "\n%s\n", img_attr(idict)); 204 pdf_dict_add_int(pdf, "Width", (int) png_get_image_width(png_p, info_p)); 205 pdf_dict_add_int(pdf, "Height", (int) png_get_image_height(png_p, info_p)); 206 pdf_dict_add_int(pdf, "BitsPerComponent", (bitdepth == 16 ? 8 : bitdepth)); 207 pdf_dict_add_name(pdf, "ColorSpace", "DeviceGray"); 208 pdf_dict_add_streaminfo(pdf); 209 pdf_end_dict(pdf); 210 pdf_begin_stream(pdf); 211 for (i = 0; i < smask_size; i++) { 212 if (i % 8 == 0) 213 pdf_room(pdf, 8); 214 pdf_quick_out(pdf, smask[i]); 215 if (bitdepth == 16) 216 i++; 217 } 218 pdf_end_stream(pdf); 219 pdf_end_obj(pdf); 220} 221 222@ @c 223static void write_png_gray(PDF pdf, image_dict * idict) 224{ 225 int i; 226 size_t j, k, l; 227 png_structp png_p = img_png_png_ptr(idict); 228 png_infop info_p = img_png_info_ptr(idict); 229 png_bytep row, r, *rows; 230 pdf_dict_add_streaminfo(pdf); 231 pdf_end_dict(pdf); 232 pdf_begin_stream(pdf); 233 if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) { 234 row = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 235 write_noninterlaced(write_simple_pixel(r)); 236 xfree(row); 237 } else { 238 if (png_get_image_height(png_p, info_p) * 239 png_get_rowbytes(png_p, info_p) >= 10240000L) 240 luatex_warn 241 ("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); 242 rows = xtalloc(png_get_image_height(png_p, info_p), png_bytep); 243 for (i = 0; i < (int) png_get_image_height(png_p, info_p); i++) 244 rows[i] = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 245 png_read_image(png_p, rows); 246 write_interlaced(write_simple_pixel(row)); 247 xfree(rows); 248 } 249 pdf_end_stream(pdf); 250 pdf_end_obj(pdf); 251} 252 253@ @c 254static void write_png_gray_alpha(PDF pdf, image_dict * idict) 255{ 256 int i; 257 size_t j, k, l; 258 png_structp png_p = img_png_png_ptr(idict); 259 png_infop info_p = img_png_info_ptr(idict); 260 png_bytep row, r, *rows; 261 int smask_objnum = 0; 262 png_bytep smask; 263 int smask_ptr = 0; 264 int smask_size = 0; 265 smask_objnum = pdf_create_obj(pdf, obj_type_others, 0); 266 pdf_dict_add_ref(pdf, "SMask", (int) smask_objnum); 267 smask_size = 268 (int) ((png_get_rowbytes(png_p, info_p) / 2) * 269 png_get_image_height(png_p, info_p)); 270 smask = xtalloc((unsigned) smask_size, png_byte); 271 pdf_dict_add_streaminfo(pdf); 272 pdf_end_dict(pdf); 273 pdf_begin_stream(pdf); 274 if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) { 275 row = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 276 if ((png_get_bit_depth(png_p, info_p) == 16) 277 && (pdf->image_hicolor != 0)) { 278 write_noninterlaced(write_gray_pixel_16(r)); 279 } else { 280 write_noninterlaced(write_gray_pixel_8(r)); 281 } 282 xfree(row); 283 } else { 284 if (png_get_image_height(png_p, info_p) * 285 png_get_rowbytes(png_p, info_p) >= 10240000L) 286 luatex_warn 287 ("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); 288 rows = xtalloc(png_get_image_height(png_p, info_p), png_bytep); 289 for (i = 0; i < (int) png_get_image_height(png_p, info_p); i++) 290 rows[i] = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 291 png_read_image(png_p, rows); 292 if ((png_get_bit_depth(png_p, info_p) == 16) 293 && (pdf->image_hicolor != 0)) { 294 write_interlaced(write_gray_pixel_16(row)); 295 } else { 296 write_interlaced(write_gray_pixel_8(row)); 297 } 298 xfree(rows); 299 } 300 pdf_end_stream(pdf); 301 pdf_end_obj(pdf); 302 write_smask_streamobj(pdf, idict, smask_objnum, smask, smask_size); 303 xfree(smask); 304} 305 306@ @c 307static void write_png_rgb_alpha(PDF pdf, image_dict * idict) 308{ 309 int i; 310 size_t j, k, l; 311 png_structp png_p = img_png_png_ptr(idict); 312 png_infop info_p = img_png_info_ptr(idict); 313 png_bytep row, r, *rows; 314 int smask_objnum = 0; 315 png_bytep smask; 316 int smask_ptr = 0; 317 int smask_size = 0; 318 smask_objnum = pdf_create_obj(pdf, obj_type_others, 0); 319 pdf_dict_add_ref(pdf, "SMask", (int) smask_objnum); 320 smask_size = 321 (int) ((png_get_rowbytes(png_p, info_p) / 4) * 322 png_get_image_height(png_p, info_p)); 323 smask = xtalloc((unsigned) smask_size, png_byte); 324 pdf_dict_add_streaminfo(pdf); 325 pdf_end_dict(pdf); 326 pdf_begin_stream(pdf); 327 if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) { 328 row = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 329 if ((png_get_bit_depth(png_p, info_p) == 16) 330 && (pdf->image_hicolor != 0)) { 331 write_noninterlaced(write_rgb_pixel_16(r)); 332 } else { 333 write_noninterlaced(write_rgb_pixel_8(r)); 334 } 335 xfree(row); 336 } else { 337 if (png_get_image_height(png_p, info_p) * 338 png_get_rowbytes(png_p, info_p) >= 10240000L) 339 luatex_warn 340 ("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); 341 rows = xtalloc(png_get_image_height(png_p, info_p), png_bytep); 342 for (i = 0; i < (int) png_get_image_height(png_p, info_p); i++) 343 rows[i] = xtalloc(png_get_rowbytes(png_p, info_p), png_byte); 344 png_read_image(png_p, rows); 345 if ((png_get_bit_depth(png_p, info_p) == 16) 346 && (pdf->image_hicolor != 0)) { 347 write_interlaced(write_rgb_pixel_16(row)); 348 } else { 349 write_interlaced(write_rgb_pixel_8(row)); 350 } 351 xfree(rows); 352 } 353 pdf_end_stream(pdf); 354 pdf_end_obj(pdf); 355 write_smask_streamobj(pdf, idict, smask_objnum, smask, smask_size); 356 xfree(smask); 357} 358 359@ The |copy_png| code is cheerfully gleaned from Thomas Merz' PDFlib, 360file |p_png.c| ``SPNG - Simple PNG''. 361The goal is to use pdf's native FlateDecode support, if that is possible. 362Only a subset of the png files allows this, but for these it greatly 363improves inclusion speed. 364 365In the ``PNG Copy'' mode only the IDAT chunks are copied; 366all other chunks from the PNG file are discarded. 367If there are any other chunks in the PNG file, 368which might influence the visual appearance of the image, 369or if image processing like gamma change is requested, 370the ``PNG Copy'' function must be skipped; therefore the lengthy tests. 371 372@c 373static int spng_getint(FILE * f) 374{ 375 unsigned char buf[4]; 376 if (fread(buf, 1, 4, f) != 4) 377 luatex_fail("writepng: reading chunk type failed"); 378 return ((((((int) buf[0] << 8) + buf[1]) << 8) + buf[2]) << 8) + buf[3]; 379} 380 381#define SPNG_CHUNK_IDAT 0x49444154 382#define SPNG_CHUNK_IEND 0x49454E44 383 384static void copy_png(PDF pdf, image_dict * idict) 385{ 386 int type, streamlength = 0, idat = 0; 387 size_t len; 388 boolean endflag = false; 389 FILE *f; 390 png_structp png_p; 391 png_infop info_p; 392 assert(idict != NULL); 393 png_p = img_png_png_ptr(idict); 394 info_p = img_png_info_ptr(idict); 395 f = (FILE *) png_get_io_ptr(png_p); 396 /* 1st pass to find overall stream /Length */ 397 if (fseek(f, 8, SEEK_SET) != 0) 398 luatex_fail("writepng: fseek in PNG file failed (1)"); 399 do { 400 len = spng_getint(f); 401 type = spng_getint(f); 402 switch (type) { 403 case SPNG_CHUNK_IEND: 404 endflag = true; 405 break; 406 case SPNG_CHUNK_IDAT: 407 streamlength += len; 408 default: 409 if (fseek(f, len + 4, SEEK_CUR) != 0) 410 luatex_fail("writepng: fseek in PNG file failed (2)"); 411 } 412 } while (endflag == false); 413 pdf_dict_add_int(pdf, "Length", streamlength); 414 pdf_dict_add_name(pdf, "Filter", "FlateDecode"); 415 pdf_add_name(pdf, "DecodeParms"); 416 pdf_begin_dict(pdf); 417 pdf_dict_add_int(pdf, "Colors", 418 png_get_color_type(png_p, 419 info_p) == PNG_COLOR_TYPE_RGB ? 3 : 1); 420 pdf_dict_add_int(pdf, "Columns", png_get_image_width(png_p, info_p)); 421 pdf_dict_add_int(pdf, "BitsPerComponent", png_get_bit_depth(png_p, info_p)); 422 pdf_dict_add_int(pdf, "Predictor", 10); 423 pdf_end_dict(pdf); 424 pdf_end_dict(pdf); 425 pdf_begin_stream(pdf); 426 assert(pdf->zip_write_state == NO_ZIP); /* the PNG stream is already compressed */ 427 /* 2nd pass to copy data */ 428 endflag = false; 429 if (fseek(f, 8, SEEK_SET) != 0) 430 luatex_fail("writepng: fseek in PNG file failed (3)"); 431 do { 432 len = spng_getint(f); 433 type = spng_getint(f); 434 switch (type) { 435 case SPNG_CHUNK_IDAT: /* do copy */ 436 if (idat == 2) 437 luatex_fail("writepng: IDAT chunk sequence broken"); 438 idat = 1; 439 if (read_file_to_buf(pdf, f, len) != len) 440 luatex_fail("writepng: fread failed"); 441 if (fseek(f, 4, SEEK_CUR) != 0) 442 luatex_fail("writepng: fseek in PNG file failed (4)"); 443 break; 444 case SPNG_CHUNK_IEND: /* done */ 445 endflag = true; 446 break; 447 default: 448 if (idat == 1) 449 idat = 2; 450 if (fseek(f, len + 4, SEEK_CUR) != 0) 451 luatex_fail("writepng: fseek in PNG file failed (5)"); 452 } 453 } while (endflag == false); 454 pdf_end_stream(pdf); 455 pdf_end_obj(pdf); 456} 457 458@ @c 459static void reopen_png(image_dict * idict) 460{ 461 int width, height, xres, yres; 462 width = img_xsize(idict); /* do consistency check */ 463 height = img_ysize(idict); 464 xres = img_xres(idict); 465 yres = img_yres(idict); 466 read_png_info(idict, IMG_KEEPOPEN); 467 if (width != img_xsize(idict) || height != img_ysize(idict) 468 || xres != img_xres(idict) || yres != img_yres(idict)) 469 luatex_fail("writepng: image dimensions have changed"); 470} 471 472@ @c 473static boolean last_png_needs_page_group; 474 475void write_png(PDF pdf, image_dict * idict) 476{ 477#ifndef PNG_FP_1 478 /* for libpng < 1.5.0 */ 479# define PNG_FP_1 100000 480#endif 481 int num_palette, palette_objnum = 0; 482 boolean png_copy = true; 483 double gamma = 0.0; 484 png_fixed_point int_file_gamma = 0; 485 png_structp png_p; 486 png_infop info_p; 487 png_colorp palette; 488 assert(idict != NULL); 489 last_png_needs_page_group = false; 490 if (img_file(idict) == NULL) 491 reopen_png(idict); 492 assert(img_png_ptr(idict) != NULL); 493 png_p = img_png_png_ptr(idict); 494 info_p = img_png_info_ptr(idict); 495 /* simple transparency support */ 496 if (png_get_valid(png_p, info_p, PNG_INFO_tRNS)) { 497 png_set_tRNS_to_alpha(png_p); 498 png_copy = false; 499 } 500 /* alpha channel support */ 501 if (pdf->minor_version < 4 502 && png_get_color_type(png_p, info_p) | PNG_COLOR_MASK_ALPHA) { 503 png_set_strip_alpha(png_p); 504 png_copy = false; 505 } 506 /* 16 bit depth support */ 507 if (pdf->minor_version < 5) 508 pdf->image_hicolor = 0; 509 if ((png_get_bit_depth(png_p, info_p) == 16) && (pdf->image_hicolor == 0)) { 510 png_set_strip_16(png_p); 511 png_copy = false; 512 } 513 /* gamma support */ 514 if (png_get_valid(png_p, info_p, PNG_INFO_gAMA)) { 515 png_get_gAMA(png_p, info_p, &gamma); 516 png_get_gAMA_fixed(png_p, info_p, &int_file_gamma); 517 } 518 if (pdf->image_apply_gamma) { 519 if (png_get_valid(png_p, info_p, PNG_INFO_gAMA)) 520 png_set_gamma(png_p, (pdf->gamma / 1000.0), gamma); 521 else 522 png_set_gamma(png_p, (pdf->gamma / 1000.0), 523 (1000.0 / pdf->image_gamma)); 524 png_copy = false; 525 } 526 /* reset structure */ 527 (void) png_set_interlace_handling(png_p); 528 png_read_update_info(png_p, info_p); 529 530 pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER); 531 pdf_begin_dict(pdf); 532 pdf_dict_add_name(pdf, "Type", "XObject"); 533 pdf_dict_add_name(pdf, "Subtype", "Image"); 534 pdf_dict_add_img_filename(pdf, idict); 535 if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) 536 pdf_printf(pdf, "\n%s\n", img_attr(idict)); 537 pdf_dict_add_int(pdf, "Width", (int) png_get_image_width(png_p, info_p)); 538 pdf_dict_add_int(pdf, "Height", (int) png_get_image_height(png_p, info_p)); 539 pdf_dict_add_int(pdf, "BitsPerComponent", 540 (int) png_get_bit_depth(png_p, info_p)); 541 if (img_colorspace(idict) != 0) { 542 pdf_dict_add_ref(pdf, "ColorSpace", (int) img_colorspace(idict)); 543 } else { 544 switch (png_get_color_type(png_p, info_p)) { 545 case PNG_COLOR_TYPE_PALETTE: 546 png_get_PLTE(png_p, info_p, &palette, &num_palette); 547 palette_objnum = pdf_create_obj(pdf, obj_type_others, 0); 548 pdf_add_name(pdf, "ColorSpace"); 549 pdf_begin_array(pdf); 550 pdf_add_name(pdf, "Indexed"); 551 pdf_add_name(pdf, "DeviceRGB"); /* base; PDFRef. 4.5.5 */ 552 pdf_add_int(pdf, (int) (num_palette - 1)); /* hival */ 553 pdf_add_ref(pdf, (int) palette_objnum); /* lookup */ 554 pdf_end_array(pdf); 555 break; 556 case PNG_COLOR_TYPE_GRAY: 557 case PNG_COLOR_TYPE_GRAY_ALPHA: 558 pdf_dict_add_name(pdf, "ColorSpace", "DeviceGray"); 559 break; 560 case PNG_COLOR_TYPE_RGB: 561 case PNG_COLOR_TYPE_RGB_ALPHA: 562 pdf_dict_add_name(pdf, "ColorSpace", "DeviceRGB"); 563 break; 564 default: 565 luatex_fail("unsupported type of color_type <%i>", 566 png_get_color_type(png_p, info_p)); 567 } 568 } 569 if (png_copy && pdf->minor_version > 1 570 && png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE 571 && (png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_GRAY 572 || png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_RGB) 573 && !pdf->image_apply_gamma 574 && (!png_get_valid(png_p, info_p, PNG_INFO_gAMA) 575 || int_file_gamma == PNG_FP_1) 576 && !png_get_valid(png_p, info_p, PNG_INFO_cHRM) 577 && !png_get_valid(png_p, info_p, PNG_INFO_iCCP) 578 && !png_get_valid(png_p, info_p, PNG_INFO_sBIT) 579 && !png_get_valid(png_p, info_p, PNG_INFO_sRGB) 580 && !png_get_valid(png_p, info_p, PNG_INFO_bKGD) 581 && !png_get_valid(png_p, info_p, PNG_INFO_hIST) 582 && !png_get_valid(png_p, info_p, PNG_INFO_tRNS) 583 && !png_get_valid(png_p, info_p, PNG_INFO_sPLT)) { 584 copy_png(pdf, idict); 585 } else { 586 if (0) { 587 tex_printf(" *** PNG copy skipped because: "); 588 if (!png_copy) 589 tex_printf("!png_copy "); 590 if (!(pdf->minor_version > 1)) 591 tex_printf("minorversion=%d ", pdf->minor_version); 592 if (!(png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE)) 593 tex_printf("interlaced "); 594 if (!((png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_GRAY) 595 || (png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_RGB))) 596 tex_printf("colortype "); 597 if (pdf->image_apply_gamma) 598 tex_printf("apply gamma "); 599 if (!(!png_get_valid(png_p, info_p, PNG_INFO_gAMA) 600 || int_file_gamma == PNG_FP_1)) 601 tex_printf("gamma "); 602 if (png_get_valid(png_p, info_p, PNG_INFO_cHRM)) 603 tex_printf("cHRM "); 604 if (png_get_valid(png_p, info_p, PNG_INFO_iCCP)) 605 tex_printf("iCCP "); 606 if (png_get_valid(png_p, info_p, PNG_INFO_sBIT)) 607 tex_printf("sBIT "); 608 if (png_get_valid(png_p, info_p, PNG_INFO_sRGB)) 609 tex_printf("sRGB "); 610 if (png_get_valid(png_p, info_p, PNG_INFO_bKGD)) 611 tex_printf("bKGD "); 612 if (png_get_valid(png_p, info_p, PNG_INFO_hIST)) 613 tex_printf("hIST "); 614 if (png_get_valid(png_p, info_p, PNG_INFO_tRNS)) 615 tex_printf("tRNS "); 616 if (png_get_valid(png_p, info_p, PNG_INFO_sPLT)) 617 tex_printf("sPLT "); 618 } 619 switch (png_get_color_type(png_p, info_p)) { 620 case PNG_COLOR_TYPE_PALETTE: 621 case PNG_COLOR_TYPE_GRAY: 622 case PNG_COLOR_TYPE_RGB: 623 write_png_gray(pdf, idict); 624 break; 625 case PNG_COLOR_TYPE_GRAY_ALPHA: 626 if (pdf->minor_version >= 4) { 627 write_png_gray_alpha(pdf, idict); 628 last_png_needs_page_group = true; 629 } else 630 write_png_gray(pdf, idict); 631 break; 632 case PNG_COLOR_TYPE_RGB_ALPHA: 633 if (pdf->minor_version >= 4) { 634 write_png_rgb_alpha(pdf, idict); 635 last_png_needs_page_group = true; 636 } else 637 write_png_gray(pdf, idict); 638 break; 639 default: 640 assert(0); 641 } 642 } 643 write_palette_streamobj(pdf, palette_objnum, palette, num_palette); 644 close_and_cleanup_png(idict); 645} 646 647@ @c 648static boolean transparent_page_group_was_written = false; 649 650@ Called after the xobject generated by |write_png| has been finished; used to 651write out additional objects 652@c 653void write_additional_png_objects(PDF pdf) 654{ 655 (void) pdf; 656 (void) transparent_page_group; 657 (void) transparent_page_group_was_written; 658 return; /* this interferes with current macro-based usage and cannot be configured */ 659#if 0 660 if (last_png_needs_page_group) { 661 if (!transparent_page_group_was_written && transparent_page_group > 1) { 662 /* create new group object */ 663 transparent_page_group_was_written = true; 664 pdf_begin_obj(pdf, transparent_page_group, 2); 665 if (pdf->compress_level == 0) { 666 pdf_puts(pdf, "%PTEX Group needed for transparent pngs\n"); 667 } 668 pdf_begin_dict(pdf); 669 pdf_dict_add_name(pdf, "Type", "Group"); 670 pdf_dict_add_name(pdf, "S", "Transparency"); 671 pdf_dict_add_name(pdf, "CS", "DeviceRGB"); 672 pdf_dict_add_bool(pdf, "I", 1); 673 pdf_dict_add_bool(pdf, "K", 1); 674 pdf_end_dict(pdf); 675 pdf_end_obj(pdf); 676 } 677 } 678#endif 679} 680