xref: /aosp_15_r20/external/libpng/contrib/examples/simpleover.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker /*- simpleover
2*a67afe4dSAndroid Build Coastguard Worker  *
3*a67afe4dSAndroid Build Coastguard Worker  * COPYRIGHT: Written by John Cunningham Bowler, 2015.
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 several PNG files, which should have an alpha channel or transparency
9*a67afe4dSAndroid Build Coastguard Worker  * information, and composite them together to produce one or more 16-bit linear
10*a67afe4dSAndroid Build Coastguard Worker  * RGBA intermediates.  This involves doing the correct 'over' composition to
11*a67afe4dSAndroid Build Coastguard Worker  * combine the alpha channels and corresponding data.
12*a67afe4dSAndroid Build Coastguard Worker  *
13*a67afe4dSAndroid Build Coastguard Worker  * Finally read an output (background) PNG using the 24-bit RGB format (the
14*a67afe4dSAndroid Build Coastguard Worker  * PNG will be composited on green (#00ff00) by default if it has an alpha
15*a67afe4dSAndroid Build Coastguard Worker  * channel), and apply the intermediate image generated above to specified
16*a67afe4dSAndroid Build Coastguard Worker  * locations in the image.
17*a67afe4dSAndroid Build Coastguard Worker  *
18*a67afe4dSAndroid Build Coastguard Worker  * The command line has the general format:
19*a67afe4dSAndroid Build Coastguard Worker  *
20*a67afe4dSAndroid Build Coastguard Worker  *    simpleover <background.png> [output.png]
21*a67afe4dSAndroid Build Coastguard Worker  *        {--sprite=width,height,name {[--at=x,y] {sprite.png}}}
22*a67afe4dSAndroid Build Coastguard Worker  *        {--add=name {x,y}}
23*a67afe4dSAndroid Build Coastguard Worker  *
24*a67afe4dSAndroid Build Coastguard Worker  * The --sprite and --add options may occur multiple times. They are executed
25*a67afe4dSAndroid Build Coastguard Worker  * in order.  --add may refer to any sprite already read.
26*a67afe4dSAndroid Build Coastguard Worker  *
27*a67afe4dSAndroid Build Coastguard Worker  * This code is intended to show how to composite multiple images together
28*a67afe4dSAndroid Build Coastguard Worker  * correctly.  Apart from the libpng Simplified API the only work done in here
29*a67afe4dSAndroid Build Coastguard Worker  * is to combine multiple input PNG images into a single sprite; this involves
30*a67afe4dSAndroid Build Coastguard Worker  * a Porter-Duff 'over' operation and the input PNG images may, as a result,
31*a67afe4dSAndroid Build Coastguard Worker  * be regarded as being layered one on top of the other with the first (leftmost
32*a67afe4dSAndroid Build Coastguard Worker  * on the command line) being at the bottom and the last on the top.
33*a67afe4dSAndroid Build Coastguard Worker  */
34*a67afe4dSAndroid Build Coastguard Worker #include <stddef.h>
35*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
36*a67afe4dSAndroid Build Coastguard Worker #include <string.h>
37*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
38*a67afe4dSAndroid Build Coastguard Worker #include <errno.h>
39*a67afe4dSAndroid Build Coastguard Worker 
40*a67afe4dSAndroid Build Coastguard Worker /* Normally use <png.h> here to get the installed libpng, but this is done to
41*a67afe4dSAndroid Build Coastguard Worker  * ensure the code picks up the local libpng implementation, so long as this
42*a67afe4dSAndroid Build Coastguard Worker  * file is linked against a sufficiently recent libpng (1.6+) it is ok to
43*a67afe4dSAndroid Build Coastguard Worker  * change this to <png.h>:
44*a67afe4dSAndroid Build Coastguard Worker  */
45*a67afe4dSAndroid Build Coastguard Worker #include "../../png.h"
46*a67afe4dSAndroid Build Coastguard Worker 
47*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SIMPLIFIED_READ_SUPPORTED
48*a67afe4dSAndroid Build Coastguard Worker 
49*a67afe4dSAndroid Build Coastguard Worker #define sprite_name_chars 15
50*a67afe4dSAndroid Build Coastguard Worker struct sprite {
51*a67afe4dSAndroid Build Coastguard Worker    FILE         *file;
52*a67afe4dSAndroid Build Coastguard Worker    png_uint_16p  buffer;
53*a67afe4dSAndroid Build Coastguard Worker    unsigned int  width;
54*a67afe4dSAndroid Build Coastguard Worker    unsigned int  height;
55*a67afe4dSAndroid Build Coastguard Worker    char          name[sprite_name_chars+1];
56*a67afe4dSAndroid Build Coastguard Worker };
57*a67afe4dSAndroid Build Coastguard Worker 
58*a67afe4dSAndroid Build Coastguard Worker #if 0 /* div by 65535 test program */
59*a67afe4dSAndroid Build Coastguard Worker #include <math.h>
60*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
61*a67afe4dSAndroid Build Coastguard Worker 
62*a67afe4dSAndroid Build Coastguard Worker int main(void) {
63*a67afe4dSAndroid Build Coastguard Worker    double err = 0;
64*a67afe4dSAndroid Build Coastguard Worker    unsigned int xerr = 0;
65*a67afe4dSAndroid Build Coastguard Worker    unsigned int r = 32769;
66*a67afe4dSAndroid Build Coastguard Worker    {
67*a67afe4dSAndroid Build Coastguard Worker       unsigned int x = 0;
68*a67afe4dSAndroid Build Coastguard Worker 
69*a67afe4dSAndroid Build Coastguard Worker       do {
70*a67afe4dSAndroid Build Coastguard Worker          unsigned int t = x + (x >> 16) /*+ (x >> 31)*/ + r;
71*a67afe4dSAndroid Build Coastguard Worker          double v = x, errtest;
72*a67afe4dSAndroid Build Coastguard Worker 
73*a67afe4dSAndroid Build Coastguard Worker          if (t < x) {
74*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "overflow: %u+%u -> %u\n", x, r, t);
75*a67afe4dSAndroid Build Coastguard Worker             return 1;
76*a67afe4dSAndroid Build Coastguard Worker          }
77*a67afe4dSAndroid Build Coastguard Worker 
78*a67afe4dSAndroid Build Coastguard Worker          v /= 65535;
79*a67afe4dSAndroid Build Coastguard Worker          errtest = v;
80*a67afe4dSAndroid Build Coastguard Worker          t >>= 16;
81*a67afe4dSAndroid Build Coastguard Worker          errtest -= t;
82*a67afe4dSAndroid Build Coastguard Worker 
83*a67afe4dSAndroid Build Coastguard Worker          if (errtest > err) {
84*a67afe4dSAndroid Build Coastguard Worker             err = errtest;
85*a67afe4dSAndroid Build Coastguard Worker             xerr = x;
86*a67afe4dSAndroid Build Coastguard Worker 
87*a67afe4dSAndroid Build Coastguard Worker             if (errtest >= .5) {
88*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "error: %u/65535 = %f, not %u, error %f\n",
89*a67afe4dSAndroid Build Coastguard Worker                      x, v, t, errtest);
90*a67afe4dSAndroid Build Coastguard Worker                return 0;
91*a67afe4dSAndroid Build Coastguard Worker             }
92*a67afe4dSAndroid Build Coastguard Worker          }
93*a67afe4dSAndroid Build Coastguard Worker       } while (++x <= 65535U*65535U);
94*a67afe4dSAndroid Build Coastguard Worker    }
95*a67afe4dSAndroid Build Coastguard Worker 
96*a67afe4dSAndroid Build Coastguard Worker    printf("error %f @ %u\n", err, xerr);
97*a67afe4dSAndroid Build Coastguard Worker 
98*a67afe4dSAndroid Build Coastguard Worker    return 0;
99*a67afe4dSAndroid Build Coastguard Worker }
100*a67afe4dSAndroid Build Coastguard Worker #endif /* div by 65535 test program */
101*a67afe4dSAndroid Build Coastguard Worker 
102*a67afe4dSAndroid Build Coastguard Worker static void
sprite_op(const struct sprite * sprite,int x_offset,int y_offset,png_imagep image,const png_uint_16 * buffer)103*a67afe4dSAndroid Build Coastguard Worker sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
104*a67afe4dSAndroid Build Coastguard Worker    png_imagep image, const png_uint_16 *buffer)
105*a67afe4dSAndroid Build Coastguard Worker {
106*a67afe4dSAndroid Build Coastguard Worker    /* This is where the Porter-Duff 'Over' operator is evaluated; change this
107*a67afe4dSAndroid Build Coastguard Worker     * code to change the operator (this could be parameterized).  Any other
108*a67afe4dSAndroid Build Coastguard Worker     * image processing operation could be used here.
109*a67afe4dSAndroid Build Coastguard Worker     */
110*a67afe4dSAndroid Build Coastguard Worker 
111*a67afe4dSAndroid Build Coastguard Worker 
112*a67afe4dSAndroid Build Coastguard Worker    /* Check for an x or y offset that pushes any part of the image beyond the
113*a67afe4dSAndroid Build Coastguard Worker     * right or bottom of the sprite:
114*a67afe4dSAndroid Build Coastguard Worker     */
115*a67afe4dSAndroid Build Coastguard Worker    if ((y_offset < 0 || (unsigned)/*SAFE*/y_offset < sprite->height) &&
116*a67afe4dSAndroid Build Coastguard Worker        (x_offset < 0 || (unsigned)/*SAFE*/x_offset < sprite->width))
117*a67afe4dSAndroid Build Coastguard Worker    {
118*a67afe4dSAndroid Build Coastguard Worker       unsigned int y = 0;
119*a67afe4dSAndroid Build Coastguard Worker 
120*a67afe4dSAndroid Build Coastguard Worker       if (y_offset < 0)
121*a67afe4dSAndroid Build Coastguard Worker          y = -y_offset; /* Skip to first visible row */
122*a67afe4dSAndroid Build Coastguard Worker 
123*a67afe4dSAndroid Build Coastguard Worker       do
124*a67afe4dSAndroid Build Coastguard Worker       {
125*a67afe4dSAndroid Build Coastguard Worker          unsigned int x = 0;
126*a67afe4dSAndroid Build Coastguard Worker 
127*a67afe4dSAndroid Build Coastguard Worker          if (x_offset < 0)
128*a67afe4dSAndroid Build Coastguard Worker             x = -x_offset;
129*a67afe4dSAndroid Build Coastguard Worker 
130*a67afe4dSAndroid Build Coastguard Worker          do
131*a67afe4dSAndroid Build Coastguard Worker          {
132*a67afe4dSAndroid Build Coastguard Worker             /* In and out are RGBA values, so: */
133*a67afe4dSAndroid Build Coastguard Worker             const png_uint_16 *in_pixel = buffer + (y * image->width + x)*4;
134*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 in_alpha = in_pixel[3];
135*a67afe4dSAndroid Build Coastguard Worker 
136*a67afe4dSAndroid Build Coastguard Worker             /* This is the optimized Porter-Duff 'Over' operation, when the
137*a67afe4dSAndroid Build Coastguard Worker              * input alpha is 0 the output is not changed.
138*a67afe4dSAndroid Build Coastguard Worker              */
139*a67afe4dSAndroid Build Coastguard Worker             if (in_alpha > 0)
140*a67afe4dSAndroid Build Coastguard Worker             {
141*a67afe4dSAndroid Build Coastguard Worker                png_uint_16 *out_pixel = sprite->buffer +
142*a67afe4dSAndroid Build Coastguard Worker                   ((y+y_offset) * sprite->width + (x+x_offset))*4;
143*a67afe4dSAndroid Build Coastguard Worker 
144*a67afe4dSAndroid Build Coastguard Worker                /* This is the weight to apply to the output: */
145*a67afe4dSAndroid Build Coastguard Worker                in_alpha = 65535-in_alpha;
146*a67afe4dSAndroid Build Coastguard Worker 
147*a67afe4dSAndroid Build Coastguard Worker                if (in_alpha > 0)
148*a67afe4dSAndroid Build Coastguard Worker                {
149*a67afe4dSAndroid Build Coastguard Worker                   /* The input must be composed onto the output. This means
150*a67afe4dSAndroid Build Coastguard Worker                    * multiplying the current output pixel value by the inverse
151*a67afe4dSAndroid Build Coastguard Worker                    * of the input alpha (1-alpha). A division is required but
152*a67afe4dSAndroid Build Coastguard Worker                    * it is by the constant 65535.  Approximate this as:
153*a67afe4dSAndroid Build Coastguard Worker                    *
154*a67afe4dSAndroid Build Coastguard Worker                    *     (x + (x >> 16) + 32769) >> 16;
155*a67afe4dSAndroid Build Coastguard Worker                    *
156*a67afe4dSAndroid Build Coastguard Worker                    * This is exact (and does not overflow) for all values of
157*a67afe4dSAndroid Build Coastguard Worker                    * x in the range 0..65535*65535.  (Note that the calculation
158*a67afe4dSAndroid Build Coastguard Worker                    * produces the closest integer; the maximum error is <0.5).
159*a67afe4dSAndroid Build Coastguard Worker                    */
160*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 tmp;
161*a67afe4dSAndroid Build Coastguard Worker 
162*a67afe4dSAndroid Build Coastguard Worker #                 define compose(c)\
163*a67afe4dSAndroid Build Coastguard Worker                      tmp = out_pixel[c] * in_alpha;\
164*a67afe4dSAndroid Build Coastguard Worker                      tmp = (tmp + (tmp >> 16) + 32769) >> 16;\
165*a67afe4dSAndroid Build Coastguard Worker                      out_pixel[c] = tmp + in_pixel[c]
166*a67afe4dSAndroid Build Coastguard Worker 
167*a67afe4dSAndroid Build Coastguard Worker                   /* The following is very vectorizable... */
168*a67afe4dSAndroid Build Coastguard Worker                   compose(0);
169*a67afe4dSAndroid Build Coastguard Worker                   compose(1);
170*a67afe4dSAndroid Build Coastguard Worker                   compose(2);
171*a67afe4dSAndroid Build Coastguard Worker                   compose(3);
172*a67afe4dSAndroid Build Coastguard Worker                }
173*a67afe4dSAndroid Build Coastguard Worker 
174*a67afe4dSAndroid Build Coastguard Worker                else
175*a67afe4dSAndroid Build Coastguard Worker                   out_pixel[0] = in_pixel[0],
176*a67afe4dSAndroid Build Coastguard Worker                   out_pixel[1] = in_pixel[1],
177*a67afe4dSAndroid Build Coastguard Worker                   out_pixel[2] = in_pixel[2],
178*a67afe4dSAndroid Build Coastguard Worker                   out_pixel[3] = in_pixel[3];
179*a67afe4dSAndroid Build Coastguard Worker             }
180*a67afe4dSAndroid Build Coastguard Worker          }
181*a67afe4dSAndroid Build Coastguard Worker          while (++x < image->width);
182*a67afe4dSAndroid Build Coastguard Worker       }
183*a67afe4dSAndroid Build Coastguard Worker       while (++y < image->height);
184*a67afe4dSAndroid Build Coastguard Worker    }
185*a67afe4dSAndroid Build Coastguard Worker }
186*a67afe4dSAndroid Build Coastguard Worker 
187*a67afe4dSAndroid Build Coastguard Worker static int
create_sprite(struct sprite * sprite,int * argc,const char *** argv)188*a67afe4dSAndroid Build Coastguard Worker create_sprite(struct sprite *sprite, int *argc, const char ***argv)
189*a67afe4dSAndroid Build Coastguard Worker {
190*a67afe4dSAndroid Build Coastguard Worker    /* Read the arguments and create this sprite. The sprite buffer has already
191*a67afe4dSAndroid Build Coastguard Worker     * been allocated. This reads the input PNGs one by one in linear format,
192*a67afe4dSAndroid Build Coastguard Worker     * composes them onto the sprite buffer (the code in the function above)
193*a67afe4dSAndroid Build Coastguard Worker     * then saves the result, converting it on the fly to PNG RGBA 8-bit format.
194*a67afe4dSAndroid Build Coastguard Worker     */
195*a67afe4dSAndroid Build Coastguard Worker    while (*argc > 0)
196*a67afe4dSAndroid Build Coastguard Worker    {
197*a67afe4dSAndroid Build Coastguard Worker       char tombstone;
198*a67afe4dSAndroid Build Coastguard Worker       int x = 0, y = 0;
199*a67afe4dSAndroid Build Coastguard Worker 
200*a67afe4dSAndroid Build Coastguard Worker       if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
201*a67afe4dSAndroid Build Coastguard Worker       {
202*a67afe4dSAndroid Build Coastguard Worker          /* The only supported option is --at. */
203*a67afe4dSAndroid Build Coastguard Worker          if (sscanf((*argv)[0], "--at=%d,%d%c", &x, &y, &tombstone) != 2)
204*a67afe4dSAndroid Build Coastguard Worker             break; /* success; caller will parse this option */
205*a67afe4dSAndroid Build Coastguard Worker 
206*a67afe4dSAndroid Build Coastguard Worker          ++*argv, --*argc;
207*a67afe4dSAndroid Build Coastguard Worker       }
208*a67afe4dSAndroid Build Coastguard Worker 
209*a67afe4dSAndroid Build Coastguard Worker       else
210*a67afe4dSAndroid Build Coastguard Worker       {
211*a67afe4dSAndroid Build Coastguard Worker          /* The argument has to be a file name */
212*a67afe4dSAndroid Build Coastguard Worker          png_image image;
213*a67afe4dSAndroid Build Coastguard Worker 
214*a67afe4dSAndroid Build Coastguard Worker          image.version = PNG_IMAGE_VERSION;
215*a67afe4dSAndroid Build Coastguard Worker          image.opaque = NULL;
216*a67afe4dSAndroid Build Coastguard Worker 
217*a67afe4dSAndroid Build Coastguard Worker          if (png_image_begin_read_from_file(&image, (*argv)[0]))
218*a67afe4dSAndroid Build Coastguard Worker          {
219*a67afe4dSAndroid Build Coastguard Worker             png_uint_16p buffer;
220*a67afe4dSAndroid Build Coastguard Worker 
221*a67afe4dSAndroid Build Coastguard Worker             image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
222*a67afe4dSAndroid Build Coastguard Worker 
223*a67afe4dSAndroid Build Coastguard Worker             buffer = malloc(PNG_IMAGE_SIZE(image));
224*a67afe4dSAndroid Build Coastguard Worker 
225*a67afe4dSAndroid Build Coastguard Worker             if (buffer != NULL)
226*a67afe4dSAndroid Build Coastguard Worker             {
227*a67afe4dSAndroid Build Coastguard Worker                if (png_image_finish_read(&image, NULL/*background*/, buffer,
228*a67afe4dSAndroid Build Coastguard Worker                   0/*row_stride*/,
229*a67afe4dSAndroid Build Coastguard Worker                   NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
230*a67afe4dSAndroid Build Coastguard Worker                {
231*a67afe4dSAndroid Build Coastguard Worker                   /* This is the place where the Porter-Duff 'Over' operator
232*a67afe4dSAndroid Build Coastguard Worker                    * needs to be done by this code.  In fact, any image
233*a67afe4dSAndroid Build Coastguard Worker                    * processing required can be done here; the data is in
234*a67afe4dSAndroid Build Coastguard Worker                    * the correct format (linear, 16-bit) and source and
235*a67afe4dSAndroid Build Coastguard Worker                    * destination are in memory.
236*a67afe4dSAndroid Build Coastguard Worker                    */
237*a67afe4dSAndroid Build Coastguard Worker                   sprite_op(sprite, x, y, &image, buffer);
238*a67afe4dSAndroid Build Coastguard Worker                   free(buffer);
239*a67afe4dSAndroid Build Coastguard Worker                   ++*argv, --*argc;
240*a67afe4dSAndroid Build Coastguard Worker                   /* And continue to the next argument */
241*a67afe4dSAndroid Build Coastguard Worker                   continue;
242*a67afe4dSAndroid Build Coastguard Worker                }
243*a67afe4dSAndroid Build Coastguard Worker 
244*a67afe4dSAndroid Build Coastguard Worker                else
245*a67afe4dSAndroid Build Coastguard Worker                {
246*a67afe4dSAndroid Build Coastguard Worker                   free(buffer);
247*a67afe4dSAndroid Build Coastguard Worker                   fprintf(stderr, "simpleover: read %s: %s\n", (*argv)[0],
248*a67afe4dSAndroid Build Coastguard Worker                       image.message);
249*a67afe4dSAndroid Build Coastguard Worker                }
250*a67afe4dSAndroid Build Coastguard Worker             }
251*a67afe4dSAndroid Build Coastguard Worker 
252*a67afe4dSAndroid Build Coastguard Worker             else
253*a67afe4dSAndroid Build Coastguard Worker             {
254*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
255*a67afe4dSAndroid Build Coastguard Worker                   (unsigned long)PNG_IMAGE_SIZE(image));
256*a67afe4dSAndroid Build Coastguard Worker 
257*a67afe4dSAndroid Build Coastguard Worker                /* png_image_free must be called if we abort the Simplified API
258*a67afe4dSAndroid Build Coastguard Worker                 * read because of a problem detected in this code.  If problems
259*a67afe4dSAndroid Build Coastguard Worker                 * are detected in the Simplified API it cleans up itself.
260*a67afe4dSAndroid Build Coastguard Worker                 */
261*a67afe4dSAndroid Build Coastguard Worker                png_image_free(&image);
262*a67afe4dSAndroid Build Coastguard Worker             }
263*a67afe4dSAndroid Build Coastguard Worker          }
264*a67afe4dSAndroid Build Coastguard Worker 
265*a67afe4dSAndroid Build Coastguard Worker          else
266*a67afe4dSAndroid Build Coastguard Worker          {
267*a67afe4dSAndroid Build Coastguard Worker             /* Failed to read the first argument: */
268*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: %s: %s\n", (*argv)[0], image.message);
269*a67afe4dSAndroid Build Coastguard Worker          }
270*a67afe4dSAndroid Build Coastguard Worker 
271*a67afe4dSAndroid Build Coastguard Worker          return 0; /* failure */
272*a67afe4dSAndroid Build Coastguard Worker       }
273*a67afe4dSAndroid Build Coastguard Worker    }
274*a67afe4dSAndroid Build Coastguard Worker 
275*a67afe4dSAndroid Build Coastguard Worker    /* All the sprite operations have completed successfully. Save the RGBA
276*a67afe4dSAndroid Build Coastguard Worker     * buffer as a PNG using the simplified write API.
277*a67afe4dSAndroid Build Coastguard Worker     */
278*a67afe4dSAndroid Build Coastguard Worker    sprite->file = tmpfile();
279*a67afe4dSAndroid Build Coastguard Worker 
280*a67afe4dSAndroid Build Coastguard Worker    if (sprite->file != NULL)
281*a67afe4dSAndroid Build Coastguard Worker    {
282*a67afe4dSAndroid Build Coastguard Worker       png_image save;
283*a67afe4dSAndroid Build Coastguard Worker 
284*a67afe4dSAndroid Build Coastguard Worker       memset(&save, 0, sizeof save);
285*a67afe4dSAndroid Build Coastguard Worker       save.version = PNG_IMAGE_VERSION;
286*a67afe4dSAndroid Build Coastguard Worker       save.opaque = NULL;
287*a67afe4dSAndroid Build Coastguard Worker       save.width = sprite->width;
288*a67afe4dSAndroid Build Coastguard Worker       save.height = sprite->height;
289*a67afe4dSAndroid Build Coastguard Worker       save.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
290*a67afe4dSAndroid Build Coastguard Worker       save.flags = PNG_IMAGE_FLAG_FAST;
291*a67afe4dSAndroid Build Coastguard Worker       save.colormap_entries = 0;
292*a67afe4dSAndroid Build Coastguard Worker 
293*a67afe4dSAndroid Build Coastguard Worker       if (png_image_write_to_stdio(&save, sprite->file, 1/*convert_to_8_bit*/,
294*a67afe4dSAndroid Build Coastguard Worker           sprite->buffer, 0/*row_stride*/, NULL/*colormap*/))
295*a67afe4dSAndroid Build Coastguard Worker       {
296*a67afe4dSAndroid Build Coastguard Worker          /* Success; the buffer is no longer needed: */
297*a67afe4dSAndroid Build Coastguard Worker          free(sprite->buffer);
298*a67afe4dSAndroid Build Coastguard Worker          sprite->buffer = NULL;
299*a67afe4dSAndroid Build Coastguard Worker          return 1; /* ok */
300*a67afe4dSAndroid Build Coastguard Worker       }
301*a67afe4dSAndroid Build Coastguard Worker 
302*a67afe4dSAndroid Build Coastguard Worker       else
303*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "simpleover: write sprite %s: %s\n", sprite->name,
304*a67afe4dSAndroid Build Coastguard Worker             save.message);
305*a67afe4dSAndroid Build Coastguard Worker    }
306*a67afe4dSAndroid Build Coastguard Worker 
307*a67afe4dSAndroid Build Coastguard Worker    else
308*a67afe4dSAndroid Build Coastguard Worker       fprintf(stderr, "simpleover: sprite %s: could not allocate tmpfile: %s\n",
309*a67afe4dSAndroid Build Coastguard Worker          sprite->name, strerror(errno));
310*a67afe4dSAndroid Build Coastguard Worker 
311*a67afe4dSAndroid Build Coastguard Worker    return 0; /* fail */
312*a67afe4dSAndroid Build Coastguard Worker }
313*a67afe4dSAndroid Build Coastguard Worker 
314*a67afe4dSAndroid Build Coastguard Worker static int
add_sprite(png_imagep output,png_bytep out_buf,struct sprite * sprite,int * argc,const char *** argv)315*a67afe4dSAndroid Build Coastguard Worker add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
316*a67afe4dSAndroid Build Coastguard Worker    int *argc, const char ***argv)
317*a67afe4dSAndroid Build Coastguard Worker {
318*a67afe4dSAndroid Build Coastguard Worker    /* Given a --add argument naming this sprite, perform the operations listed
319*a67afe4dSAndroid Build Coastguard Worker     * in the following arguments.  The arguments are expected to have the form
320*a67afe4dSAndroid Build Coastguard Worker     * (x,y), which is just an offset at which to add the sprite to the
321*a67afe4dSAndroid Build Coastguard Worker     * output.
322*a67afe4dSAndroid Build Coastguard Worker     */
323*a67afe4dSAndroid Build Coastguard Worker    while (*argc > 0)
324*a67afe4dSAndroid Build Coastguard Worker    {
325*a67afe4dSAndroid Build Coastguard Worker       char tombstone;
326*a67afe4dSAndroid Build Coastguard Worker       int x, y;
327*a67afe4dSAndroid Build Coastguard Worker 
328*a67afe4dSAndroid Build Coastguard Worker       if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-')
329*a67afe4dSAndroid Build Coastguard Worker          return 1; /* success */
330*a67afe4dSAndroid Build Coastguard Worker 
331*a67afe4dSAndroid Build Coastguard Worker       if (sscanf((*argv)[0], "%d,%d%c", &x, &y, &tombstone) == 2)
332*a67afe4dSAndroid Build Coastguard Worker       {
333*a67afe4dSAndroid Build Coastguard Worker          /* Now add the new image into the sprite data, but only if it
334*a67afe4dSAndroid Build Coastguard Worker           * will fit.
335*a67afe4dSAndroid Build Coastguard Worker           */
336*a67afe4dSAndroid Build Coastguard Worker          if (x < 0 || y < 0 ||
337*a67afe4dSAndroid Build Coastguard Worker              (unsigned)/*SAFE*/x >= output->width ||
338*a67afe4dSAndroid Build Coastguard Worker              (unsigned)/*SAFE*/y >= output->height ||
339*a67afe4dSAndroid Build Coastguard Worker              sprite->width > output->width-x ||
340*a67afe4dSAndroid Build Coastguard Worker              sprite->height > output->height-y)
341*a67afe4dSAndroid Build Coastguard Worker          {
342*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: sprite %s @ (%d,%d) outside image\n",
343*a67afe4dSAndroid Build Coastguard Worker                sprite->name, x, y);
344*a67afe4dSAndroid Build Coastguard Worker             /* Could just skip this, but for the moment it is an error */
345*a67afe4dSAndroid Build Coastguard Worker             return 0; /* error */
346*a67afe4dSAndroid Build Coastguard Worker          }
347*a67afe4dSAndroid Build Coastguard Worker 
348*a67afe4dSAndroid Build Coastguard Worker          else
349*a67afe4dSAndroid Build Coastguard Worker          {
350*a67afe4dSAndroid Build Coastguard Worker             /* Since we know the sprite fits we can just read it into the
351*a67afe4dSAndroid Build Coastguard Worker              * output using the simplified API.
352*a67afe4dSAndroid Build Coastguard Worker              */
353*a67afe4dSAndroid Build Coastguard Worker             png_image in;
354*a67afe4dSAndroid Build Coastguard Worker 
355*a67afe4dSAndroid Build Coastguard Worker             in.version = PNG_IMAGE_VERSION;
356*a67afe4dSAndroid Build Coastguard Worker             rewind(sprite->file);
357*a67afe4dSAndroid Build Coastguard Worker 
358*a67afe4dSAndroid Build Coastguard Worker             if (png_image_begin_read_from_stdio(&in, sprite->file))
359*a67afe4dSAndroid Build Coastguard Worker             {
360*a67afe4dSAndroid Build Coastguard Worker                in.format = PNG_FORMAT_RGB; /* force compose */
361*a67afe4dSAndroid Build Coastguard Worker 
362*a67afe4dSAndroid Build Coastguard Worker                if (png_image_finish_read(&in, NULL/*background*/,
363*a67afe4dSAndroid Build Coastguard Worker                   out_buf + (y*output->width + x)*3/*RGB*/,
364*a67afe4dSAndroid Build Coastguard Worker                   output->width*3/*row_stride*/,
365*a67afe4dSAndroid Build Coastguard Worker                   NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
366*a67afe4dSAndroid Build Coastguard Worker                {
367*a67afe4dSAndroid Build Coastguard Worker                   ++*argv, --*argc;
368*a67afe4dSAndroid Build Coastguard Worker                   continue;
369*a67afe4dSAndroid Build Coastguard Worker                }
370*a67afe4dSAndroid Build Coastguard Worker             }
371*a67afe4dSAndroid Build Coastguard Worker 
372*a67afe4dSAndroid Build Coastguard Worker             /* The read failed: */
373*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: add sprite %s: %s\n", sprite->name,
374*a67afe4dSAndroid Build Coastguard Worker                 in.message);
375*a67afe4dSAndroid Build Coastguard Worker             return 0; /* error */
376*a67afe4dSAndroid Build Coastguard Worker          }
377*a67afe4dSAndroid Build Coastguard Worker       }
378*a67afe4dSAndroid Build Coastguard Worker 
379*a67afe4dSAndroid Build Coastguard Worker       else
380*a67afe4dSAndroid Build Coastguard Worker       {
381*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "simpleover: --add='%s': invalid position %s\n",
382*a67afe4dSAndroid Build Coastguard Worker                sprite->name, (*argv)[0]);
383*a67afe4dSAndroid Build Coastguard Worker          return 0; /* error */
384*a67afe4dSAndroid Build Coastguard Worker       }
385*a67afe4dSAndroid Build Coastguard Worker    }
386*a67afe4dSAndroid Build Coastguard Worker 
387*a67afe4dSAndroid Build Coastguard Worker    return 1; /* ok */
388*a67afe4dSAndroid Build Coastguard Worker }
389*a67afe4dSAndroid Build Coastguard Worker 
390*a67afe4dSAndroid Build Coastguard Worker static int
simpleover_process(png_imagep output,png_bytep out_buf,int argc,const char ** argv)391*a67afe4dSAndroid Build Coastguard Worker simpleover_process(png_imagep output, png_bytep out_buf, int argc,
392*a67afe4dSAndroid Build Coastguard Worker    const char **argv)
393*a67afe4dSAndroid Build Coastguard Worker {
394*a67afe4dSAndroid Build Coastguard Worker    int result = 1; /* success */
395*a67afe4dSAndroid Build Coastguard Worker #  define csprites 10/*limit*/
396*a67afe4dSAndroid Build Coastguard Worker #  define str(a) #a
397*a67afe4dSAndroid Build Coastguard Worker    int nsprites = 0;
398*a67afe4dSAndroid Build Coastguard Worker    struct sprite sprites[csprites];
399*a67afe4dSAndroid Build Coastguard Worker 
400*a67afe4dSAndroid Build Coastguard Worker    while (argc > 0)
401*a67afe4dSAndroid Build Coastguard Worker    {
402*a67afe4dSAndroid Build Coastguard Worker       result = 0; /* fail */
403*a67afe4dSAndroid Build Coastguard Worker 
404*a67afe4dSAndroid Build Coastguard Worker       if (strncmp(argv[0], "--sprite=", 9) == 0)
405*a67afe4dSAndroid Build Coastguard Worker       {
406*a67afe4dSAndroid Build Coastguard Worker          char tombstone;
407*a67afe4dSAndroid Build Coastguard Worker 
408*a67afe4dSAndroid Build Coastguard Worker          if (nsprites < csprites)
409*a67afe4dSAndroid Build Coastguard Worker          {
410*a67afe4dSAndroid Build Coastguard Worker             int n;
411*a67afe4dSAndroid Build Coastguard Worker 
412*a67afe4dSAndroid Build Coastguard Worker             sprites[nsprites].width = sprites[nsprites].height = 0;
413*a67afe4dSAndroid Build Coastguard Worker             sprites[nsprites].name[0] = 0;
414*a67afe4dSAndroid Build Coastguard Worker 
415*a67afe4dSAndroid Build Coastguard Worker             n = sscanf(argv[0], "--sprite=%u,%u,%" str(sprite_name_chars) "s%c",
416*a67afe4dSAndroid Build Coastguard Worker                 &sprites[nsprites].width, &sprites[nsprites].height,
417*a67afe4dSAndroid Build Coastguard Worker                 sprites[nsprites].name, &tombstone);
418*a67afe4dSAndroid Build Coastguard Worker 
419*a67afe4dSAndroid Build Coastguard Worker             if ((n == 2 || n == 3) &&
420*a67afe4dSAndroid Build Coastguard Worker                 sprites[nsprites].width > 0 && sprites[nsprites].height > 0)
421*a67afe4dSAndroid Build Coastguard Worker             {
422*a67afe4dSAndroid Build Coastguard Worker                size_t buf_size, tmp;
423*a67afe4dSAndroid Build Coastguard Worker 
424*a67afe4dSAndroid Build Coastguard Worker                /* Default a name if not given. */
425*a67afe4dSAndroid Build Coastguard Worker                if (sprites[nsprites].name[0] == 0)
426*a67afe4dSAndroid Build Coastguard Worker                   sprintf(sprites[nsprites].name, "sprite-%d", nsprites+1);
427*a67afe4dSAndroid Build Coastguard Worker 
428*a67afe4dSAndroid Build Coastguard Worker                /* Allocate a buffer for the sprite and calculate the buffer
429*a67afe4dSAndroid Build Coastguard Worker                 * size:
430*a67afe4dSAndroid Build Coastguard Worker                 */
431*a67afe4dSAndroid Build Coastguard Worker                buf_size = sizeof (png_uint_16 [4]);
432*a67afe4dSAndroid Build Coastguard Worker                buf_size *= sprites[nsprites].width;
433*a67afe4dSAndroid Build Coastguard Worker                buf_size *= sprites[nsprites].height;
434*a67afe4dSAndroid Build Coastguard Worker 
435*a67afe4dSAndroid Build Coastguard Worker                /* This can overflow a (size_t); check for this: */
436*a67afe4dSAndroid Build Coastguard Worker                tmp = buf_size;
437*a67afe4dSAndroid Build Coastguard Worker                tmp /= sprites[nsprites].width;
438*a67afe4dSAndroid Build Coastguard Worker                tmp /= sprites[nsprites].height;
439*a67afe4dSAndroid Build Coastguard Worker 
440*a67afe4dSAndroid Build Coastguard Worker                if (tmp == sizeof (png_uint_16 [4]))
441*a67afe4dSAndroid Build Coastguard Worker                {
442*a67afe4dSAndroid Build Coastguard Worker                   sprites[nsprites].buffer = malloc(buf_size);
443*a67afe4dSAndroid Build Coastguard Worker                   /* This buffer must be initialized to transparent: */
444*a67afe4dSAndroid Build Coastguard Worker                   memset(sprites[nsprites].buffer, 0, buf_size);
445*a67afe4dSAndroid Build Coastguard Worker 
446*a67afe4dSAndroid Build Coastguard Worker                   if (sprites[nsprites].buffer != NULL)
447*a67afe4dSAndroid Build Coastguard Worker                   {
448*a67afe4dSAndroid Build Coastguard Worker                      sprites[nsprites].file = NULL;
449*a67afe4dSAndroid Build Coastguard Worker                      ++argv, --argc;
450*a67afe4dSAndroid Build Coastguard Worker 
451*a67afe4dSAndroid Build Coastguard Worker                      if (create_sprite(sprites+nsprites++, &argc, &argv))
452*a67afe4dSAndroid Build Coastguard Worker                      {
453*a67afe4dSAndroid Build Coastguard Worker                         result = 1; /* still ok */
454*a67afe4dSAndroid Build Coastguard Worker                         continue;
455*a67afe4dSAndroid Build Coastguard Worker                      }
456*a67afe4dSAndroid Build Coastguard Worker 
457*a67afe4dSAndroid Build Coastguard Worker                      break; /* error */
458*a67afe4dSAndroid Build Coastguard Worker                   }
459*a67afe4dSAndroid Build Coastguard Worker                }
460*a67afe4dSAndroid Build Coastguard Worker 
461*a67afe4dSAndroid Build Coastguard Worker                /* Overflow, or OOM */
462*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "simpleover: %s: sprite too large\n", argv[0]);
463*a67afe4dSAndroid Build Coastguard Worker                break;
464*a67afe4dSAndroid Build Coastguard Worker             }
465*a67afe4dSAndroid Build Coastguard Worker 
466*a67afe4dSAndroid Build Coastguard Worker             else
467*a67afe4dSAndroid Build Coastguard Worker             {
468*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "simpleover: %s: invalid sprite (%u,%u)\n",
469*a67afe4dSAndroid Build Coastguard Worker                   argv[0], sprites[nsprites].width, sprites[nsprites].height);
470*a67afe4dSAndroid Build Coastguard Worker                break;
471*a67afe4dSAndroid Build Coastguard Worker             }
472*a67afe4dSAndroid Build Coastguard Worker          }
473*a67afe4dSAndroid Build Coastguard Worker 
474*a67afe4dSAndroid Build Coastguard Worker          else
475*a67afe4dSAndroid Build Coastguard Worker          {
476*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: %s: too many sprites\n", argv[0]);
477*a67afe4dSAndroid Build Coastguard Worker             break;
478*a67afe4dSAndroid Build Coastguard Worker          }
479*a67afe4dSAndroid Build Coastguard Worker       }
480*a67afe4dSAndroid Build Coastguard Worker 
481*a67afe4dSAndroid Build Coastguard Worker       else if (strncmp(argv[0], "--add=", 6) == 0)
482*a67afe4dSAndroid Build Coastguard Worker       {
483*a67afe4dSAndroid Build Coastguard Worker          const char *name = argv[0]+6;
484*a67afe4dSAndroid Build Coastguard Worker          int isprite = nsprites;
485*a67afe4dSAndroid Build Coastguard Worker 
486*a67afe4dSAndroid Build Coastguard Worker          ++argv, --argc;
487*a67afe4dSAndroid Build Coastguard Worker 
488*a67afe4dSAndroid Build Coastguard Worker          while (--isprite >= 0)
489*a67afe4dSAndroid Build Coastguard Worker          {
490*a67afe4dSAndroid Build Coastguard Worker             if (strcmp(sprites[isprite].name, name) == 0)
491*a67afe4dSAndroid Build Coastguard Worker             {
492*a67afe4dSAndroid Build Coastguard Worker                if (!add_sprite(output, out_buf, sprites+isprite, &argc, &argv))
493*a67afe4dSAndroid Build Coastguard Worker                   goto out; /* error in add_sprite */
494*a67afe4dSAndroid Build Coastguard Worker 
495*a67afe4dSAndroid Build Coastguard Worker                break;
496*a67afe4dSAndroid Build Coastguard Worker             }
497*a67afe4dSAndroid Build Coastguard Worker          }
498*a67afe4dSAndroid Build Coastguard Worker 
499*a67afe4dSAndroid Build Coastguard Worker          if (isprite < 0) /* sprite not found */
500*a67afe4dSAndroid Build Coastguard Worker          {
501*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: --add='%s': sprite not found\n", name);
502*a67afe4dSAndroid Build Coastguard Worker             break;
503*a67afe4dSAndroid Build Coastguard Worker          }
504*a67afe4dSAndroid Build Coastguard Worker       }
505*a67afe4dSAndroid Build Coastguard Worker 
506*a67afe4dSAndroid Build Coastguard Worker       else
507*a67afe4dSAndroid Build Coastguard Worker       {
508*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "simpleover: %s: unrecognized operation\n", argv[0]);
509*a67afe4dSAndroid Build Coastguard Worker          break;
510*a67afe4dSAndroid Build Coastguard Worker       }
511*a67afe4dSAndroid Build Coastguard Worker 
512*a67afe4dSAndroid Build Coastguard Worker       result = 1; /* ok  */
513*a67afe4dSAndroid Build Coastguard Worker    }
514*a67afe4dSAndroid Build Coastguard Worker 
515*a67afe4dSAndroid Build Coastguard Worker    /* Clean up the cache of sprites: */
516*a67afe4dSAndroid Build Coastguard Worker out:
517*a67afe4dSAndroid Build Coastguard Worker    while (--nsprites >= 0)
518*a67afe4dSAndroid Build Coastguard Worker    {
519*a67afe4dSAndroid Build Coastguard Worker       if (sprites[nsprites].buffer != NULL)
520*a67afe4dSAndroid Build Coastguard Worker          free(sprites[nsprites].buffer);
521*a67afe4dSAndroid Build Coastguard Worker 
522*a67afe4dSAndroid Build Coastguard Worker       if (sprites[nsprites].file != NULL)
523*a67afe4dSAndroid Build Coastguard Worker          (void)fclose(sprites[nsprites].file);
524*a67afe4dSAndroid Build Coastguard Worker    }
525*a67afe4dSAndroid Build Coastguard Worker 
526*a67afe4dSAndroid Build Coastguard Worker    return result;
527*a67afe4dSAndroid Build Coastguard Worker }
528*a67afe4dSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)529*a67afe4dSAndroid Build Coastguard Worker int main(int argc, const char **argv)
530*a67afe4dSAndroid Build Coastguard Worker {
531*a67afe4dSAndroid Build Coastguard Worker    int result = 1; /* default to fail */
532*a67afe4dSAndroid Build Coastguard Worker 
533*a67afe4dSAndroid Build Coastguard Worker    if (argc >= 2)
534*a67afe4dSAndroid Build Coastguard Worker    {
535*a67afe4dSAndroid Build Coastguard Worker       int argi = 2;
536*a67afe4dSAndroid Build Coastguard Worker       const char *output = NULL;
537*a67afe4dSAndroid Build Coastguard Worker       png_image image;
538*a67afe4dSAndroid Build Coastguard Worker 
539*a67afe4dSAndroid Build Coastguard Worker       if (argc > 2 && argv[2][0] != '-'/*an operation*/)
540*a67afe4dSAndroid Build Coastguard Worker       {
541*a67afe4dSAndroid Build Coastguard Worker          output = argv[2];
542*a67afe4dSAndroid Build Coastguard Worker          argi = 3;
543*a67afe4dSAndroid Build Coastguard Worker       }
544*a67afe4dSAndroid Build Coastguard Worker 
545*a67afe4dSAndroid Build Coastguard Worker       image.version = PNG_IMAGE_VERSION;
546*a67afe4dSAndroid Build Coastguard Worker       image.opaque = NULL;
547*a67afe4dSAndroid Build Coastguard Worker 
548*a67afe4dSAndroid Build Coastguard Worker       if (png_image_begin_read_from_file(&image, argv[1]))
549*a67afe4dSAndroid Build Coastguard Worker       {
550*a67afe4dSAndroid Build Coastguard Worker          png_bytep buffer;
551*a67afe4dSAndroid Build Coastguard Worker 
552*a67afe4dSAndroid Build Coastguard Worker          image.format = PNG_FORMAT_RGB; /* 24-bit RGB */
553*a67afe4dSAndroid Build Coastguard Worker 
554*a67afe4dSAndroid Build Coastguard Worker          buffer = malloc(PNG_IMAGE_SIZE(image));
555*a67afe4dSAndroid Build Coastguard Worker 
556*a67afe4dSAndroid Build Coastguard Worker          if (buffer != NULL)
557*a67afe4dSAndroid Build Coastguard Worker          {
558*a67afe4dSAndroid Build Coastguard Worker             png_color background = {0, 0xff, 0}; /* fully saturated green */
559*a67afe4dSAndroid Build Coastguard Worker 
560*a67afe4dSAndroid Build Coastguard Worker             if (png_image_finish_read(&image, &background, buffer,
561*a67afe4dSAndroid Build Coastguard Worker                0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */))
562*a67afe4dSAndroid Build Coastguard Worker             {
563*a67afe4dSAndroid Build Coastguard Worker                /* At this point png_image_finish_read has cleaned up the
564*a67afe4dSAndroid Build Coastguard Worker                 * allocated data in png_image, and only the buffer needs to be
565*a67afe4dSAndroid Build Coastguard Worker                 * freed.
566*a67afe4dSAndroid Build Coastguard Worker                 *
567*a67afe4dSAndroid Build Coastguard Worker                 * Perform the remaining operations:
568*a67afe4dSAndroid Build Coastguard Worker                 */
569*a67afe4dSAndroid Build Coastguard Worker                if (simpleover_process(&image, buffer, argc-argi, argv+argi))
570*a67afe4dSAndroid Build Coastguard Worker                {
571*a67afe4dSAndroid Build Coastguard Worker                   /* Write the output: */
572*a67afe4dSAndroid Build Coastguard Worker                   if ((output != NULL &&
573*a67afe4dSAndroid Build Coastguard Worker                        png_image_write_to_file(&image, output,
574*a67afe4dSAndroid Build Coastguard Worker                         0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
575*a67afe4dSAndroid Build Coastguard Worker                         NULL/*colormap*/)) ||
576*a67afe4dSAndroid Build Coastguard Worker                       (output == NULL &&
577*a67afe4dSAndroid Build Coastguard Worker                        png_image_write_to_stdio(&image, stdout,
578*a67afe4dSAndroid Build Coastguard Worker                         0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
579*a67afe4dSAndroid Build Coastguard Worker                         NULL/*colormap*/)))
580*a67afe4dSAndroid Build Coastguard Worker                      result = 0;
581*a67afe4dSAndroid Build Coastguard Worker 
582*a67afe4dSAndroid Build Coastguard Worker                   else
583*a67afe4dSAndroid Build Coastguard Worker                      fprintf(stderr, "simpleover: write %s: %s\n",
584*a67afe4dSAndroid Build Coastguard Worker                         output == NULL ? "stdout" : output, image.message);
585*a67afe4dSAndroid Build Coastguard Worker                }
586*a67afe4dSAndroid Build Coastguard Worker 
587*a67afe4dSAndroid Build Coastguard Worker                /* else simpleover_process writes an error message */
588*a67afe4dSAndroid Build Coastguard Worker             }
589*a67afe4dSAndroid Build Coastguard Worker 
590*a67afe4dSAndroid Build Coastguard Worker             else
591*a67afe4dSAndroid Build Coastguard Worker                fprintf(stderr, "simpleover: read %s: %s\n", argv[1],
592*a67afe4dSAndroid Build Coastguard Worker                    image.message);
593*a67afe4dSAndroid Build Coastguard Worker 
594*a67afe4dSAndroid Build Coastguard Worker             free(buffer);
595*a67afe4dSAndroid Build Coastguard Worker          }
596*a67afe4dSAndroid Build Coastguard Worker 
597*a67afe4dSAndroid Build Coastguard Worker          else
598*a67afe4dSAndroid Build Coastguard Worker          {
599*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
600*a67afe4dSAndroid Build Coastguard Worker                (unsigned long)PNG_IMAGE_SIZE(image));
601*a67afe4dSAndroid Build Coastguard Worker 
602*a67afe4dSAndroid Build Coastguard Worker             /* This is the only place where a 'free' is required; libpng does
603*a67afe4dSAndroid Build Coastguard Worker              * the cleanup on error and success, but in this case we couldn't
604*a67afe4dSAndroid Build Coastguard Worker              * complete the read because of running out of memory.
605*a67afe4dSAndroid Build Coastguard Worker              */
606*a67afe4dSAndroid Build Coastguard Worker             png_image_free(&image);
607*a67afe4dSAndroid Build Coastguard Worker          }
608*a67afe4dSAndroid Build Coastguard Worker       }
609*a67afe4dSAndroid Build Coastguard Worker 
610*a67afe4dSAndroid Build Coastguard Worker       else
611*a67afe4dSAndroid Build Coastguard Worker       {
612*a67afe4dSAndroid Build Coastguard Worker          /* Failed to read the first argument: */
613*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "simpleover: %s: %s\n", argv[1], image.message);
614*a67afe4dSAndroid Build Coastguard Worker       }
615*a67afe4dSAndroid Build Coastguard Worker    }
616*a67afe4dSAndroid Build Coastguard Worker 
617*a67afe4dSAndroid Build Coastguard Worker    else
618*a67afe4dSAndroid Build Coastguard Worker    {
619*a67afe4dSAndroid Build Coastguard Worker       /* Usage message */
620*a67afe4dSAndroid Build Coastguard Worker       fprintf(stderr,
621*a67afe4dSAndroid Build Coastguard Worker          "simpleover: usage: simpleover background.png [output.png]\n"
622*a67afe4dSAndroid Build Coastguard Worker          "  Output 'background.png' as a 24-bit RGB PNG file in 'output.png'\n"
623*a67afe4dSAndroid Build Coastguard Worker          "   or, if not given, stdout.  'background.png' will be composited\n"
624*a67afe4dSAndroid Build Coastguard Worker          "   on fully saturated green.\n"
625*a67afe4dSAndroid Build Coastguard Worker          "\n"
626*a67afe4dSAndroid Build Coastguard Worker          "  Optionally, before output, process additional PNG files:\n"
627*a67afe4dSAndroid Build Coastguard Worker          "\n"
628*a67afe4dSAndroid Build Coastguard Worker          "   --sprite=width,height,name {[--at=x,y] {sprite.png}}\n"
629*a67afe4dSAndroid Build Coastguard Worker          "    Produce a transparent sprite of size (width,height) and with\n"
630*a67afe4dSAndroid Build Coastguard Worker          "     name 'name'.\n"
631*a67afe4dSAndroid Build Coastguard Worker          "    For each sprite.png composite it using a Porter-Duff 'Over'\n"
632*a67afe4dSAndroid Build Coastguard Worker          "     operation at offset (x,y) in the sprite (defaulting to (0,0)).\n"
633*a67afe4dSAndroid Build Coastguard Worker          "     Input PNGs will be truncated to the area of the sprite.\n"
634*a67afe4dSAndroid Build Coastguard Worker          "\n"
635*a67afe4dSAndroid Build Coastguard Worker          "   --add='name' {x,y}\n"
636*a67afe4dSAndroid Build Coastguard Worker          "    Optionally, before output, composite a sprite, 'name', which\n"
637*a67afe4dSAndroid Build Coastguard Worker          "     must have been previously produced using --sprite, at each\n"
638*a67afe4dSAndroid Build Coastguard Worker          "     offset (x,y) in the output image.  Each sprite must fit\n"
639*a67afe4dSAndroid Build Coastguard Worker          "     completely within the output image.\n"
640*a67afe4dSAndroid Build Coastguard Worker          "\n"
641*a67afe4dSAndroid Build Coastguard Worker          "  PNG files are processed in the order they occur on the command\n"
642*a67afe4dSAndroid Build Coastguard Worker          "  line and thus the first PNG processed appears as the bottommost\n"
643*a67afe4dSAndroid Build Coastguard Worker          "  in the output image.\n");
644*a67afe4dSAndroid Build Coastguard Worker    }
645*a67afe4dSAndroid Build Coastguard Worker 
646*a67afe4dSAndroid Build Coastguard Worker    return result;
647*a67afe4dSAndroid Build Coastguard Worker }
648*a67afe4dSAndroid Build Coastguard Worker #endif /* SIMPLIFIED_READ */
649