19b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/*- simpleover 29b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 39b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * COPYRIGHT: Written by John Cunningham Bowler, 2015. 49b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * To the extent possible under law, the author has waived all copyright and 59b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * related or neighboring rights to this work. This work is published from: 69b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * United States. 79b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 89b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Read several PNG files, which should have an alpha channel or transparency 99b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * information, and composite them together to produce one or more 16-bit linear 109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * RGBA intermediates. This involves doing the correct 'over' composition to 119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * combine the alpha channels and corresponding data. 129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Finally read an output (background) PNG using the 24-bit RGB format (the 149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * PNG will be composited on green (#00ff00) by default if it has an alpha 159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * channel), and apply the intermediate image generated above to specified 169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * locations in the image. 179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The command line has the general format: 199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * simpleover <background.png> [output.png] 219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * {--sprite=width,height,name {[--at=x,y] {sprite.png}}} 229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * {--add=name {x,y}} 239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The --sprite and --add options may occur multiple times. They are executed 259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * in order. --add may refer to any sprite already read. 269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This code is intended to show how to composite multiple images together 289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * correctly. Apart from the libpng Simplified API the only work done in here 299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * is to combine multiple input PNG images into a single sprite; this involves 309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * a Porter-Duff 'over' operation and the input PNG images may, as a result, 319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * be regarded as being layered one on top of the other with the first (leftmost 329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * on the command line) being at the bottom and the last on the top. 339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stddef.h> 359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdlib.h> 369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <string.h> 379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdio.h> 389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <errno.h> 399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* Normally use <png.h> here to get the installed libpng, but this is done to 419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * ensure the code picks up the local libpng implementation, so long as this 429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * file is linked against a sufficiently recent libpng (1.6+) it is ok to 439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * change this to <png.h>: 449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include "../../png.h" 469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_SIMPLIFIED_READ_SUPPORTED 489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define sprite_name_chars 15 509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstruct sprite { 519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett FILE *file; 529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_16p buffer; 539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int width; 549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int height; 559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char name[sprite_name_chars+1]; 569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}; 579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#if 0 /* div by 65535 test program */ 599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <math.h> 609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdio.h> 619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettint main(void) { 639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double err = 0; 649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int xerr = 0; 659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int r = 32769; 669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int x = 0; 689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett do { 709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int t = x + (x >> 16) /*+ (x >> 31)*/ + r; 719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double v = x, errtest; 729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (t < x) { 749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "overflow: %u+%u -> %u\n", x, r, t); 759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; 769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett v /= 65535; 799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett errtest = v; 809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett t >>= 16; 819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett errtest -= t; 829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (errtest > err) { 849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett err = errtest; 859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett xerr = x; 869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (errtest >= .5) { 889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "error: %u/65535 = %f, not %u, error %f\n", 899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x, v, t, errtest); 909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } while (++x <= 65535U*65535U); 949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett printf("error %f @ %u\n", err, xerr); 979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 1009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* div by 65535 test program */ 1019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic void 1039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettsprite_op(const struct sprite *sprite, int x_offset, int y_offset, 1049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_imagep image, const png_uint_16 *buffer) 1059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This is where the Porter-Duff 'Over' operator is evaluated; change this 1079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * code to change the operator (this could be parameterized). Any other 1089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * image processing operation could be used here. 1099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 1109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Check for an x or y offset that pushes any part of the image beyond the 1139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * right or bottom of the sprite: 1149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 1159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if ((y_offset < 0 || (unsigned)/*SAFE*/y_offset < sprite->height) && 1169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (x_offset < 0 || (unsigned)/*SAFE*/x_offset < sprite->width)) 1179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int y = 0; 1199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (y_offset < 0) 1219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett y = -y_offset; /* Skip to first visible row */ 1229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett do 1249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int x = 0; 1269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (x_offset < 0) 1289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x = -x_offset; 1299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett do 1319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* In and out are RGBA values, so: */ 1339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const png_uint_16 *in_pixel = buffer + (y * image->width + x)*4; 1349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_32 in_alpha = in_pixel[3]; 1359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This is the optimized Porter-Duff 'Over' operation, when the 1379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * input alpha is 0 the output is not changed. 1389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 13906f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett if (in_alpha > 0) 1409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_16 *out_pixel = sprite->buffer + 1429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ((y+y_offset) * sprite->width + (x+x_offset))*4; 1439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This is the weight to apply to the output: */ 1459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett in_alpha = 65535-in_alpha; 1469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (in_alpha > 0) 1489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The input must be composed onto the output. This means 1509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * multiplying the current output pixel value by the inverse 1519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * of the input alpha (1-alpha). A division is required but 1529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * it is by the constant 65535. Approximate this as: 1539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * (x + (x >> 16) + 32769) >> 16; 1559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This is exact (and does not overflow) for all values of 1579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x in the range 0..65535*65535. (Note that the calculation 1589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * produces the closest integer; the maximum error is <0.5). 1599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 1609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_32 tmp; 1619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define compose(c)\ 1639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett tmp = out_pixel[c] * in_alpha;\ 1649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett tmp = (tmp + (tmp >> 16) + 32769) >> 16;\ 1659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_pixel[c] = tmp + in_pixel[c] 1669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The following is very vectorizable... */ 1689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett compose(0); 1699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett compose(1); 1709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett compose(2); 1719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett compose(3); 1729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 1759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_pixel[0] = in_pixel[0], 1769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_pixel[1] = in_pixel[1], 1779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_pixel[2] = in_pixel[2], 1789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_pixel[3] = in_pixel[3]; 1799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (++x < image->width); 1829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (++y < image->height); 1849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 1869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 18706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarettstatic int 1889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcreate_sprite(struct sprite *sprite, int *argc, const char ***argv) 1899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Read the arguments and create this sprite. The sprite buffer has already 1919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * been allocated. This reads the input PNGs one by one in linear format, 1929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * composes them onto the sprite buffer (the code in the function above) 1939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * then saves the result, converting it on the fly to PNG RGBA 8-bit format. 1949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 1959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (*argc > 0) 1969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char tombstone; 1989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int x = 0, y = 0; 1999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-') 2019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The only supported option is --at. */ 2039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sscanf((*argv)[0], "--at=%d,%d%c", &x, &y, &tombstone) != 2) 2049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; /* success; caller will parse this option */ 2059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++*argv, --*argc; 2079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 2109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The argument has to be a file name */ 2129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image image; 2139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.version = PNG_IMAGE_VERSION; 2159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.opaque = NULL; 2169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_begin_read_from_file(&image, (*argv)[0])) 2189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_16p buffer; 2209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.format = PNG_FORMAT_LINEAR_RGB_ALPHA; 2229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buffer = malloc(PNG_IMAGE_SIZE(image)); 2249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (buffer != NULL) 2269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_finish_read(&image, NULL/*background*/, buffer, 2289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 0/*row_stride*/, 2299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/)) 2309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This is the place where the Porter-Duff 'Over' operator 2329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * needs to be done by this code. In fact, any image 2339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * processing required can be done here; the data is in 2349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the correct format (linear, 16-bit) and source and 2359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * destination are in memory. 2369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 2379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite_op(sprite, x, y, &image, buffer); 2389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(buffer); 2399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++*argv, --*argc; 2409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* And continue to the next argument */ 2419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett continue; 2429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 2459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(buffer); 2479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: read %s: %s\n", (*argv)[0], 2489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.message); 2499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 2539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: out of memory: %lu bytes\n", 2559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (unsigned long)PNG_IMAGE_SIZE(image)); 2569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* png_image_free must be called if we abort the Simplified API 2589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * read because of a problem detected in this code. If problems 2599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * are detected in the Simplified API it cleans up itself. 2609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 2619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image_free(&image); 2629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 2669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Failed to read the first argument: */ 2689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: %s\n", (*argv)[0], image.message); 2699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* failure */ 2729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* All the sprite operations have completed successfully. Save the RGBA 2769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * buffer as a PNG using the simplified write API. 2779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 2789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->file = tmpfile(); 2799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sprite->file != NULL) 2819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image save; 2839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett memset(&save, 0, sizeof save); 2859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.version = PNG_IMAGE_VERSION; 2869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.opaque = NULL; 2879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.width = sprite->width; 2889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.height = sprite->height; 2899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.format = PNG_FORMAT_LINEAR_RGB_ALPHA; 2909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.flags = PNG_IMAGE_FLAG_FAST; 2919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.colormap_entries = 0; 2929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_write_to_stdio(&save, sprite->file, 1/*convert_to_8_bit*/, 2949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->buffer, 0/*row_stride*/, NULL/*colormap*/)) 2959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 2969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Success; the buffer is no longer needed: */ 2979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(sprite->buffer); 2989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->buffer = NULL; 2999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; /* ok */ 3009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 3039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: write sprite %s: %s\n", sprite->name, 3049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett save.message); 3059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 3089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: sprite %s: could not allocate tmpfile: %s\n", 3099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->name, strerror(errno)); 3109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* fail */ 3129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 3139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 3159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettadd_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite, 3169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int *argc, const char ***argv) 3179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 3189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Given a --add argument naming this sprite, perform the operations listed 3199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * in the following arguments. The arguments are expected to have the form 3209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * (x,y), which is just an offset at which to add the sprite to the 3219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * output. 3229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (*argc > 0) 3249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char tombstone; 3269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int x, y; 3279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if ((*argv)[0][0] == '-' && (*argv)[0][1] == '-') 3299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; /* success */ 3309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sscanf((*argv)[0], "%d,%d%c", &x, &y, &tombstone) == 2) 3329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Now add the new image into the sprite data, but only if it 3349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * will fit. 3359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (x < 0 || y < 0 || 3379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (unsigned)/*SAFE*/x >= output->width || 3389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (unsigned)/*SAFE*/y >= output->height || 3399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->width > output->width-x || 3409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->height > output->height-y) 3419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: sprite %s @ (%d,%d) outside image\n", 3439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->name, x, y); 3449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Could just skip this, but for the moment it is an error */ 3459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* error */ 3469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 3499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Since we know the sprite fits we can just read it into the 3519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * output using the simplified API. 3529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image in; 3549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett in.version = PNG_IMAGE_VERSION; 3569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett rewind(sprite->file); 3579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_begin_read_from_stdio(&in, sprite->file)) 3599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett in.format = PNG_FORMAT_RGB; /* force compose */ 3619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_finish_read(&in, NULL/*background*/, 3639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett out_buf + (y*output->width + x)*3/*RGB*/, 3649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett output->width*3/*row_stride*/, 3659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/)) 3669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++*argv, --*argc; 3689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett continue; 3699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The read failed: */ 3739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: add sprite %s: %s\n", sprite->name, 3749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett in.message); 3759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* error */ 3769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 3809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: --add='%s': invalid position %s\n", 3829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprite->name, (*argv)[0]); 3839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* error */ 3849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; /* ok */ 3889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 3899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 3919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettsimpleover_process(png_imagep output, png_bytep out_buf, int argc, 3929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const char **argv) 3939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 3949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int result = 1; /* success */ 3959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define csprites 10/*limit*/ 3969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define str(a) #a 3979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int nsprites = 0; 3989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett struct sprite sprites[csprites]; 3999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (argc > 0) 4019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett result = 0; /* fail */ 4039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (strncmp(argv[0], "--sprite=", 9) == 0) 4059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char tombstone; 4079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (nsprites < csprites) 4099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int n; 4119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].width = sprites[nsprites].height = 0; 4139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].name[0] = 0; 4149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett n = sscanf(argv[0], "--sprite=%u,%u,%" str(sprite_name_chars) "s%c", 4169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett &sprites[nsprites].width, &sprites[nsprites].height, 4179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].name, &tombstone); 41806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett 4199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if ((n == 2 || n == 3) && 4209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].width > 0 && sprites[nsprites].height > 0) 4219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett size_t buf_size, tmp; 4239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Default a name if not given. */ 4259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sprites[nsprites].name[0] == 0) 4269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprintf(sprites[nsprites].name, "sprite-%d", nsprites+1); 4279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Allocate a buffer for the sprite and calculate the buffer 4299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * size: 4309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buf_size = sizeof (png_uint_16 [4]); 4329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buf_size *= sprites[nsprites].width; 4339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buf_size *= sprites[nsprites].height; 4349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This can overflow a (size_t); check for this: */ 4369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett tmp = buf_size; 4379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett tmp /= sprites[nsprites].width; 4389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett tmp /= sprites[nsprites].height; 4399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (tmp == sizeof (png_uint_16 [4])) 4419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].buffer = malloc(buf_size); 4439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This buffer must be initialized to transparent: */ 4449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett memset(sprites[nsprites].buffer, 0, buf_size); 4459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sprites[nsprites].buffer != NULL) 4479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett sprites[nsprites].file = NULL; 4499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++argv, --argc; 4509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (create_sprite(sprites+nsprites++, &argc, &argv)) 4529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett result = 1; /* still ok */ 4549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett continue; 4559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; /* error */ 4589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Overflow, or OOM */ 4629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: sprite too large\n", argv[0]); 4639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; 4649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 4679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: invalid sprite (%u,%u)\n", 4699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett argv[0], sprites[nsprites].width, sprites[nsprites].height); 4709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; 4719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 4759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: too many sprites\n", argv[0]); 4779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; 4789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else if (strncmp(argv[0], "--add=", 6) == 0) 4829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const char *name = argv[0]+6; 4849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int isprite = nsprites; 4859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++argv, --argc; 4879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (--isprite >= 0) 4899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (strcmp(sprites[isprite].name, name) == 0) 4919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (!add_sprite(output, out_buf, sprites+isprite, &argc, &argv)) 4939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett goto out; /* error in add_sprite */ 4949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 49506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett break; 4969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (isprite < 0) /* sprite not found */ 5009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: --add='%s': sprite not found\n", name); 5029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; 5039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 5079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: unrecognized operation\n", argv[0]); 5099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett break; 5109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett result = 1; /* ok */ 5139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Clean up the cache of sprites: */ 5169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettout: 5179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (--nsprites >= 0) 5189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sprites[nsprites].buffer != NULL) 5209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(sprites[nsprites].buffer); 5219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (sprites[nsprites].file != NULL) 5239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (void)fclose(sprites[nsprites].file); 5249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return result; 5279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettint main(int argc, const char **argv) 5309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 5319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int result = 1; /* default to fail */ 5329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (argc >= 2) 5349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int argi = 2; 5369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const char *output = NULL; 5379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image image; 5389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (argc > 2 && argv[2][0] != '-'/*an operation*/) 5409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett output = argv[2]; 5429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett argi = 3; 5439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.version = PNG_IMAGE_VERSION; 5469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.opaque = NULL; 5479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_begin_read_from_file(&image, argv[1])) 5499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_bytep buffer; 5519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.format = PNG_FORMAT_RGB; /* 24-bit RGB */ 5539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buffer = malloc(PNG_IMAGE_SIZE(image)); 5559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (buffer != NULL) 5579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_color background = {0, 0xff, 0}; /* fully saturated green */ 5599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_finish_read(&image, &background, buffer, 5619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */)) 5629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* At this point png_image_finish_read has cleaned up the 5649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * allocated data in png_image, and only the buffer needs to be 5659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * freed. 5669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 5679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Perform the remaining operations: 5689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (simpleover_process(&image, buffer, argc-argi, argv+argi)) 5709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Write the output: */ 5729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if ((output != NULL && 5739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image_write_to_file(&image, output, 5749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, 5759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett NULL/*colormap*/)) || 5769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (output == NULL && 5779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image_write_to_stdio(&image, stdout, 5789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 0/*convert_to_8bit*/, buffer, 0/*row_stride*/, 5799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett NULL/*colormap*/))) 5809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett result = 0; 5819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 5839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: write %s: %s\n", 5849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett output == NULL ? "stdout" : output, image.message); 5859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* else simpleover_process writes an error message */ 5889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 5919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: read %s: %s\n", argv[1], 5929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.message); 5939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(buffer); 5959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 5989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: out of memory: %lu bytes\n", 6009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (unsigned long)PNG_IMAGE_SIZE(image)); 6019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This is the only place where a 'free' is required; libpng does 6039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the cleanup on error and success, but in this case we couldn't 6049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * complete the read because of running out of memory. 6059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 6069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image_free(&image); 6079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 6119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 6129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Failed to read the first argument: */ 6139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "simpleover: %s: %s\n", argv[1], image.message); 6149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 6189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 6199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Usage message */ 6209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, 6219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "simpleover: usage: simpleover background.png [output.png]\n" 6229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Output 'background.png' as a 24-bit RGB PNG file in 'output.png'\n" 6239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " or, if not given, stdout. 'background.png' will be composited\n" 6249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " on fully saturated green.\n" 6259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 6269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Optionally, before output, process additional PNG files:\n" 6279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 6289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " --sprite=width,height,name {[--at=x,y] {sprite.png}}\n" 6299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Produce a transparent sprite of size (width,height) and with\n" 6309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " name 'name'.\n" 6319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " For each sprite.png composite it using a Porter-Duff 'Over'\n" 6329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " operation at offset (x,y) in the sprite (defaulting to (0,0)).\n" 6339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Input PNGs will be truncated to the area of the sprite.\n" 6349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 6359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " --add='name' {x,y}\n" 6369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Optionally, before output, composite a sprite, 'name', which\n" 6379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " must have been previously produced using --sprite, at each\n" 6389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " offset (x,y) in the output image. Each sprite must fit\n" 6399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " completely within the output image.\n" 6409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 6419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " PNG files are processed in the order they occur on the command\n" 6429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " line and thus the first PNG processed appears as the bottommost\n" 6439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " in the output image.\n"); 6449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return result; 6479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 6489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* SIMPLIFIED_READ */ 649