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