forked from thp/apkenv
-
Notifications
You must be signed in to change notification settings - Fork 3
/
loadpng.c
146 lines (120 loc) · 4.24 KB
/
loadpng.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/// png loader, (c) crow_riot 2013
#include <stdio.h>
#include <libpng12/png.h>
#include <stdlib.h>
#include "imagelib.h"
image_t* loadpng( const char *filepath, const imageloadersettings_t settings)
{
FILE *fp = fopen(filepath,"rb");
if (!fp)
return NULL;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
if ( !png_ptr ) {
fclose(fp);
return NULL;
}
png_infop info = png_create_info_struct(png_ptr);
if ( !info ) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(fp);
return NULL;
}
if ( setjmp(png_jmpbuf(png_ptr)) ) {
png_destroy_read_struct(&png_ptr, &info, NULL);
fclose(fp);
return NULL;
}
png_init_io(png_ptr,fp);
png_set_sig_bytes(png_ptr,0);
int png_transforms = PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_SWAP_ENDIAN|PNG_TRANSFORM_PACKING|PNG_TRANSFORM_EXPAND|(settings.swaprb?PNG_TRANSFORM_BGR:0);
png_read_png(png_ptr, info, png_transforms, NULL);
int rowbytes = png_get_rowbytes(png_ptr, info);
int width = png_get_image_width(png_ptr, info);
int height = png_get_image_height(png_ptr, info);
int bit_depth = png_get_bit_depth(png_ptr, info);
int color_type = png_get_color_type(png_ptr, info);
// convert bit_depth + color_type to image format
int bytepp = 0;
if ( bit_depth==8 )
{
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY: bytepp = 1; break;
case PNG_COLOR_TYPE_GRAY_ALPHA: bytepp = 2; break;
case PNG_COLOR_TYPE_RGB: bytepp = 3; break;
case PNG_COLOR_TYPE_RGBA: bytepp = 4; break;
}
}
if ( bytepp==0 ) {
fclose(fp);
png_destroy_read_struct(&png_ptr, &info, NULL);
return NULL;
}
int forcergba = settings.forcergba && color_type!=PNG_COLOR_TYPE_RGBA;
image_t* image = malloc(sizeof(image_t));
image->data = malloc(sizeof(unsigned char)*width*height*(forcergba?4:bytepp));
image->width = width;
image->height = height;
image->bpp = bytepp;
int stride = width*(forcergba?4:bytepp);
png_bytepp row_pointers = png_get_rows(png_ptr, info);
int x,y;
if (!forcergba) {
if (settings.swapy) {
for ( y=0; y<image->height; y++ )
memcpy(image->data+stride*(image->height-1-y), row_pointers[y], rowbytes);
}
else {
for ( y=0; y<image->height; y++ )
memcpy(image->data+stride*y, row_pointers[y], rowbytes);
}
} else {
if (color_type==PNG_COLOR_TYPE_RGB) {
for ( y=0;y<image->height;y++ ) {
unsigned char* src = row_pointers[y];
unsigned char* trg = image->data+stride*y;
for ( x=0; x<image->width; x++ ) {
int tx = x*4;
int sx = x*bytepp;
trg[tx+0] = src[sx+0];
trg[tx+1] = src[sx+1];
trg[tx+2] = src[sx+2];
trg[tx+3] = settings.alpha;
}
}
}
else
if (color_type==PNG_COLOR_TYPE_GRAY) {
for ( y=0;y<image->height;y++ ) {
unsigned char* src = row_pointers[y];
unsigned char* trg = image->data+stride*y;
for ( x=0; x<image->width; x++ ) {
int tx = x*4;
int sx = x*bytepp;
trg[tx+0] = src[sx];
trg[tx+1] = src[sx];
trg[tx+2] = src[sx];
trg[tx+3] = settings.alpha;
}
}
}
else
if (color_type==PNG_COLOR_TYPE_GRAY_ALPHA) {
for ( y=0;y<image->height;y++ ) {
unsigned char* src = row_pointers[y];
unsigned char* trg = image->data+stride*y;
for ( x=0; x<image->width; x++ ) {
int tx = x*4;
int sx = x*bytepp;
trg[tx+0] = src[sx];
trg[tx+1] = src[sx];
trg[tx+2] = src[sx];
trg[tx+3] = src[sx+1];
}
}
}
}
png_destroy_read_struct(&png_ptr, &info, NULL);
fclose(fp);
return image;
}