source: tools/grab/readpng.c @ 4899

Last change on this file since 4899 was 4899, checked in by nit, 12 years ago

add grab source

File size: 9.5 KB
Line 
1/*---------------------------------------------------------------------------
2
3   rpng - simple PNG display program                              readpng.c
4
5  ---------------------------------------------------------------------------
6
7      Copyright (c) 1998-2007 Greg Roelofs.  All rights reserved.
8
9      This software is provided "as is," without warranty of any kind,
10      express or implied.  In no event shall the author or contributors
11      be held liable for any damages arising in any way from the use of
12      this software.
13
14      The contents of this file are DUAL-LICENSED.  You may modify and/or
15      redistribute this software according to the terms of one of the
16      following two licenses (at your option):
17
18
19      LICENSE 1 ("BSD-like with advertising clause"):
20
21      Permission is granted to anyone to use this software for any purpose,
22      including commercial applications, and to alter it and redistribute
23      it freely, subject to the following restrictions:
24
25      1. Redistributions of source code must retain the above copyright
26         notice, disclaimer, and this list of conditions.
27      2. Redistributions in binary form must reproduce the above copyright
28         notice, disclaimer, and this list of conditions in the documenta-
29         tion and/or other materials provided with the distribution.
30      3. All advertising materials mentioning features or use of this
31         software must display the following acknowledgment:
32
33            This product includes software developed by Greg Roelofs
34            and contributors for the book, "PNG: The Definitive Guide,"
35            published by O'Reilly and Associates.
36
37
38      LICENSE 2 (GNU GPL v2 or later):
39
40      This program is free software; you can redistribute it and/or modify
41      it under the terms of the GNU General Public License as published by
42      the Free Software Foundation; either version 2 of the License, or
43      (at your option) any later version.
44
45      This program is distributed in the hope that it will be useful,
46      but WITHOUT ANY WARRANTY; without even the implied warranty of
47      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48      GNU General Public License for more details.
49
50      You should have received a copy of the GNU General Public License
51      along with this program; if not, write to the Free Software Foundation,
52      Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
53
54  ---------------------------------------------------------------------------*/
55
56#include <stdio.h>
57#include <stdlib.h>
58
59#include "png.h"        /* libpng header; includes zlib.h */
60#include "readpng.h"    /* typedefs, common macros, public prototypes */
61
62/* future versions of libpng will provide this macro: */
63#ifndef png_jmpbuf
64#  define png_jmpbuf(png_ptr)   ((png_ptr)->jmpbuf)
65#endif
66
67
68static png_structp png_ptr = NULL;
69static png_infop info_ptr = NULL;
70
71png_uint_32  width, height;
72int  bit_depth, color_type;
73uch  *image_data = NULL;
74
75void readpng_version_info(void)
76{
77    fprintf(stderr, "   Compiled with libpng %s; using libpng %s.\n",
78      PNG_LIBPNG_VER_STRING, png_libpng_ver);
79    fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
80      ZLIB_VERSION, zlib_version);
81}
82
83
84/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */
85
86int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
87{
88    uch sig[8];
89
90
91    /* first do a quick check that the file really is a PNG image; could
92     * have used slightly more general png_sig_cmp() function instead */
93
94    fread(sig, 1, 8, infile);
95    if (!png_check_sig(sig, 8))
96        return 1;   /* bad signature */
97
98
99    /* could pass pointers to user-defined error handlers instead of NULLs: */
100
101    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
102    if (!png_ptr)
103        return 4;   /* out of memory */
104
105    info_ptr = png_create_info_struct(png_ptr);
106    if (!info_ptr) {
107        png_destroy_read_struct(&png_ptr, NULL, NULL);
108        return 4;   /* out of memory */
109    }
110
111
112    /* we could create a second info struct here (end_info), but it's only
113     * useful if we want to keep pre- and post-IDAT chunk info separated
114     * (mainly for PNG-aware image editors and converters) */
115
116
117    /* setjmp() must be called in every function that calls a PNG-reading
118     * libpng function */
119
120    if (setjmp(png_jmpbuf(png_ptr))) {
121        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
122        return 2;
123    }
124
125
126    png_init_io(png_ptr, infile);
127    png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
128
129    png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */
130
131
132    /* alternatively, could make separate calls to png_get_image_width(),
133     * etc., but want bit_depth and color_type for later [don't care about
134     * compression_type and filter_type => NULLs] */
135
136    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
137      NULL, NULL, NULL);
138    *pWidth = width;
139    *pHeight = height;
140
141
142    /* OK, that's all we need for now; return happy */
143
144    return 0;
145}
146
147
148
149
150/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error;
151 * scales values to 8-bit if necessary */
152
153int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
154{
155    png_color_16p pBackground;
156
157
158    /* setjmp() must be called in every function that calls a PNG-reading
159     * libpng function */
160
161    if (setjmp(png_jmpbuf(png_ptr))) {
162        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
163        return 2;
164    }
165
166
167    if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
168        return 1;
169
170    /* it is not obvious from the libpng documentation, but this function
171     * takes a pointer to a pointer, and it always returns valid red, green
172     * and blue values, regardless of color_type: */
173
174    png_get_bKGD(png_ptr, info_ptr, &pBackground);
175
176
177    /* however, it always returns the raw bKGD data, regardless of any
178     * bit-depth transformations, so check depth and adjust if necessary */
179
180    if (bit_depth == 16) {
181        *red   = pBackground->red   >> 8;
182        *green = pBackground->green >> 8;
183        *blue  = pBackground->blue  >> 8;
184    } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
185        if (bit_depth == 1)
186            *red = *green = *blue = pBackground->gray? 255 : 0;
187        else if (bit_depth == 2)
188            *red = *green = *blue = (255/3) * pBackground->gray;
189        else /* bit_depth == 4 */
190            *red = *green = *blue = (255/15) * pBackground->gray;
191    } else {
192        *red   = (uch)pBackground->red;
193        *green = (uch)pBackground->green;
194        *blue  = (uch)pBackground->blue;
195    }
196
197    return 0;
198}
199
200
201
202
203/* display_exponent == LUT_exponent * CRT_exponent */
204
205uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
206{
207    double  gamma;
208    png_uint_32  i, rowbytes;
209    png_bytepp  row_pointers = NULL;
210
211
212    /* setjmp() must be called in every function that calls a PNG-reading
213     * libpng function */
214
215    if (setjmp(png_jmpbuf(png_ptr))) {
216        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
217        return NULL;
218    }
219
220
221    /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
222     * transparency chunks to full alpha channel; strip 16-bit-per-sample
223     * images to 8 bits per sample; and convert grayscale to RGB[A] */
224
225    if (color_type == PNG_COLOR_TYPE_PALETTE)
226        png_set_expand(png_ptr);
227    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
228        png_set_expand(png_ptr);
229    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
230        png_set_expand(png_ptr);
231    if (bit_depth == 16)
232        png_set_strip_16(png_ptr);
233    if (color_type == PNG_COLOR_TYPE_GRAY ||
234        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
235        png_set_gray_to_rgb(png_ptr);
236
237
238    /* unlike the example in the libpng documentation, we have *no* idea where
239     * this file may have come from--so if it doesn't have a file gamma, don't
240     * do any correction ("do no harm") */
241
242    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
243        png_set_gamma(png_ptr, display_exponent, gamma);
244
245
246    /* all transformations have been registered; now update info_ptr data,
247     * get rowbytes and channels, and allocate image memory */
248
249    png_read_update_info(png_ptr, info_ptr);
250
251    *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr);
252    *pChannels = (int)png_get_channels(png_ptr, info_ptr);
253
254    if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) {
255        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
256        return NULL;
257    }
258    if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
259        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
260        free(image_data);
261        image_data = NULL;
262        return NULL;
263    }
264
265    Trace((stderr, "readpng_get_image:  channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height));
266
267
268    /* set the individual row_pointers to point at the correct offsets */
269
270    for (i = 0;  i < height;  ++i)
271        row_pointers[i] = image_data + i*rowbytes;
272
273
274    /* now we can go ahead and just read the whole image */
275
276    png_read_image(png_ptr, row_pointers);
277
278
279    /* and we're done!  (png_read_end() can be omitted if no processing of
280     * post-IDAT text/time/etc. is desired) */
281
282    free(row_pointers);
283    row_pointers = NULL;
284
285    png_read_end(png_ptr, NULL);
286
287    return image_data;
288}
289
290
291void readpng_cleanup(int free_image_data)
292{
293    if (free_image_data && image_data) {
294        free(image_data);
295        image_data = NULL;
296    }
297
298    if (png_ptr && info_ptr) {
299        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
300        png_ptr = NULL;
301        info_ptr = NULL;
302    }
303}
Note: See TracBrowser for help on using the repository browser.