1 /* -*- c -*- */
2
3 /*
4 * rwpng.c
5 *
6 * rwimg
7 *
8 * Copyright (C) 1997-2004 Mark Probst
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <assert.h>
26 #include <stdlib.h>
27
28 #include <png.h>
29
30 #include "rwpng.h"
31
32 typedef struct
33 {
34 FILE *file;
35 png_structp png_ptr;
36 png_infop info_ptr, end_info;
37 int row_stride;
38 int have_read;
39 } png_data_t;
40
41 void*
open_png_file_reading(const char * filename,int * width,int * height)42 open_png_file_reading (const char *filename, int *width, int *height)
43 {
44 png_data_t *data = (png_data_t*)malloc(sizeof(png_data_t));
45 int _bit_depth,_color_type,_interlace_type,_compression,_filter;
46
47 assert(data != 0);
48
49 data->file = fopen(filename, "r");
50 assert(data->file != 0);
51
52 data->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
53 assert(data->png_ptr != 0);
54
55 data->info_ptr = png_create_info_struct(data->png_ptr);
56 assert(data->info_ptr != 0);
57
58 data->end_info = png_create_info_struct(data->png_ptr);
59 assert(data->end_info != 0);
60
61 if (setjmp(png_jmpbuf(data->png_ptr)))
62 assert(0);
63
64 png_init_io(data->png_ptr, data->file);
65
66 png_read_info(data->png_ptr, data->info_ptr);
67
68 png_get_IHDR(data->png_ptr,data->info_ptr,
69 (png_uint_32 *)width,(png_uint_32 *)height,
70 &_bit_depth,&_color_type,&_interlace_type,&_compression,&_filter);
71
72 assert(_bit_depth == 8 || _bit_depth == 16);
73 assert(_color_type == PNG_COLOR_TYPE_RGB || _color_type == PNG_COLOR_TYPE_RGB_ALPHA);
74 assert(_interlace_type == PNG_INTERLACE_NONE);
75
76 data->have_read = 0;
77
78 return data;
79 }
80
81 void
png_read_lines(void * _data,unsigned char * lines,int num_lines)82 png_read_lines (void *_data, unsigned char *lines, int num_lines)
83 {
84 png_data_t *data = (png_data_t*)_data;
85 int i;
86 int bps, spp;
87 unsigned char *row;
88 png_uint_32 _width,_height;
89 int _bit_depth,_color_type,_interlace_type,_compression,_filter;
90
91 if (setjmp(png_jmpbuf(data->png_ptr)))
92 assert(0);
93
94 png_get_IHDR(data->png_ptr,data->info_ptr,
95 &_width,&_height,&_bit_depth,&_color_type,&_interlace_type,
96 &_compression,&_filter);
97
98 if (_color_type == PNG_COLOR_TYPE_RGB)
99 spp = 3;
100 else
101 spp = 4;
102
103 if (_bit_depth == 16)
104 bps = 2;
105 else
106 bps = 1;
107
108 row = (unsigned char*)malloc(_width * spp * bps);
109
110 for (i = 0; i < num_lines; ++i)
111 {
112 int j, channel;
113
114 png_read_row(data->png_ptr, (png_bytep)row, 0);
115 for (j = 0; j < _width; ++j)
116 for (channel = 0; channel < 3; ++channel)
117 lines[i * _width * 3 + j * 3 + channel] = row[j * spp * bps + channel * bps];
118 }
119
120 free(row);
121
122 data->have_read = 1;
123 }
124
125 void
png_free_reader_data(void * _data)126 png_free_reader_data (void *_data)
127 {
128 png_data_t *data = (png_data_t*)_data;
129
130 if (setjmp(png_jmpbuf(data->png_ptr)))
131 assert(0);
132
133 if (data->have_read)
134 png_read_end(data->png_ptr, data->end_info);
135 png_destroy_read_struct(&data->png_ptr, &data->info_ptr, &data->end_info);
136 fclose(data->file);
137
138 free(data);
139 }
140
141 void*
open_png_file_writing(const char * filename,int width,int height,int pixel_stride,int row_stride)142 open_png_file_writing (const char *filename, int width, int height, int pixel_stride, int row_stride)
143 {
144 png_data_t *data = (png_data_t*)malloc(sizeof(png_data_t));
145
146 assert(data != 0);
147
148 assert(pixel_stride == 3 || pixel_stride == 4);
149
150 data->file = fopen(filename, "w");
151 assert(data->file != 0);
152
153 data->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
154 assert(data->png_ptr != 0);
155
156 data->info_ptr = png_create_info_struct(data->png_ptr);
157 assert(data->info_ptr != 0);
158
159 if (setjmp(png_jmpbuf(data->png_ptr)))
160 assert(0);
161
162 if (pixel_stride == 4)
163 png_set_filler(data->png_ptr, 0, PNG_FILLER_AFTER);
164
165 png_init_io(data->png_ptr, data->file);
166
167 png_set_IHDR(data->png_ptr,data->info_ptr,width,height,
168 8,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,
169 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
170 /* setting these to 0 so just skipping ...
171 data->info_ptr->rowbytes = width * 3;
172 data->info_ptr->palette = 0;
173 data->info_ptr->num_palette = 0;
174 data->info_ptr->num_trans = 0; */
175
176 png_write_info(data->png_ptr, data->info_ptr);
177
178 data->row_stride = row_stride;
179
180 return data;
181 }
182
183 void
png_write_lines(void * _data,unsigned char * lines,int num_lines)184 png_write_lines (void *_data, unsigned char *lines, int num_lines)
185 {
186 png_data_t *data = (png_data_t*)_data;
187 int i;
188
189 if (setjmp(png_jmpbuf(data->png_ptr)))
190 assert(0);
191
192 for (i = 0; i < num_lines; ++i)
193 png_write_row(data->png_ptr, (png_bytep)(lines + i * data->row_stride));
194 }
195
196 void
png_free_writer_data(void * _data)197 png_free_writer_data (void *_data)
198 {
199 png_data_t *data = (png_data_t*)_data;
200
201 if (setjmp(png_jmpbuf(data->png_ptr)))
202 assert(0);
203
204 png_write_end(data->png_ptr, data->info_ptr);
205 png_destroy_write_struct(&data->png_ptr, &data->info_ptr);
206 fclose(data->file);
207
208 free(data);
209 }
210