1 #include <cstdio>
2 #include <iostream>
3 #include <png.h>
4 
5 #include "png_helpers.h"
6 
7 using namespace PNGHelpers;
8 
load(const std::string & filepath)9 struct image_info PNGHelpers::load(const std::string &filepath) {
10     const auto fp = fopen(filepath.c_str(), "rb");
11     if (fp == 0) {
12         perror(filepath.c_str());
13         exit(1);
14     }
15 
16     // verify the header
17     png_byte header[8];
18     fread(header, 1, 8, fp);
19     if (png_sig_cmp(header, 0, 8)) {
20         std::cerr << "error: " << filepath << " is not a PNG file.\n";
21         exit(1);
22     }
23 
24     auto png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
25     auto png_info = png_create_info_struct(png);
26 
27     if (setjmp(png_jmpbuf(png))) abort();
28 
29     png_init_io(png, fp);
30     png_set_sig_bytes(png, 8);  // already read header
31     png_read_info(png, png_info);
32 
33     const auto width = png_get_image_width(png, png_info);
34     const auto height = png_get_image_height(png, png_info);
35     const auto color_type = png_get_color_type(png, png_info);
36     const auto bit_depth = png_get_bit_depth(png, png_info);
37 
38     if (bit_depth == 16)
39         png_set_strip_16(png);
40 
41     if (color_type == PNG_COLOR_TYPE_PALETTE)
42         png_set_palette_to_rgb(png);
43 
44     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
45         png_set_expand_gray_1_2_4_to_8(png);
46 
47     if (png_get_valid(png, png_info, PNG_INFO_tRNS))
48         png_set_tRNS_to_alpha(png);
49 
50     if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
51         png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
52 
53     if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
54         png_set_gray_to_rgb(png);
55 
56     png_read_update_info(png, png_info);
57 
58     const auto rowbytes = png_get_rowbytes(png, png_info);
59     const auto image_data = (png_byte *)malloc(rowbytes * height * sizeof(png_byte));
60 
61     const auto row_pointers = (png_byte **)malloc(height * sizeof(png_byte *));
62     for (int i = 0; i < height; i++) {
63         row_pointers[i] = image_data + i * rowbytes;
64     }
65 
66     png_read_image(png, row_pointers);
67 
68     png_destroy_read_struct(&png, &png_info, nullptr);
69     free(row_pointers);
70     fclose(fp);
71 
72     return {width, height, image_data};
73 }
74