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
|
#include <stdlib.h>
#include <png.h>
#include "meh.h"
struct png_t{
struct image img;
FILE *f;
png_structp png_ptr;
png_infop info_ptr;
png_infop end_info;
int numpasses;
};
static int ispng(FILE *f){
unsigned char buf[8];
if(fread(buf, 1, 8, f) != 8)
return 0;
return png_check_sig(buf, 8);
}
struct image *png_open(FILE *f){
struct png_t *p;
rewind(f);
if(!ispng(f))
return NULL;
p = malloc(sizeof(struct png_t));
if((p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL){
free(p);
return NULL;
}
if((p->info_ptr = png_create_info_struct(p->png_ptr)) == NULL){
png_destroy_read_struct(&p->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
free(p);
return NULL;
}
if((p->end_info = png_create_info_struct(p->png_ptr)) == NULL){
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, (png_infopp)NULL);
free(p);
return NULL;
}
if(setjmp(png_jmpbuf(p->png_ptr))){
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info);
free(p);
return NULL;
}
p->f = f;
rewind(f);
png_init_io(p->png_ptr, f);
png_read_info(p->png_ptr, p->info_ptr);
p->img.bufwidth = png_get_image_width(p->png_ptr, p->info_ptr);
p->img.bufheight = png_get_image_height(p->png_ptr, p->info_ptr);
p->img.fmt = &libpng;
return (struct image *)p;
}
int png_read(struct image *img){
unsigned int y;
png_bytepp row_pointers;
struct png_t *p = (struct png_t *)img;
if(setjmp(png_jmpbuf(p->png_ptr))){
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info);
return 1;
}
{
int color_type = png_get_color_type(p->png_ptr, p->info_ptr);
int bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(p->png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(p->png_ptr);
if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS))
png_set_expand(p->png_ptr);
if (bit_depth == 16)
png_set_strip_16(p->png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(p->png_ptr);
png_set_strip_alpha(p->png_ptr);
if(png_get_interlace_type(p->png_ptr, p->info_ptr) == PNG_INTERLACE_ADAM7)
p->numpasses = png_set_interlace_handling(p->png_ptr);
else
p->numpasses = 1;
png_read_update_info(p->png_ptr, p->info_ptr);
}
row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep));
for(y = 0; y < img->bufheight; y++)
row_pointers[y] = img->buf + y * img->bufwidth * 3;
png_read_image(p->png_ptr, row_pointers);
free(row_pointers);
img->state = LOADED;
return 0;
}
void png_close(struct image *img){
struct png_t *p = (struct png_t *)img;
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info);
fclose(p->f);
}
struct imageformat libpng = {
png_open,
NULL,
png_read,
png_close
};
|