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