1*a67afe4dSAndroid Build Coastguard Worker /*- pngpixel
2*a67afe4dSAndroid Build Coastguard Worker *
3*a67afe4dSAndroid Build Coastguard Worker * COPYRIGHT: Written by John Cunningham Bowler, 2011.
4*a67afe4dSAndroid Build Coastguard Worker * To the extent possible under law, the author has waived all copyright and
5*a67afe4dSAndroid Build Coastguard Worker * related or neighboring rights to this work. This work is published from:
6*a67afe4dSAndroid Build Coastguard Worker * United States.
7*a67afe4dSAndroid Build Coastguard Worker *
8*a67afe4dSAndroid Build Coastguard Worker * Read a single pixel value from a PNG file.
9*a67afe4dSAndroid Build Coastguard Worker *
10*a67afe4dSAndroid Build Coastguard Worker * This code illustrates basic 'by-row' reading of a PNG file using libpng.
11*a67afe4dSAndroid Build Coastguard Worker * Rows are read until a particular pixel is found; the value of this pixel is
12*a67afe4dSAndroid Build Coastguard Worker * then printed on stdout.
13*a67afe4dSAndroid Build Coastguard Worker *
14*a67afe4dSAndroid Build Coastguard Worker * The code illustrates how to do this on interlaced as well as non-interlaced
15*a67afe4dSAndroid Build Coastguard Worker * images. Normally you would call png_set_interlace_handling() to have libpng
16*a67afe4dSAndroid Build Coastguard Worker * deal with the interlace for you, but that obliges you to buffer half of the
17*a67afe4dSAndroid Build Coastguard Worker * image to assemble the interlaced rows. In this code
18*a67afe4dSAndroid Build Coastguard Worker * png_set_interlace_handling() is not called and, instead, the code handles the
19*a67afe4dSAndroid Build Coastguard Worker * interlace passes directly looking for the required pixel.
20*a67afe4dSAndroid Build Coastguard Worker */
21*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
22*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
23*a67afe4dSAndroid Build Coastguard Worker #include <setjmp.h> /* required for error handling */
24*a67afe4dSAndroid Build Coastguard Worker
25*a67afe4dSAndroid Build Coastguard Worker /* Normally use <png.h> here to get the installed libpng, but this is done to
26*a67afe4dSAndroid Build Coastguard Worker * ensure the code picks up the local libpng implementation:
27*a67afe4dSAndroid Build Coastguard Worker */
28*a67afe4dSAndroid Build Coastguard Worker #include "../../png.h"
29*a67afe4dSAndroid Build Coastguard Worker
30*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
31*a67afe4dSAndroid Build Coastguard Worker
32*a67afe4dSAndroid Build Coastguard Worker /* Return component 'c' of pixel 'x' from the given row. */
33*a67afe4dSAndroid Build Coastguard Worker static unsigned int
component(png_const_bytep row,png_uint_32 x,unsigned int c,unsigned int bit_depth,unsigned int channels)34*a67afe4dSAndroid Build Coastguard Worker component(png_const_bytep row, png_uint_32 x, unsigned int c,
35*a67afe4dSAndroid Build Coastguard Worker unsigned int bit_depth, unsigned int channels)
36*a67afe4dSAndroid Build Coastguard Worker {
37*a67afe4dSAndroid Build Coastguard Worker /* PNG images can be up to 2^31 pixels wide, but this means they can be up to
38*a67afe4dSAndroid Build Coastguard Worker * 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34
39*a67afe4dSAndroid Build Coastguard Worker * bytes wide. Since the row fitted into memory, however, the following must
40*a67afe4dSAndroid Build Coastguard Worker * work:
41*a67afe4dSAndroid Build Coastguard Worker */
42*a67afe4dSAndroid Build Coastguard Worker png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels);
43*a67afe4dSAndroid Build Coastguard Worker png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c);
44*a67afe4dSAndroid Build Coastguard Worker
45*a67afe4dSAndroid Build Coastguard Worker row = (png_const_bytep)(((const png_byte (*)[8])row) + bit_offset_hi);
46*a67afe4dSAndroid Build Coastguard Worker row += bit_offset_lo >> 3;
47*a67afe4dSAndroid Build Coastguard Worker bit_offset_lo &= 0x07;
48*a67afe4dSAndroid Build Coastguard Worker
49*a67afe4dSAndroid Build Coastguard Worker /* PNG pixels are packed into bytes to put the first pixel in the highest
50*a67afe4dSAndroid Build Coastguard Worker * bits of the byte and into two bytes for 16-bit values with the high 8 bits
51*a67afe4dSAndroid Build Coastguard Worker * first, so:
52*a67afe4dSAndroid Build Coastguard Worker */
53*a67afe4dSAndroid Build Coastguard Worker switch (bit_depth)
54*a67afe4dSAndroid Build Coastguard Worker {
55*a67afe4dSAndroid Build Coastguard Worker case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01;
56*a67afe4dSAndroid Build Coastguard Worker case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03;
57*a67afe4dSAndroid Build Coastguard Worker case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f;
58*a67afe4dSAndroid Build Coastguard Worker case 8: return row[0];
59*a67afe4dSAndroid Build Coastguard Worker case 16: return (row[0] << 8) + row[1];
60*a67afe4dSAndroid Build Coastguard Worker default:
61*a67afe4dSAndroid Build Coastguard Worker /* This should never happen; it indicates a bug in this program or in
62*a67afe4dSAndroid Build Coastguard Worker * libpng itself:
63*a67afe4dSAndroid Build Coastguard Worker */
64*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth);
65*a67afe4dSAndroid Build Coastguard Worker exit(1);
66*a67afe4dSAndroid Build Coastguard Worker }
67*a67afe4dSAndroid Build Coastguard Worker }
68*a67afe4dSAndroid Build Coastguard Worker
69*a67afe4dSAndroid Build Coastguard Worker /* Print a pixel from a row returned by libpng; determine the row format, find
70*a67afe4dSAndroid Build Coastguard Worker * the pixel, and print the relevant information to stdout.
71*a67afe4dSAndroid Build Coastguard Worker */
72*a67afe4dSAndroid Build Coastguard Worker static void
print_pixel(png_structp png_ptr,png_infop info_ptr,png_const_bytep row,png_uint_32 x)73*a67afe4dSAndroid Build Coastguard Worker print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
74*a67afe4dSAndroid Build Coastguard Worker png_uint_32 x)
75*a67afe4dSAndroid Build Coastguard Worker {
76*a67afe4dSAndroid Build Coastguard Worker unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
77*a67afe4dSAndroid Build Coastguard Worker
78*a67afe4dSAndroid Build Coastguard Worker switch (png_get_color_type(png_ptr, info_ptr))
79*a67afe4dSAndroid Build Coastguard Worker {
80*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_GRAY:
81*a67afe4dSAndroid Build Coastguard Worker printf("GRAY %u\n", component(row, x, 0, bit_depth, 1));
82*a67afe4dSAndroid Build Coastguard Worker return;
83*a67afe4dSAndroid Build Coastguard Worker
84*a67afe4dSAndroid Build Coastguard Worker /* The palette case is slightly more difficult - the palette and, if
85*a67afe4dSAndroid Build Coastguard Worker * present, the tRNS ('transparency', though the values are really
86*a67afe4dSAndroid Build Coastguard Worker * opacity) data must be read to give the full picture:
87*a67afe4dSAndroid Build Coastguard Worker */
88*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_PALETTE:
89*a67afe4dSAndroid Build Coastguard Worker {
90*a67afe4dSAndroid Build Coastguard Worker int index = component(row, x, 0, bit_depth, 1);
91*a67afe4dSAndroid Build Coastguard Worker png_colorp palette = NULL;
92*a67afe4dSAndroid Build Coastguard Worker int num_palette = 0;
93*a67afe4dSAndroid Build Coastguard Worker
94*a67afe4dSAndroid Build Coastguard Worker if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) &
95*a67afe4dSAndroid Build Coastguard Worker PNG_INFO_PLTE) && num_palette > 0 && palette != NULL)
96*a67afe4dSAndroid Build Coastguard Worker {
97*a67afe4dSAndroid Build Coastguard Worker png_bytep trans_alpha = NULL;
98*a67afe4dSAndroid Build Coastguard Worker int num_trans = 0;
99*a67afe4dSAndroid Build Coastguard Worker if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans,
100*a67afe4dSAndroid Build Coastguard Worker NULL) & PNG_INFO_tRNS) && num_trans > 0 &&
101*a67afe4dSAndroid Build Coastguard Worker trans_alpha != NULL)
102*a67afe4dSAndroid Build Coastguard Worker printf("INDEXED %u = %d %d %d %d\n", index,
103*a67afe4dSAndroid Build Coastguard Worker palette[index].red, palette[index].green,
104*a67afe4dSAndroid Build Coastguard Worker palette[index].blue,
105*a67afe4dSAndroid Build Coastguard Worker index < num_trans ? trans_alpha[index] : 255);
106*a67afe4dSAndroid Build Coastguard Worker
107*a67afe4dSAndroid Build Coastguard Worker else /* no transparency */
108*a67afe4dSAndroid Build Coastguard Worker printf("INDEXED %u = %d %d %d\n", index,
109*a67afe4dSAndroid Build Coastguard Worker palette[index].red, palette[index].green,
110*a67afe4dSAndroid Build Coastguard Worker palette[index].blue);
111*a67afe4dSAndroid Build Coastguard Worker }
112*a67afe4dSAndroid Build Coastguard Worker
113*a67afe4dSAndroid Build Coastguard Worker else
114*a67afe4dSAndroid Build Coastguard Worker printf("INDEXED %u = invalid index\n", index);
115*a67afe4dSAndroid Build Coastguard Worker }
116*a67afe4dSAndroid Build Coastguard Worker return;
117*a67afe4dSAndroid Build Coastguard Worker
118*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_RGB:
119*a67afe4dSAndroid Build Coastguard Worker printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3),
120*a67afe4dSAndroid Build Coastguard Worker component(row, x, 1, bit_depth, 3),
121*a67afe4dSAndroid Build Coastguard Worker component(row, x, 2, bit_depth, 3));
122*a67afe4dSAndroid Build Coastguard Worker return;
123*a67afe4dSAndroid Build Coastguard Worker
124*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_GRAY_ALPHA:
125*a67afe4dSAndroid Build Coastguard Worker printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2),
126*a67afe4dSAndroid Build Coastguard Worker component(row, x, 1, bit_depth, 2));
127*a67afe4dSAndroid Build Coastguard Worker return;
128*a67afe4dSAndroid Build Coastguard Worker
129*a67afe4dSAndroid Build Coastguard Worker case PNG_COLOR_TYPE_RGB_ALPHA:
130*a67afe4dSAndroid Build Coastguard Worker printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4),
131*a67afe4dSAndroid Build Coastguard Worker component(row, x, 1, bit_depth, 4),
132*a67afe4dSAndroid Build Coastguard Worker component(row, x, 2, bit_depth, 4),
133*a67afe4dSAndroid Build Coastguard Worker component(row, x, 3, bit_depth, 4));
134*a67afe4dSAndroid Build Coastguard Worker return;
135*a67afe4dSAndroid Build Coastguard Worker
136*a67afe4dSAndroid Build Coastguard Worker default:
137*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "pngpixel: invalid color type");
138*a67afe4dSAndroid Build Coastguard Worker }
139*a67afe4dSAndroid Build Coastguard Worker }
140*a67afe4dSAndroid Build Coastguard Worker
main(int argc,const char ** argv)141*a67afe4dSAndroid Build Coastguard Worker int main(int argc, const char **argv)
142*a67afe4dSAndroid Build Coastguard Worker {
143*a67afe4dSAndroid Build Coastguard Worker /* This program uses the default, <setjmp.h> based, libpng error handling
144*a67afe4dSAndroid Build Coastguard Worker * mechanism, therefore any local variable that exists before the call to
145*a67afe4dSAndroid Build Coastguard Worker * setjmp and is changed after the call to setjmp returns successfully must
146*a67afe4dSAndroid Build Coastguard Worker * be declared with 'volatile' to ensure that their values don't get
147*a67afe4dSAndroid Build Coastguard Worker * destroyed by longjmp:
148*a67afe4dSAndroid Build Coastguard Worker */
149*a67afe4dSAndroid Build Coastguard Worker volatile int result = 1/*fail*/;
150*a67afe4dSAndroid Build Coastguard Worker
151*a67afe4dSAndroid Build Coastguard Worker if (argc == 4)
152*a67afe4dSAndroid Build Coastguard Worker {
153*a67afe4dSAndroid Build Coastguard Worker long x = atol(argv[1]);
154*a67afe4dSAndroid Build Coastguard Worker long y = atol(argv[2]);
155*a67afe4dSAndroid Build Coastguard Worker FILE *f = fopen(argv[3], "rb");
156*a67afe4dSAndroid Build Coastguard Worker volatile png_bytep row = NULL;
157*a67afe4dSAndroid Build Coastguard Worker
158*a67afe4dSAndroid Build Coastguard Worker if (f != NULL)
159*a67afe4dSAndroid Build Coastguard Worker {
160*a67afe4dSAndroid Build Coastguard Worker /* libpng requires a callback function for handling errors; this
161*a67afe4dSAndroid Build Coastguard Worker * callback must not return. The default callback function uses a
162*a67afe4dSAndroid Build Coastguard Worker * stored <setjmp.h> style jmp_buf which is held in a png_struct and
163*a67afe4dSAndroid Build Coastguard Worker * writes error messages to stderr. Creating the png_struct is a
164*a67afe4dSAndroid Build Coastguard Worker * little tricky; just copy the following code.
165*a67afe4dSAndroid Build Coastguard Worker */
166*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
167*a67afe4dSAndroid Build Coastguard Worker NULL, NULL, NULL);
168*a67afe4dSAndroid Build Coastguard Worker
169*a67afe4dSAndroid Build Coastguard Worker if (png_ptr != NULL)
170*a67afe4dSAndroid Build Coastguard Worker {
171*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr = png_create_info_struct(png_ptr);
172*a67afe4dSAndroid Build Coastguard Worker
173*a67afe4dSAndroid Build Coastguard Worker if (info_ptr != NULL)
174*a67afe4dSAndroid Build Coastguard Worker {
175*a67afe4dSAndroid Build Coastguard Worker /* Declare stack variables to hold pointers to locally allocated
176*a67afe4dSAndroid Build Coastguard Worker * data.
177*a67afe4dSAndroid Build Coastguard Worker */
178*a67afe4dSAndroid Build Coastguard Worker
179*a67afe4dSAndroid Build Coastguard Worker /* Initialize the error control buffer: */
180*a67afe4dSAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(png_ptr)) == 0)
181*a67afe4dSAndroid Build Coastguard Worker {
182*a67afe4dSAndroid Build Coastguard Worker png_uint_32 width, height;
183*a67afe4dSAndroid Build Coastguard Worker int bit_depth, color_type, interlace_method,
184*a67afe4dSAndroid Build Coastguard Worker compression_method, filter_method;
185*a67afe4dSAndroid Build Coastguard Worker png_bytep row_tmp;
186*a67afe4dSAndroid Build Coastguard Worker
187*a67afe4dSAndroid Build Coastguard Worker /* Now associate the recently opened (FILE*) with the default
188*a67afe4dSAndroid Build Coastguard Worker * libpng initialization functions. Sometimes libpng is
189*a67afe4dSAndroid Build Coastguard Worker * compiled without stdio support (it can be difficult to do
190*a67afe4dSAndroid Build Coastguard Worker * in some environments); in that case you will have to write
191*a67afe4dSAndroid Build Coastguard Worker * your own read callback to read data from the (FILE*).
192*a67afe4dSAndroid Build Coastguard Worker */
193*a67afe4dSAndroid Build Coastguard Worker png_init_io(png_ptr, f);
194*a67afe4dSAndroid Build Coastguard Worker
195*a67afe4dSAndroid Build Coastguard Worker /* And read the first part of the PNG file - the header and
196*a67afe4dSAndroid Build Coastguard Worker * all the information up to the first pixel.
197*a67afe4dSAndroid Build Coastguard Worker */
198*a67afe4dSAndroid Build Coastguard Worker png_read_info(png_ptr, info_ptr);
199*a67afe4dSAndroid Build Coastguard Worker
200*a67afe4dSAndroid Build Coastguard Worker /* This fills in enough information to tell us the width of
201*a67afe4dSAndroid Build Coastguard Worker * each row in bytes, allocate the appropriate amount of
202*a67afe4dSAndroid Build Coastguard Worker * space. In this case png_malloc is used - it will not
203*a67afe4dSAndroid Build Coastguard Worker * return if memory isn't available.
204*a67afe4dSAndroid Build Coastguard Worker */
205*a67afe4dSAndroid Build Coastguard Worker row = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
206*a67afe4dSAndroid Build Coastguard Worker info_ptr));
207*a67afe4dSAndroid Build Coastguard Worker
208*a67afe4dSAndroid Build Coastguard Worker /* To avoid the overhead of using a volatile auto copy row_tmp
209*a67afe4dSAndroid Build Coastguard Worker * to a local here - just use row for the png_free below.
210*a67afe4dSAndroid Build Coastguard Worker */
211*a67afe4dSAndroid Build Coastguard Worker row_tmp = row;
212*a67afe4dSAndroid Build Coastguard Worker
213*a67afe4dSAndroid Build Coastguard Worker /* All the information we need is in the header is returned by
214*a67afe4dSAndroid Build Coastguard Worker * png_get_IHDR, if this fails we can now use 'png_error' to
215*a67afe4dSAndroid Build Coastguard Worker * signal the error and return control to the setjmp above.
216*a67afe4dSAndroid Build Coastguard Worker */
217*a67afe4dSAndroid Build Coastguard Worker if (png_get_IHDR(png_ptr, info_ptr, &width, &height,
218*a67afe4dSAndroid Build Coastguard Worker &bit_depth, &color_type, &interlace_method,
219*a67afe4dSAndroid Build Coastguard Worker &compression_method, &filter_method))
220*a67afe4dSAndroid Build Coastguard Worker {
221*a67afe4dSAndroid Build Coastguard Worker int passes, pass;
222*a67afe4dSAndroid Build Coastguard Worker
223*a67afe4dSAndroid Build Coastguard Worker /* png_set_interlace_handling returns the number of
224*a67afe4dSAndroid Build Coastguard Worker * passes required as well as turning on libpng's
225*a67afe4dSAndroid Build Coastguard Worker * handling, but since we do it ourselves this is
226*a67afe4dSAndroid Build Coastguard Worker * necessary:
227*a67afe4dSAndroid Build Coastguard Worker */
228*a67afe4dSAndroid Build Coastguard Worker switch (interlace_method)
229*a67afe4dSAndroid Build Coastguard Worker {
230*a67afe4dSAndroid Build Coastguard Worker case PNG_INTERLACE_NONE:
231*a67afe4dSAndroid Build Coastguard Worker passes = 1;
232*a67afe4dSAndroid Build Coastguard Worker break;
233*a67afe4dSAndroid Build Coastguard Worker
234*a67afe4dSAndroid Build Coastguard Worker case PNG_INTERLACE_ADAM7:
235*a67afe4dSAndroid Build Coastguard Worker passes = PNG_INTERLACE_ADAM7_PASSES;
236*a67afe4dSAndroid Build Coastguard Worker break;
237*a67afe4dSAndroid Build Coastguard Worker
238*a67afe4dSAndroid Build Coastguard Worker default:
239*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "pngpixel: unknown interlace");
240*a67afe4dSAndroid Build Coastguard Worker }
241*a67afe4dSAndroid Build Coastguard Worker
242*a67afe4dSAndroid Build Coastguard Worker /* Now read the pixels, pass-by-pass, row-by-row: */
243*a67afe4dSAndroid Build Coastguard Worker png_start_read_image(png_ptr);
244*a67afe4dSAndroid Build Coastguard Worker
245*a67afe4dSAndroid Build Coastguard Worker for (pass=0; pass<passes; ++pass)
246*a67afe4dSAndroid Build Coastguard Worker {
247*a67afe4dSAndroid Build Coastguard Worker png_uint_32 ystart, xstart, ystep, xstep;
248*a67afe4dSAndroid Build Coastguard Worker png_uint_32 py;
249*a67afe4dSAndroid Build Coastguard Worker
250*a67afe4dSAndroid Build Coastguard Worker if (interlace_method == PNG_INTERLACE_ADAM7)
251*a67afe4dSAndroid Build Coastguard Worker {
252*a67afe4dSAndroid Build Coastguard Worker /* Sometimes the whole pass is empty because the
253*a67afe4dSAndroid Build Coastguard Worker * image is too narrow or too short. libpng
254*a67afe4dSAndroid Build Coastguard Worker * expects to be called for each row that is
255*a67afe4dSAndroid Build Coastguard Worker * present in the pass, so it may be necessary to
256*a67afe4dSAndroid Build Coastguard Worker * skip the loop below (over py) if the image is
257*a67afe4dSAndroid Build Coastguard Worker * too narrow.
258*a67afe4dSAndroid Build Coastguard Worker */
259*a67afe4dSAndroid Build Coastguard Worker if (PNG_PASS_COLS(width, pass) == 0)
260*a67afe4dSAndroid Build Coastguard Worker continue;
261*a67afe4dSAndroid Build Coastguard Worker
262*a67afe4dSAndroid Build Coastguard Worker /* We need the starting pixel and the offset
263*a67afe4dSAndroid Build Coastguard Worker * between each pixel in this pass; use the macros
264*a67afe4dSAndroid Build Coastguard Worker * in png.h:
265*a67afe4dSAndroid Build Coastguard Worker */
266*a67afe4dSAndroid Build Coastguard Worker xstart = PNG_PASS_START_COL(pass);
267*a67afe4dSAndroid Build Coastguard Worker ystart = PNG_PASS_START_ROW(pass);
268*a67afe4dSAndroid Build Coastguard Worker xstep = PNG_PASS_COL_OFFSET(pass);
269*a67afe4dSAndroid Build Coastguard Worker ystep = PNG_PASS_ROW_OFFSET(pass);
270*a67afe4dSAndroid Build Coastguard Worker }
271*a67afe4dSAndroid Build Coastguard Worker
272*a67afe4dSAndroid Build Coastguard Worker else
273*a67afe4dSAndroid Build Coastguard Worker {
274*a67afe4dSAndroid Build Coastguard Worker ystart = xstart = 0;
275*a67afe4dSAndroid Build Coastguard Worker ystep = xstep = 1;
276*a67afe4dSAndroid Build Coastguard Worker }
277*a67afe4dSAndroid Build Coastguard Worker
278*a67afe4dSAndroid Build Coastguard Worker /* To find the pixel, loop over 'py' for each pass
279*a67afe4dSAndroid Build Coastguard Worker * reading a row and then checking to see if it
280*a67afe4dSAndroid Build Coastguard Worker * contains the pixel.
281*a67afe4dSAndroid Build Coastguard Worker */
282*a67afe4dSAndroid Build Coastguard Worker for (py = ystart; py < height; py += ystep)
283*a67afe4dSAndroid Build Coastguard Worker {
284*a67afe4dSAndroid Build Coastguard Worker png_uint_32 px, ppx;
285*a67afe4dSAndroid Build Coastguard Worker
286*a67afe4dSAndroid Build Coastguard Worker /* png_read_row takes two pointers. When libpng
287*a67afe4dSAndroid Build Coastguard Worker * handles the interlace the first is filled in
288*a67afe4dSAndroid Build Coastguard Worker * pixel-by-pixel, and the second receives the same
289*a67afe4dSAndroid Build Coastguard Worker * pixels but they are replicated across the
290*a67afe4dSAndroid Build Coastguard Worker * unwritten pixels so far for each pass. When we
291*a67afe4dSAndroid Build Coastguard Worker * do the interlace, however, they just contain
292*a67afe4dSAndroid Build Coastguard Worker * the pixels from the interlace pass - giving
293*a67afe4dSAndroid Build Coastguard Worker * both is wasteful and pointless, so we pass a
294*a67afe4dSAndroid Build Coastguard Worker * NULL pointer.
295*a67afe4dSAndroid Build Coastguard Worker */
296*a67afe4dSAndroid Build Coastguard Worker png_read_row(png_ptr, row_tmp, NULL);
297*a67afe4dSAndroid Build Coastguard Worker
298*a67afe4dSAndroid Build Coastguard Worker /* Now find the pixel if it is in this row; there
299*a67afe4dSAndroid Build Coastguard Worker * are, of course, much better ways of doing this
300*a67afe4dSAndroid Build Coastguard Worker * than using a for loop:
301*a67afe4dSAndroid Build Coastguard Worker */
302*a67afe4dSAndroid Build Coastguard Worker if (y == py) for (px = xstart, ppx = 0;
303*a67afe4dSAndroid Build Coastguard Worker px < width; px += xstep, ++ppx) if (x == px)
304*a67afe4dSAndroid Build Coastguard Worker {
305*a67afe4dSAndroid Build Coastguard Worker /* 'ppx' is the index of the pixel in the row
306*a67afe4dSAndroid Build Coastguard Worker * buffer.
307*a67afe4dSAndroid Build Coastguard Worker */
308*a67afe4dSAndroid Build Coastguard Worker print_pixel(png_ptr, info_ptr, row_tmp, ppx);
309*a67afe4dSAndroid Build Coastguard Worker
310*a67afe4dSAndroid Build Coastguard Worker /* Now terminate the loops early - we have
311*a67afe4dSAndroid Build Coastguard Worker * found and handled the required data.
312*a67afe4dSAndroid Build Coastguard Worker */
313*a67afe4dSAndroid Build Coastguard Worker goto pass_loop_end;
314*a67afe4dSAndroid Build Coastguard Worker } /* x loop */
315*a67afe4dSAndroid Build Coastguard Worker } /* y loop */
316*a67afe4dSAndroid Build Coastguard Worker } /* pass loop */
317*a67afe4dSAndroid Build Coastguard Worker
318*a67afe4dSAndroid Build Coastguard Worker /* Finally free the temporary buffer: */
319*a67afe4dSAndroid Build Coastguard Worker pass_loop_end:
320*a67afe4dSAndroid Build Coastguard Worker row = NULL;
321*a67afe4dSAndroid Build Coastguard Worker png_free(png_ptr, row_tmp);
322*a67afe4dSAndroid Build Coastguard Worker }
323*a67afe4dSAndroid Build Coastguard Worker
324*a67afe4dSAndroid Build Coastguard Worker else
325*a67afe4dSAndroid Build Coastguard Worker png_error(png_ptr, "pngpixel: png_get_IHDR failed");
326*a67afe4dSAndroid Build Coastguard Worker
327*a67afe4dSAndroid Build Coastguard Worker }
328*a67afe4dSAndroid Build Coastguard Worker
329*a67afe4dSAndroid Build Coastguard Worker else
330*a67afe4dSAndroid Build Coastguard Worker {
331*a67afe4dSAndroid Build Coastguard Worker /* Else libpng has raised an error. An error message has
332*a67afe4dSAndroid Build Coastguard Worker * already been output, so it is only necessary to clean up
333*a67afe4dSAndroid Build Coastguard Worker * locally allocated data:
334*a67afe4dSAndroid Build Coastguard Worker */
335*a67afe4dSAndroid Build Coastguard Worker if (row != NULL)
336*a67afe4dSAndroid Build Coastguard Worker {
337*a67afe4dSAndroid Build Coastguard Worker /* The default implementation of png_free never errors out
338*a67afe4dSAndroid Build Coastguard Worker * (it just crashes if something goes wrong), but the safe
339*a67afe4dSAndroid Build Coastguard Worker * way of using it is still to clear 'row' before calling
340*a67afe4dSAndroid Build Coastguard Worker * png_free:
341*a67afe4dSAndroid Build Coastguard Worker */
342*a67afe4dSAndroid Build Coastguard Worker png_bytep row_tmp = row;
343*a67afe4dSAndroid Build Coastguard Worker row = NULL;
344*a67afe4dSAndroid Build Coastguard Worker png_free(png_ptr, row_tmp);
345*a67afe4dSAndroid Build Coastguard Worker }
346*a67afe4dSAndroid Build Coastguard Worker }
347*a67afe4dSAndroid Build Coastguard Worker
348*a67afe4dSAndroid Build Coastguard Worker png_destroy_info_struct(png_ptr, &info_ptr);
349*a67afe4dSAndroid Build Coastguard Worker }
350*a67afe4dSAndroid Build Coastguard Worker
351*a67afe4dSAndroid Build Coastguard Worker else
352*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "pngpixel: out of memory allocating png_info\n");
353*a67afe4dSAndroid Build Coastguard Worker
354*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, NULL, NULL);
355*a67afe4dSAndroid Build Coastguard Worker }
356*a67afe4dSAndroid Build Coastguard Worker
357*a67afe4dSAndroid Build Coastguard Worker else
358*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "pngpixel: out of memory allocating png_struct\n");
359*a67afe4dSAndroid Build Coastguard Worker }
360*a67afe4dSAndroid Build Coastguard Worker
361*a67afe4dSAndroid Build Coastguard Worker else
362*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "pngpixel: %s: could not open file\n", argv[3]);
363*a67afe4dSAndroid Build Coastguard Worker }
364*a67afe4dSAndroid Build Coastguard Worker
365*a67afe4dSAndroid Build Coastguard Worker else
366*a67afe4dSAndroid Build Coastguard Worker /* Wrong number of arguments */
367*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "pngpixel: usage: pngpixel x y png-file\n");
368*a67afe4dSAndroid Build Coastguard Worker
369*a67afe4dSAndroid Build Coastguard Worker return result;
370*a67afe4dSAndroid Build Coastguard Worker }
371*a67afe4dSAndroid Build Coastguard Worker #endif /* READ && SEQUENTIAL_READ */
372