Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Format/PNGLoad.cpp
3189 views
1
#include <cstdio>
2
#include <cstdlib>
3
#include <cstring>
4
#include <png.h>
5
6
#include "Common/Data/Format/PNGLoad.h"
7
#include "Common/Log.h"
8
9
// *image_data_ptr should be deleted with free()
10
// return value of 1 == success.
11
int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr) {
12
png_image png;
13
memset(&png, 0, sizeof(png));
14
png.version = PNG_IMAGE_VERSION;
15
16
png_image_begin_read_from_file(&png, file);
17
18
if (PNG_IMAGE_FAILED(png))
19
{
20
WARN_LOG(Log::IO, "pngLoad: %s (%s)", png.message, file);
21
*image_data_ptr = nullptr;
22
return 0;
23
}
24
*pwidth = png.width;
25
*pheight = png.height;
26
png.format = PNG_FORMAT_RGBA;
27
28
int stride = PNG_IMAGE_ROW_STRIDE(png);
29
*image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png));
30
png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
31
return 1;
32
}
33
34
// Custom error handler
35
void pngErrorHandler(png_structp png_ptr, png_const_charp error_msg) {
36
ERROR_LOG(Log::System, "libpng error: %s\n", error_msg);
37
longjmp(png_jmpbuf(png_ptr), 1);
38
}
39
40
void pngWarningHandler(png_structp png_ptr, png_const_charp warning_msg) {
41
DEBUG_LOG(Log::System, "libpng warning: %s\n", warning_msg);
42
}
43
44
int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, int *pheight, unsigned char **image_data_ptr) {
45
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngErrorHandler, pngWarningHandler);
46
if (!png) {
47
return 0;
48
}
49
if (input_len == 0) {
50
return 0;
51
}
52
53
// Ignore incorrect sRGB profiles
54
png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
55
png_set_benign_errors(png, PNG_OPTION_ON);
56
57
png_infop info = png_create_info_struct(png);
58
if (!info) {
59
png_destroy_read_struct(&png, NULL, NULL);
60
return 0;
61
}
62
63
if (setjmp(png_jmpbuf(png))) {
64
png_destroy_read_struct(&png, &info, NULL);
65
if (*image_data_ptr) {
66
free(*image_data_ptr);
67
*image_data_ptr = NULL;
68
}
69
return 0;
70
}
71
72
png_set_read_fn(png, (png_voidp)&input_ptr, [](png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
73
const unsigned char **input = (const unsigned char **)png_get_io_ptr(png_ptr);
74
memcpy(outBytes, *input, byteCountToRead);
75
*input += byteCountToRead;
76
});
77
78
png_read_info(png, info);
79
80
*pwidth = png_get_image_width(png, info);
81
*pheight = png_get_image_height(png, info);
82
83
const int color_type = png_get_color_type(png, info);
84
png_set_strip_16(png);
85
png_set_packing(png);
86
if (color_type == PNG_COLOR_TYPE_GRAY)
87
png_set_expand_gray_1_2_4_to_8(png);
88
if (color_type == PNG_COLOR_TYPE_PALETTE) {
89
png_set_palette_to_rgb(png);
90
} else if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
91
png_set_gray_to_rgb(png);
92
}
93
94
if (png_get_valid(png, info, PNG_INFO_tRNS))
95
png_set_tRNS_to_alpha(png);
96
// Force 8-bit RGBA format
97
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
98
png_set_interlace_handling(png);
99
// Ignore the file's gamma correction
100
png_set_gamma(png, 1.0, 1.0);
101
102
png_read_update_info(png, info);
103
104
size_t row_bytes = png_get_rowbytes(png, info);
105
size_t size = row_bytes * (*pheight);
106
107
*image_data_ptr = (unsigned char *)malloc(size);
108
if (!*image_data_ptr) {
109
png_destroy_read_struct(&png, &info, NULL);
110
return 0;
111
}
112
113
png_bytep *row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * (*pheight));
114
for (int y = 0; y < *pheight; y++) {
115
row_pointers[y] = *image_data_ptr + y * row_bytes;
116
}
117
118
png_read_image(png, row_pointers);
119
free(row_pointers);
120
png_destroy_read_struct(&png, &info, NULL);
121
return 1;
122
}
123
124
bool PNGHeaderPeek::IsValidPNGHeader() const {
125
if (magic != 0x474e5089 || ihdrTag != 0x52444849) {
126
return false;
127
}
128
// Reject crazy sized images, too.
129
if (Width() > 32768 && Height() > 32768) {
130
return false;
131
}
132
return true;
133
}
134
135