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