1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/app.h"
12 #include "app/doc.h"
13 #include "app/file/file.h"
14 #include "app/file/file_format.h"
15 #include "app/file/format_options.h"
16 #include "app/file/png_format.h"
17 #include "base/file_handle.h"
18 #include "doc/doc.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "png.h"
24
25 namespace app {
26
27 using namespace base;
28
29 class PngFormat : public FileFormat {
onGetName() const30 const char* onGetName() const override {
31 return "png";
32 }
33
onGetExtensions(base::paths & exts) const34 void onGetExtensions(base::paths& exts) const override {
35 exts.push_back("png");
36 }
37
onGetDioFormat() const38 dio::FileFormat onGetDioFormat() const override {
39 return dio::FileFormat::PNG_IMAGE;
40 }
41
onGetFlags() const42 int onGetFlags() const override {
43 return
44 FILE_SUPPORT_LOAD |
45 FILE_SUPPORT_SAVE |
46 FILE_SUPPORT_RGB |
47 FILE_SUPPORT_RGBA |
48 FILE_SUPPORT_GRAY |
49 FILE_SUPPORT_GRAYA |
50 FILE_SUPPORT_INDEXED |
51 FILE_SUPPORT_SEQUENCES |
52 FILE_SUPPORT_PALETTE_WITH_ALPHA;
53 }
54
55 bool onLoad(FileOp* fop) override;
56 #ifdef ENABLE_SAVE
57 bool onSave(FileOp* fop) override;
58 #endif
59 };
60
CreatePngFormat()61 FileFormat* CreatePngFormat()
62 {
63 return new PngFormat;
64 }
65
report_png_error(png_structp png_ptr,png_const_charp error)66 static void report_png_error(png_structp png_ptr, png_const_charp error)
67 {
68 ((FileOp*)png_get_error_ptr(png_ptr))->setError("libpng: %s\n", error);
69 }
70
71 // TODO this should be part of an png encoder instance
72 static bool fix_one_alpha_pixel = false;
73
PngEncoderOneAlphaPixel(bool state)74 PngEncoderOneAlphaPixel::PngEncoderOneAlphaPixel(bool state)
75 {
76 fix_one_alpha_pixel = state;
77 }
78
~PngEncoderOneAlphaPixel()79 PngEncoderOneAlphaPixel::~PngEncoderOneAlphaPixel()
80 {
81 fix_one_alpha_pixel = false;
82 }
83
onLoad(FileOp * fop)84 bool PngFormat::onLoad(FileOp* fop)
85 {
86 png_uint_32 width, height, y;
87 unsigned int sig_read = 0;
88 png_structp png_ptr;
89 png_infop info_ptr;
90 int bit_depth, color_type, interlace_type;
91 int pass, number_passes;
92 int num_palette;
93 png_colorp palette;
94 png_bytepp rows_pointer;
95 PixelFormat pixelFormat;
96
97 FileHandle handle(open_file_with_exception(fop->filename(), "rb"));
98 FILE* fp = handle.get();
99
100 /* Create and initialize the png_struct with the desired error handler
101 * functions. If you want to use the default stderr and longjump method,
102 * you can supply NULL for the last three parameters. We also supply the
103 * the compiler header file version, so that we know if the application
104 * was compiled with a compatible version of the library
105 */
106 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)fop,
107 report_png_error, report_png_error);
108 if (png_ptr == NULL) {
109 fop->setError("png_create_read_struct\n");
110 return false;
111 }
112
113 /* Allocate/initialize the memory for image information. */
114 info_ptr = png_create_info_struct(png_ptr);
115 if (info_ptr == NULL) {
116 fop->setError("png_create_info_struct\n");
117 png_destroy_read_struct(&png_ptr, NULL, NULL);
118 return false;
119 }
120
121 /* Set error handling if you are using the setjmp/longjmp method (this is
122 * the normal method of doing things with libpng).
123 */
124 if (setjmp(png_jmpbuf(png_ptr))) {
125 fop->setError("Error reading PNG file\n");
126 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
127 return false;
128 }
129
130 // Do not check sRGB profile
131 #ifdef PNG_SKIP_sRGB_CHECK_PROFILE
132 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, 1);
133 #endif
134
135 /* Set up the input control if you are using standard C streams */
136 png_init_io(png_ptr, fp);
137
138 /* If we have already read some of the signature */
139 png_set_sig_bytes(png_ptr, sig_read);
140
141 /* The call to png_read_info() gives us all of the information from the
142 * PNG file before the first IDAT (image data chunk).
143 */
144 png_read_info(png_ptr, info_ptr);
145
146 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
147 &interlace_type, NULL, NULL);
148
149
150 /* Set up the data transformations you want. Note that these are all
151 * optional. Only call them if you want/need them. Many of the
152 * transformations only work on specific types of images, and many
153 * are mutually exclusive.
154 */
155
156 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
157 png_set_strip_16(png_ptr);
158
159 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
160 * byte into separate bytes (useful for paletted and grayscale images).
161 */
162 png_set_packing(png_ptr);
163
164 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
165 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
166 png_set_expand_gray_1_2_4_to_8(png_ptr);
167
168 /* Turn on interlace handling. REQUIRED if you are not using
169 * png_read_image(). To see how to handle interlacing passes,
170 * see the png_read_row() method below:
171 */
172 number_passes = png_set_interlace_handling(png_ptr);
173
174 /* Optional call to gamma correct and add the background to the palette
175 * and update info structure.
176 */
177 png_read_update_info(png_ptr, info_ptr);
178
179 /* create the output image */
180 switch (png_get_color_type(png_ptr, info_ptr)) {
181
182 case PNG_COLOR_TYPE_RGB_ALPHA:
183 fop->sequenceSetHasAlpha(true);
184 case PNG_COLOR_TYPE_RGB:
185 pixelFormat = IMAGE_RGB;
186 break;
187
188 case PNG_COLOR_TYPE_GRAY_ALPHA:
189 fop->sequenceSetHasAlpha(true);
190 case PNG_COLOR_TYPE_GRAY:
191 pixelFormat = IMAGE_GRAYSCALE;
192 break;
193
194 case PNG_COLOR_TYPE_PALETTE:
195 pixelFormat = IMAGE_INDEXED;
196 break;
197
198 default:
199 fop->setError("Color type not supported\n)");
200 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
201 return false;
202 }
203
204 int imageWidth = png_get_image_width(png_ptr, info_ptr);
205 int imageHeight = png_get_image_height(png_ptr, info_ptr);
206 Image* image = fop->sequenceImage(pixelFormat, imageWidth, imageHeight);
207 if (!image) {
208 fop->setError("file_sequence_image %dx%d\n", imageWidth, imageHeight);
209 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
210 return false;
211 }
212
213 // Transparent color
214 png_color_16p png_trans_color = NULL;
215
216 // Read the palette
217 if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE &&
218 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
219 fop->sequenceSetNColors(num_palette);
220
221 for (int c=0; c<num_palette; ++c) {
222 fop->sequenceSetColor(c,
223 palette[c].red,
224 palette[c].green,
225 palette[c].blue);
226 }
227
228 // Read alpha values for palette entries
229 png_bytep trans = NULL; // Transparent palette entries
230 int num_trans = 0;
231 int mask_entry = -1;
232
233 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
234
235 for (int i = 0; i < num_trans; ++i) {
236 fop->sequenceSetAlpha(i, trans[i]);
237
238 if (trans[i] < 255) {
239 fop->sequenceSetHasAlpha(true); // Is a transparent sprite
240 if (trans[i] == 0) {
241 if (mask_entry < 0)
242 mask_entry = i;
243 }
244 }
245 }
246
247 if (mask_entry >= 0)
248 fop->document()->sprite()->setTransparentColor(mask_entry);
249 }
250 else {
251 png_get_tRNS(png_ptr, info_ptr, nullptr, nullptr, &png_trans_color);
252 }
253
254 // Allocate the memory to hold the image using the fields of info_ptr.
255 rows_pointer = (png_bytepp)png_malloc(png_ptr, sizeof(png_bytep) * height);
256 for (y = 0; y < height; y++)
257 rows_pointer[y] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
258
259 for (pass = 0; pass < number_passes; pass++) {
260 for (y = 0; y < height; y++) {
261 png_read_rows(png_ptr, rows_pointer+y, nullptr, 1);
262
263 fop->setProgress(
264 (double)((double)pass + (double)(y+1) / (double)(height))
265 / (double)number_passes);
266
267 if (fop->isStop())
268 break;
269 }
270 }
271
272 // Convert rows_pointer into the doc::Image
273 for (y = 0; y < height; y++) {
274 // RGB_ALPHA
275 if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB_ALPHA) {
276 uint8_t* src_address = rows_pointer[y];
277 uint32_t* dst_address = (uint32_t*)image->getPixelAddress(0, y);
278 unsigned int x, r, g, b, a;
279
280 for (x=0; x<width; x++) {
281 r = *(src_address++);
282 g = *(src_address++);
283 b = *(src_address++);
284 a = *(src_address++);
285 *(dst_address++) = rgba(r, g, b, a);
286 }
287 }
288 // RGB
289 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
290 uint8_t* src_address = rows_pointer[y];
291 uint32_t* dst_address = (uint32_t*)image->getPixelAddress(0, y);
292 unsigned int x, r, g, b, a;
293
294 for (x=0; x<width; x++) {
295 r = *(src_address++);
296 g = *(src_address++);
297 b = *(src_address++);
298
299 // Transparent color
300 if (png_trans_color &&
301 r == png_trans_color->red &&
302 g == png_trans_color->green &&
303 b == png_trans_color->blue) {
304 a = 0;
305 if (!fop->sequenceGetHasAlpha())
306 fop->sequenceSetHasAlpha(true);
307 }
308 else
309 a = 255;
310
311 *(dst_address++) = rgba(r, g, b, a);
312 }
313 }
314 // GRAY_ALPHA
315 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) {
316 uint8_t* src_address = rows_pointer[y];
317 uint16_t* dst_address = (uint16_t*)image->getPixelAddress(0, y);
318 unsigned int x, k, a;
319
320 for (x=0; x<width; x++) {
321 k = *(src_address++);
322 a = *(src_address++);
323 *(dst_address++) = graya(k, a);
324 }
325 }
326 // GRAY
327 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) {
328 uint8_t* src_address = rows_pointer[y];
329 uint16_t* dst_address = (uint16_t*)image->getPixelAddress(0, y);
330 unsigned int x, k, a;
331
332 for (x=0; x<width; x++) {
333 k = *(src_address++);
334
335 // Transparent color
336 if (png_trans_color &&
337 k == png_trans_color->gray) {
338 a = 0;
339 if (!fop->sequenceGetHasAlpha())
340 fop->sequenceSetHasAlpha(true);
341 }
342 else
343 a = 255;
344
345 *(dst_address++) = graya(k, a);
346 }
347 }
348 // PALETTE
349 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
350 uint8_t* src_address = rows_pointer[y];
351 uint8_t* dst_address = (uint8_t*)image->getPixelAddress(0, y);
352 unsigned int x;
353
354 for (x=0; x<width; x++)
355 *(dst_address++) = *(src_address++);
356 }
357 png_free(png_ptr, rows_pointer[y]);
358 }
359 png_free(png_ptr, rows_pointer);
360
361 // Clean up after the read, and free any memory allocated
362 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
363 return true;
364 }
365
366 #ifdef ENABLE_SAVE
onSave(FileOp * fop)367 bool PngFormat::onSave(FileOp* fop)
368 {
369 png_structp png_ptr;
370 png_infop info_ptr;
371 png_colorp palette = nullptr;
372 png_bytep row_pointer;
373 int color_type = 0;
374 int pass, number_passes;
375
376 FileHandle handle(open_file_with_exception_sync_on_close(fop->filename(), "wb"));
377 FILE* fp = handle.get();
378
379 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)fop,
380 report_png_error, report_png_error);
381 if (png_ptr == NULL) {
382 return false;
383 }
384
385 info_ptr = png_create_info_struct(png_ptr);
386 if (info_ptr == NULL) {
387 png_destroy_write_struct(&png_ptr, NULL);
388 return false;
389 }
390
391 if (setjmp(png_jmpbuf(png_ptr))) {
392 png_destroy_write_struct(&png_ptr, &info_ptr);
393 return false;
394 }
395
396 png_init_io(png_ptr, fp);
397
398 const Image* image = fop->sequenceImage();
399 switch (image->pixelFormat()) {
400 case IMAGE_RGB:
401 color_type =
402 (fop->document()->sprite()->needAlpha() ||
403 fix_one_alpha_pixel ?
404 PNG_COLOR_TYPE_RGB_ALPHA:
405 PNG_COLOR_TYPE_RGB);
406 break;
407 case IMAGE_GRAYSCALE:
408 color_type =
409 (fop->document()->sprite()->needAlpha() ||
410 fix_one_alpha_pixel ?
411 PNG_COLOR_TYPE_GRAY_ALPHA:
412 PNG_COLOR_TYPE_GRAY);
413 break;
414 case IMAGE_INDEXED:
415 if (fix_one_alpha_pixel)
416 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
417 else
418 color_type = PNG_COLOR_TYPE_PALETTE;
419 break;
420 }
421
422 const png_uint_32 width = image->width();
423 const png_uint_32 height = image->height();
424
425 png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
426 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
427
428 if (color_type == PNG_COLOR_TYPE_PALETTE) {
429 int c, r, g, b;
430 int pal_size = fop->sequenceGetNColors();
431 pal_size = MID(1, pal_size, PNG_MAX_PALETTE_LENGTH);
432
433 #if PNG_MAX_PALETTE_LENGTH != 256
434 #error PNG_MAX_PALETTE_LENGTH should be 256
435 #endif
436
437 // Save the color palette.
438 palette = (png_colorp)png_malloc(png_ptr, pal_size * sizeof(png_color));
439 for (c = 0; c < pal_size; c++) {
440 fop->sequenceGetColor(c, &r, &g, &b);
441 palette[c].red = r;
442 palette[c].green = g;
443 palette[c].blue = b;
444 }
445
446 png_set_PLTE(png_ptr, info_ptr, palette, pal_size);
447
448 // If the sprite does not have a (visible) background layer, we
449 // put alpha=0 to the transparent color.
450 int mask_entry = -1;
451 if (fop->document()->sprite()->backgroundLayer() == NULL ||
452 !fop->document()->sprite()->backgroundLayer()->isVisible()) {
453 mask_entry = fop->document()->sprite()->transparentColor();
454 }
455
456 bool all_opaque = true;
457 int num_trans = pal_size;
458 png_bytep trans = (png_bytep)png_malloc(png_ptr, num_trans);
459
460 for (c=0; c<num_trans; ++c) {
461 int alpha = 255;
462 fop->sequenceGetAlpha(c, &alpha);
463 trans[c] = (c == mask_entry ? 0: alpha);
464 if (alpha < 255)
465 all_opaque = false;
466 }
467
468 if (!all_opaque || mask_entry >= 0)
469 png_set_tRNS(png_ptr, info_ptr, trans, num_trans, nullptr);
470
471 png_free(png_ptr, trans);
472 }
473
474 png_write_info(png_ptr, info_ptr);
475 png_set_packing(png_ptr);
476
477 row_pointer = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
478
479 for (png_uint_32 y=0; y<height; ++y) {
480 uint8_t* dst_address = row_pointer;
481
482 if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB_ALPHA) {
483 unsigned int x, c, a;
484 bool opaque = true;
485
486 if (image->pixelFormat() == IMAGE_RGB) {
487 uint32_t* src_address = (uint32_t*)image->getPixelAddress(0, y);
488
489 for (x=0; x<width; ++x) {
490 c = *(src_address++);
491 a = rgba_geta(c);
492
493 if (opaque) {
494 if (a < 255)
495 opaque = false;
496 else if (fix_one_alpha_pixel && x == width-1 && y == height-1)
497 a = 254;
498 }
499
500 *(dst_address++) = rgba_getr(c);
501 *(dst_address++) = rgba_getg(c);
502 *(dst_address++) = rgba_getb(c);
503 *(dst_address++) = a;
504 }
505 }
506 // In case that we are converting an indexed image to RGB just
507 // to convert one pixel with alpha=254.
508 else if (image->pixelFormat() == IMAGE_INDEXED) {
509 uint8_t* src_address = (uint8_t*)image->getPixelAddress(0, y);
510 unsigned int x, c;
511 int r, g, b, a;
512 bool opaque = true;
513
514 for (x=0; x<width; ++x) {
515 c = *(src_address++);
516 fop->sequenceGetColor(c, &r, &g, &b);
517 fop->sequenceGetAlpha(c, &a);
518
519 if (opaque) {
520 if (a < 255)
521 opaque = false;
522 else if (fix_one_alpha_pixel && x == width-1 && y == height-1)
523 a = 254;
524 }
525
526 *(dst_address++) = r;
527 *(dst_address++) = g;
528 *(dst_address++) = b;
529 *(dst_address++) = a;
530 }
531 }
532 }
533 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
534 uint32_t* src_address = (uint32_t*)image->getPixelAddress(0, y);
535 unsigned int x, c;
536
537 for (x=0; x<width; ++x) {
538 c = *(src_address++);
539 *(dst_address++) = rgba_getr(c);
540 *(dst_address++) = rgba_getg(c);
541 *(dst_address++) = rgba_getb(c);
542 }
543 }
544 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) {
545 uint16_t* src_address = (uint16_t*)image->getPixelAddress(0, y);
546 unsigned int x, c, a;
547 bool opaque = true;
548
549 for (x=0; x<width; x++) {
550 c = *(src_address++);
551 a = graya_geta(c);
552
553 if (opaque) {
554 if (a < 255)
555 opaque = false;
556 else if (fix_one_alpha_pixel && x == width-1 && y == height-1)
557 a = 254;
558 }
559
560 *(dst_address++) = graya_getv(c);
561 *(dst_address++) = a;
562 }
563 }
564 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) {
565 uint16_t* src_address = (uint16_t*)image->getPixelAddress(0, y);
566 unsigned int x, c;
567
568 for (x=0; x<width; ++x) {
569 c = *(src_address++);
570 *(dst_address++) = graya_getv(c);
571 }
572 }
573 else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
574 uint8_t* src_address = (uint8_t*)image->getPixelAddress(0, y);
575 unsigned int x;
576
577 for (x=0; x<width; ++x)
578 *(dst_address++) = *(src_address++);
579 }
580
581 png_write_rows(png_ptr, &row_pointer, 1);
582
583 fop->setProgress(
584 (double)((double)pass + (double)(y+1) / (double)(height))
585 / (double)number_passes);
586 }
587
588 png_free(png_ptr, row_pointer);
589 png_write_end(png_ptr, info_ptr);
590
591 if (image->pixelFormat() == IMAGE_INDEXED) {
592 png_free(png_ptr, palette);
593 palette = nullptr;
594 }
595
596 png_destroy_write_struct(&png_ptr, &info_ptr);
597 return true;
598 }
599 #endif
600
601 } // namespace app
602