19b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/*- genpng 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 * Generate a PNG with an alpha channel, correctly. 99b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This is a test case generator; the resultant PNG files are only of interest 119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * to those of us who care about whether the edges of circles are green, red, 129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * or yellow. 139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The program generates an RGB+Alpha PNG of a given size containing the given 159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shapes on a transparent background: 169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * genpng width height { shape } 189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shape ::= color width shape x1 y1 x2 y2 199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'color' is: 219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * black white red green yellow blue brown purple pink orange gray cyan 239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The point is to have colors that are linguistically meaningful plus that old 259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * bugbear of the department store dress murders, Cyan, the only color we argue 269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * about. 279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'shape' is: 299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * circle: an ellipse 319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * square: a rectangle 329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * line: a straight line 339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Each shape is followed by four numbers, these are two points in the output 359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * coordinate space (as real numbers) which describe the circle, square, or 369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * line. The shape is filled if it is preceded by 'filled' (not valid for 379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'line') or is drawn with a line, in which case the width of the line must 389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * precede the shape. 399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The whole set of information can be repeated as many times as desired: 419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shape ::= color width shape x1 y1 x2 y2 439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * color ::= black|white|red|green|yellow|blue 459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * color ::= brown|purple|pink|orange|gray|cyan 469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * width ::= filled 479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * width ::= <number> 489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shape ::= circle|square|line 499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x1 ::= <number> 509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x2 ::= <number> 519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * y1 ::= <number> 529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * y2 ::= <number> 539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The output PNG is generated by down-sampling a 4x supersampled image using 559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * a bi-cubic filter. The bi-cubic has a 2 (output) pixel width, so an 8x8 569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * array of super-sampled points contribute to each output pixel. The value of 579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * a super-sampled point is found using an unfiltered, aliased, infinite 589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * precision image: Each shape from the last to the first is checked to see if 599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the point is in the drawn area and, if it is, the color of the point is the 609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * color of the shape and the alpha is 1, if not the previous shape is checked. 619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This is an aliased algorithm because no filtering is done; a point is either 639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * inside or outside each shape and 'close' points do not contribute to the 649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * sample. The down-sampling is relied on to correct the error of not using 659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * a filter. 669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The line end-caps are 'flat'; they go through the points. The square line 689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * joins are mitres; the outside of the lines are continued to the point of 699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * intersection. 709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stddef.h> 729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdlib.h> 739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <string.h> 749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <stdio.h> 759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include <math.h> 769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* Normally use <png.h> here to get the installed libpng, but this is done to 789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * ensure the code picks up the local libpng implementation: 799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#include "../../png.h" 819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) 839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic const struct color 859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const char *name; 879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double red; 889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double green; 899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double blue; 909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} colors[] = 919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* color ::= black|white|red|green|yellow|blue 929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * color ::= brown|purple|pink|orange|gray|cyan 939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "black", 0, 0, 0 }, 969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "white", 1, 1, 1 }, 979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "red", 1, 0, 0 }, 989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "green", 0, 1, 0 }, 999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "yellow", 1, 1, 0 }, 1009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "blue", 0, 0, 1 }, 1019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "brown", .5, .125, 0 }, 1029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "purple", 1, 0, 1 }, 1039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "pink", 1, .5, .5 }, 1049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "orange", 1, .5, 0 }, 1059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "gray", 0, .5, .5 }, 1069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "cyan", 0, 1, 1 } 1079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}; 1089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define color_count ((sizeof colors)/(sizeof colors[0])) 1099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic const struct color * 1119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcolor_of(const char *arg) 1129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int icolor = color_count; 1149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (--icolor >= 0) 1169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (strcmp(colors[icolor].name, arg) == 0) 1189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return colors+icolor; 1199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: invalid color %s\n", arg); 1229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 1239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 1249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic double 1269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettwidth_of(const char *arg) 1279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (strcmp(arg, "filled") == 0) 1299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 1309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 1329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 1339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char *ep = NULL; 1349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double w = strtod(arg, &ep); 1359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (ep != NULL && *ep == 0 && w > 0) 1379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return w; 1389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 1399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: invalid line width %s\n", arg); 1419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 1429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 1439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic double 1459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcoordinate_of(const char *arg) 1469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char *ep = NULL; 1489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double w = strtod(arg, &ep); 1499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (ep != NULL && *ep == 0) 1519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return w; 1529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: invalid coordinate value %s\n", arg); 1549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 1559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 1569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstruct arg; /* forward declaration */ 1589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Saretttypedef int (*shape_fn_ptr)(const struct arg *arg, double x, double y); 1609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* A function to determine if (x,y) is inside the shape. 1619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * There are two implementations: 1639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * inside_fn: returns true if the point is inside 1659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * check_fn: returns; 1669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * -1: the point is outside the shape by more than the filter width (2) 1679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 0: the point may be inside the shape 1689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * +1: the point is inside the shape by more than the filter width 1699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 1709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define OUTSIDE (-1) 1719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define INSIDE (1) 1729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstruct arg 1749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 1759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const struct color *color; 1769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett shape_fn_ptr inside_fn; 1779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett shape_fn_ptr check_fn; 1789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double width; /* line width, 0 for 'filled' */ 1799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double x1, y1, x2, y2; 1809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}; 1819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 1829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* IMPLEMENTATION NOTE: 1839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * We want the contribution of each shape to the sample corresponding to each 1859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * pixel. This could be obtained by super sampling the image to infinite 1869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * dimensions, finding each point within the shape and assigning that a value 1879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * '1' while leaving every point outside the shape with value '0' then 1889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * downsampling to the image size with sinc; computationally very expensive. 1899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Approximations are as follows: 1919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1) If the pixel coordinate is within the shape assume the sample has the 1939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shape color and is opaque, else assume there is no contribution from 1949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the shape. 1959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This is the equivalent of aliased rendering or resampling an image with 1979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * a block filter. The maximum error in the calculated alpha (which will 1989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * always be 0 or 1) is 0.5. 1999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2) If the shape is within a square of size 1x1 centered on the pixel assume 2019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * that the shape obscures an amount of the pixel equal to its area within 2029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * that square. 2039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This is the equivalent of 'pixel coverage' alpha calculation or resampling 2059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * an image with a bi-linear filter. The maximum error is over 0.2, but the 2069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * results are often acceptable. 2079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This can be approximated by applying (1) to a super-sampled image then 2099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * downsampling with a bi-linear filter. The error in the super-sampled 2109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * image is 0.5 per sample, but the resampling reduces this. 2119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 3) Use a better filter with a super-sampled image; in the limit this is the 2139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * sinc() approach. 2149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 4) Do the geometric calculation; a bivariate definite integral across the 2169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * shape, unfortunately this means evaluating Si(x), the integral of sinc(x), 2179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * which is still a lot of math. 2189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * This code uses approach (3) with a bi-cubic filter and 8x super-sampling 2209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * and method (1) for the super-samples. This means that the sample is either 2219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 0 or 1, depending on whether the sub-pixel is within or outside the shape. 2229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The bi-cubic weights are also fixed and the 16 required weights are 2239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * pre-computed here (note that the 'scale' setting will need to be changed if 2249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'super' is increased). 2259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 2269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The code also calculates a sum to the edge of the filter. This is not 2279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * currently used by could be used to optimize the calculation. 2289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 2299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#if 0 /* bc code */ 2309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettscale=10 2319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettsuper=8 2329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettdefine bicubic(x) { 2339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (x <= 1) return (1.5*x - 2.5)*x*x + 1; 2349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (x < 2) return (((2.5 - 0.5*x)*x - 4)*x + 2); 2359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 2369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 2379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettdefine sum(x) { 2389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett auto s; 2399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett s = 0; 2409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (x < 2*super) { 2419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett s = s + bicubic(x/super); 2429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x = x + 1; 2439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 2449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return s; 2459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 2469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettdefine results(x) { 2479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett auto b, s; 2489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett b = bicubic(x/super); 2499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett s = sum(x); 2509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett print " /*", x, "*/ { ", b, ", ", s, " }"; 2529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; 2539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 2549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettx=0 2559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettwhile (x<2*super) { 2569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x = x + results(x) 2579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (x < 2*super) print "," 2589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett print "\n" 2599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 2609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettquit 2619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif 2629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define BICUBIC1(x) /* |x| <= 1 */ ((1.5*(x)* - 2.5)*(x)*(x) + 1) 2649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define BICUBIC2(x) /* 1 < |x| < 2 */ (((2.5 - 0.5*(x))*(x) - 4)*(x) + 2) 2659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define FILTER_WEIGHT 9 /* Twice the first sum below */ 2669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define FILTER_WIDTH 2 /* Actually half the width; -2..+2 */ 2679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define FILTER_STEPS 8 /* steps per filter unit */ 2689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic const double 2699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettbicubic[16][2] = 2709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 2719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* These numbers are exact; the weight for the filter is 1/9, but this 2729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * would make the numbers inexact, so it is not included here. 2739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 2749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* bicubic sum */ 2759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 0*/ { 1.0000000000, 4.5000000000 }, 2769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 1*/ { .9638671875, 3.5000000000 }, 2779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 2*/ { .8671875000, 2.5361328125 }, 2789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 3*/ { .7275390625, 1.6689453125 }, 2799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 4*/ { .5625000000, .9414062500 }, 2809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 5*/ { .3896484375, .3789062500 }, 2819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 6*/ { .2265625000, -.0107421875 }, 2829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 7*/ { .0908203125, -.2373046875 }, 2839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 8*/ { 0, -.3281250000 }, 2849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 9*/ { -.0478515625, -.3281250000 }, 2859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*10*/ { -.0703125000, -.2802734375 }, 2869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*11*/ { -.0732421875, -.2099609375 }, 2879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*12*/ { -.0625000000, -.1367187500 }, 2889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*13*/ { -.0439453125, -.0742187500 }, 2899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*14*/ { -.0234375000, -.0302734375 }, 2909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /*15*/ { -.0068359375, -.0068359375 } 2919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}; 2929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 2939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic double 2949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettalpha_calc(const struct arg *arg, double x, double y) 2959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 2969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* For [x-2..x+2],[y-2,y+2] calculate the weighted bicubic given a function 2979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * which tells us whether a point is inside or outside the shape. First 2989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * check if we need to do this at all: 2999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett switch (arg->check_fn(arg, x, y)) 3019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett case OUTSIDE: 3039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* all samples outside the shape */ 3049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett case INSIDE: 3069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; /* all samples inside the shape */ 3079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett default: 3099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int dy; 3119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double alpha = 0; 3129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define FILTER_D (FILTER_WIDTH*FILTER_STEPS-1) 3149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (dy=-FILTER_D; dy<=FILTER_D; ++dy) 3159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wy = bicubic[abs(dy)][0]; 3179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (wy != 0) 3199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double alphay = 0; 3219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int dx; 3229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (dx=-FILTER_D; dx<=FILTER_D; ++dx) 3249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wx = bicubic[abs(dx)][0]; 3269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 32706f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett if (wx != 0 && arg->inside_fn(arg, x+dx/16, y+dy/16)) 3289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett alphay += wx; 3299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett alpha += wy * alphay; 3329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* This needs to be weighted for each dimension: */ 3369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return alpha / (FILTER_WEIGHT*FILTER_WEIGHT); 3379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 3399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 3409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* These are the shape functions. */ 3429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* "square", 3439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { inside_square_filled, check_square_filled }, 3449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { inside_square, check_square } 3459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 3479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettsquare_check(double x, double y, double x1, double y1, double x2, double y2) 3489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Is x,y inside the square (x1,y1)..(x2,y2)? */ 3499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 3509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Do a modified Cohen-Sutherland on one point, bit patterns that indicate 3519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'outside' are: 3529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 3539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x<x1 | x<y1 | x<x2 | x<y2 3549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 0 x 0 x To the right 3559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 1 x 1 x To the left 3569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x 0 x 0 Below 3579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * x 1 x 1 Above 3589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 3599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * So 'inside' is (x<x1) != (x<x2) && (y<y1) != (y<y2); 3609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return ((x<x1) ^ (x<x2)) & ((y<y1) ^ (y<y2)); 3629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 3639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 3659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinside_square_filled(const struct arg *arg, double x, double y) 3669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 3679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return square_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2); 3689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 3699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 3719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettsquare_check_line(const struct arg *arg, double x, double y, double w) 3729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Check for a point being inside the boundaries implied by the given arg 3739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * and assuming a width 2*w each side of the boundaries. This returns the 3749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 'check' INSIDE/OUTSIDE/0 result but note the semantics: 3759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 3769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * +--------------+ 3779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * | | OUTSIDE 3789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * | INSIDE | 3799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * | | 3809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * +--------------+ 3819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 3829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * And '0' means within the line boundaries. 3839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 3859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double cx = (arg->x1+arg->x2)/2; 3869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wx = fabs(arg->x1-arg->x2)/2; 3879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double cy = (arg->y1+arg->y2)/2; 3889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wy = fabs(arg->y1-arg->y2)/2; 3899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 3909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (square_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w)) 3919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 3929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Inside, but maybe too far; check for the redundant case where 3939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the lines overlap: 3949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 3959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett wx -= w; 3969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett wy -= w; 3979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (wx > 0 && wy > 0 && square_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy)) 3989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return INSIDE; /* between (inside) the boundary lines. */ 3999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* inside the lines themselves. */ 4019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return OUTSIDE; /* outside the boundary lines. */ 4049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcheck_square_filled(const struct arg *arg, double x, double y) 4089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The filter extends +/-FILTER_WIDTH each side of each output point, so 4109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the check has to expand and contract the square by that amount; '0' 4119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * means close enough to the edge of the square that the bicubic filter has 4129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * to be run, OUTSIDE means alpha==0, INSIDE means alpha==1. 4139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return square_check_line(arg, x, y, FILTER_WIDTH); 4159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinside_square(const struct arg *arg, double x, double y) 4199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Return true if within the drawn lines, else false, no need to distinguish 4219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * INSIDE vs OUTSIDE here: 4229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return square_check_line(arg, x, y, arg->width/2) == 0; 4249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcheck_square(const struct arg *arg, double x, double y) 4289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* So for this function a result of 'INSIDE' means inside the actual lines. 4309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double w = arg->width/2; 4329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (square_check_line(arg, x, y, w+FILTER_WIDTH) == 0) 4349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Somewhere close to the boundary lines. If far enough inside one of 4369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * them then we can return INSIDE: 4379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett w -= FILTER_WIDTH; 4399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (w > 0 && square_check_line(arg, x, y, w) == 0) 4419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return INSIDE; 4429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Point is somewhere in the filter region: */ 4449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 4459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else /* Inside or outside the square by more than w+FILTER_WIDTH. */ 4489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return OUTSIDE; 4499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* "circle", 4529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { inside_circle_filled, check_circle_filled }, 4539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { inside_circle, check_circle } 4549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 4559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The functions here are analoguous to the square ones; however, they check 4569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the corresponding ellipse as opposed to the rectangle. 4579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcircle_check(double x, double y, double x1, double y1, double x2, double y2) 4609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (square_check(x, y, x1, y1, x2, y2)) 4629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 4639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Inside the square, so maybe inside the circle too: */ 4649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const double cx = (x1 + x2)/2; 4659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const double cy = (y1 + y2)/2; 4669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const double dx = x1 - x2; 4679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const double dy = y1 - y2; 4689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x = (x - cx)/dx; 4709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett y = (y - cy)/dy; 4719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* It is outside if the distance from the center is more than half the 4739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * diameter: 4749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return x*x+y*y < .25; 4769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 4779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* outside */ 4799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinside_circle_filled(const struct arg *arg, double x, double y) 4839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return circle_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2); 4859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 4869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 4889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcircle_check_line(const struct arg *arg, double x, double y, double w) 4899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Check for a point being inside the boundaries implied by the given arg 4909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * and assuming a width 2*w each side of the boundaries. This function has 4919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the same semantic as square_check_line but tests the circle. 4929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 4939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 4949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double cx = (arg->x1+arg->x2)/2; 4959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wx = fabs(arg->x1-arg->x2)/2; 4969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double cy = (arg->y1+arg->y2)/2; 4979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double wy = fabs(arg->y1-arg->y2)/2; 4989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 4999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (circle_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w)) 5009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Inside, but maybe too far; check for the redundant case where 5029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the lines overlap: 5039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett wx -= w; 5059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett wy -= w; 5069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (wx > 0 && wy > 0 && circle_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy)) 5079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return INSIDE; /* between (inside) the boundary lines. */ 5089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* inside the lines themselves. */ 5109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return OUTSIDE; /* outside the boundary lines. */ 5139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 5169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcheck_circle_filled(const struct arg *arg, double x, double y) 5179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 5189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return circle_check_line(arg, x, y, FILTER_WIDTH); 5199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 5229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinside_circle(const struct arg *arg, double x, double y) 5239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 5249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return circle_check_line(arg, x, y, arg->width/2) == 0; 5259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 5289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcheck_circle(const struct arg *arg, double x, double y) 5299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 5309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Exactly as the 'square' code. */ 5319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double w = arg->width/2; 5329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (circle_check_line(arg, x, y, w+FILTER_WIDTH) == 0) 5349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 5359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett w -= FILTER_WIDTH; 5369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (w > 0 && circle_check_line(arg, x, y, w) == 0) 5389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return INSIDE; 5399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Point is somewhere in the filter region: */ 5419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 5429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 5439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else /* Inside or outside the square by more than w+FILTER_WIDTH. */ 5459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return OUTSIDE; 5469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* "line", 5499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { NULL, NULL }, There is no 'filled' line. 5509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * { inside_line, check_line } 5519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 5539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettline_check(double x, double y, double x1, double y1, double x2, double y2, 5549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double w, double expand) 5559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 5569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Shift all the points to (arg->x1, arg->y1) */ 5579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double lx = x2 - x1; 5589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double ly = y2 - y1; 5599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double len2 = lx*lx + ly*ly; 5609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double cross, dot; 5619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett x -= x1; 5639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett y -= y1; 5649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The dot product is the distance down the line, the cross product is 5669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the distance away from the line: 5679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 56806f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett * distance = |cross| / sqrt(len2) 5699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett cross = x * ly - y * lx; 5719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* If 'distance' is more than w the point is definitely outside the line: 5739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 5749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * distance >= w 5759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * |cross| >= w * sqrt(len2) 5769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * cross^2 >= w^2 * len2: 5779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (cross*cross >= (w+expand)*(w+expand)*len2) 5799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* outside */ 5809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Now find the distance *along* the line; this comes from the dot product 5829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * lx.x+ly.y. The actual distance (in pixels) is: 5839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 5849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * distance = dot / sqrt(len2) 5859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett dot = lx * x + ly * y; 5879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The test for 'outside' is: 5899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 5909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * distance < 0 || distance > sqrt(len2) 5919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * -> dot / sqrt(len2) > sqrt(len2) 5929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * -> dot > len2 5939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * 5949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * But 'expand' is used for the filter width and needs to be handled too: 5959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 5969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return dot > -expand && dot < len2+expand; 5979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 5989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 5999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 6009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettinside_line(const struct arg *arg, double x, double y) 6019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 0); 6039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 6049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic int 6069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettcheck_line(const struct arg *arg, double x, double y) 6079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The end caps of the line must be checked too; it's not enough just to 6099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * widen the line by FILTER_WIDTH; 'expand' exists for this purpose: 6109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 6119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 6129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett FILTER_WIDTH)) 6139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 6149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Inside the line+filter; far enough inside that the filter isn't 6159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * required? 6169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 6179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (arg->width > 2*FILTER_WIDTH && 6189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 6199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett -FILTER_WIDTH)) 6209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return INSIDE; 6219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; 6239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return OUTSIDE; 6269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 6279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic const struct 6299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const char *name; 6319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett shape_fn_ptr function[2/*fill,line*/][2]; 6329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define FN_INSIDE 0 6339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define FN_CHECK 1 6349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} shape_defs[] = 6359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "square", 6379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { { inside_square_filled, check_square_filled }, 6389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { inside_square, check_square } } 6399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett }, 6409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "circle", 6419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { { inside_circle_filled, check_circle_filled }, 6429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { inside_circle, check_circle } } 6439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett }, 6449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { "line", 6459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { { NULL, NULL }, 6469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { inside_line, check_line } } 6479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett}; 6499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#define shape_count ((sizeof shape_defs)/(sizeof shape_defs[0])) 6519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic shape_fn_ptr 6539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettshape_of(const char *arg, double width, int f) 6549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned int i; 6569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (i=0; i<shape_count; ++i) if (strcmp(shape_defs[i].name, arg) == 0) 6589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 6599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett shape_fn_ptr fn = shape_defs[i].function[width != 0][f]; 6609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (fn != NULL) 6629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return fn; 6639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: %s %s not supported\n", 6659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett width == 0 ? "filled" : "unfilled", arg); 6669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 6679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 6689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: %s: not a valid shape name\n", arg); 6709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 6719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 6729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic void 6749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettparse_arg(struct arg *arg, const char **argv/*7 arguments*/) 6759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* shape ::= color width shape x1 y1 x2 y2 */ 6779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->color = color_of(argv[0]); 6789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->width = width_of(argv[1]); 6799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->inside_fn = shape_of(argv[2], arg->width, FN_INSIDE); 6809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->check_fn = shape_of(argv[2], arg->width, FN_CHECK); 6819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->x1 = coordinate_of(argv[3]); 6829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->y1 = coordinate_of(argv[4]); 6839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->x2 = coordinate_of(argv[5]); 6849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett arg->y2 = coordinate_of(argv[6]); 6859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 6869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic png_uint_32 6889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettread_wh(const char *name, const char *str) 6899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* read a PNG width or height */ 6909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 6919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett char *ep = NULL; 6929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett unsigned long ul = strtoul(str, &ep, 10); 6939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (ep != NULL && *ep == 0 && ul > 0 && ul <= 0x7fffffff) 6959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return (png_uint_32)/*SAFE*/ul; 6969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 6979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: %s: invalid number %s\n", name, str); 6989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett exit(1); 6999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 7009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettstatic void 7029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettpixel(png_uint_16p p, struct arg *args, int nargs, double x, double y) 7039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 7049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Fill in the pixel by checking each shape (args[nargs]) for effects on 7059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the corresponding sample: 7069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 7079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett double r=0, g=0, b=0, a=0; 7089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett while (--nargs >= 0 && a != 1) 7109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* NOTE: alpha_calc can return a value outside the range 0..1 with the 7129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * bicubic filter. 7139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 7149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett const double alpha = alpha_calc(args+nargs, x, y) * (1-a); 7159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett r += alpha * args[nargs].color->red; 7179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett g += alpha * args[nargs].color->green; 7189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett b += alpha * args[nargs].color->blue; 7199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett a += alpha; 7209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 7219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* 'a' may be negative or greater than 1; if it is, negative clamp the 7239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * pixel to 0 if >1 clamp r/g/b: 7249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 72506f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett if (a > 0) 7269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (a > 1) 7289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (r > 1) r = 1; 7309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (g > 1) g = 1; 7319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (b > 1) b = 1; 7329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett a = 1; 7339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 7349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* And fill in the pixel: */ 7369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett p[0] = (png_uint_16)/*SAFE*/round(r * 65535); 7379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett p[1] = (png_uint_16)/*SAFE*/round(g * 65535); 7389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett p[2] = (png_uint_16)/*SAFE*/round(b * 65535); 7399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett p[3] = (png_uint_16)/*SAFE*/round(a * 65535); 7409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 7419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 7439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett p[3] = p[2] = p[1] = p[0] = 0; 7449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 7459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettint 7479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarettmain(int argc, const char **argv) 7489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett{ 7499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int convert_to_8bit = 0; 7509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* There is one option: --8bit: */ 7529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (argc > 1 && strcmp(argv[1], "--8bit") == 0) 7539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett --argc, ++argv, convert_to_8bit = 1; 7549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (argc >= 3) 7569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_16p buffer; 7589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett int nshapes; 7599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_image image; 7609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett# define max_shapes 256 7619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett struct arg arg_list[max_shapes]; 7629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* The libpng Simplified API write code requires a fully initialized 7649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * structure. 7659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett */ 7669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett memset(&image, 0, sizeof image); 7679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.version = PNG_IMAGE_VERSION; 7689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.opaque = NULL; 7699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.width = read_wh("width", argv[1]); 7709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.height = read_wh("height", argv[2]); 7719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.format = PNG_FORMAT_LINEAR_RGB_ALPHA; 7729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.flags = 0; 7739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett image.colormap_entries = 0; 7749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Check the remainder of the arguments */ 7769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (nshapes=0; 3+7*(nshapes+1) <= argc && nshapes < max_shapes; 7779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett ++nshapes) 7789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett parse_arg(arg_list+nshapes, argv+3+7*nshapes); 7799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (3+7*nshapes != argc) 7819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: %s: too many arguments\n", argv[3+7*nshapes]); 7839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; 7849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 7859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Create the buffer: */ 7879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buffer = malloc(PNG_IMAGE_SIZE(image)); 7889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (buffer != NULL) 7909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_32 y; 7929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Write each row... */ 7949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (y=0; y<image.height; ++y) 7959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 7969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett png_uint_32 x; 7979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 7989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Each pixel in each row: */ 7999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett for (x=0; x<image.width; ++x) 8009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett pixel(buffer + 4*(x + y*image.width), arg_list, nshapes, x, y); 8019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 8029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Write the result (to stdout) */ 8049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett if (png_image_write_to_stdio(&image, stdout, convert_to_8bit, 8059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett buffer, 0/*row_stride*/, NULL/*colormap*/)) 8069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 8079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(buffer); 8089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 0; /* success */ 8099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 8109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 8129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: write stdout: %s\n", image.message); 8139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett free(buffer); 8159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 8169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 8189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: out of memory: %lu bytes\n", 8199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett (unsigned long)PNG_IMAGE_SIZE(image)); 8209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 8219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett else 8239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett { 8249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett /* Wrong number of arguments */ 8259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett fprintf(stderr, "genpng: usage: genpng [--8bit] width height {shape}\n" 8269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Generate a transparent PNG in RGBA (truecolor+alpha) format\n" 8279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " containing the given shape or shapes. Shapes are defined:\n" 8289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " shape ::= color width shape x1 y1 x2 y2\n" 8309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " color ::= black|white|red|green|yellow|blue\n" 8319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " color ::= brown|purple|pink|orange|gray|cyan\n" 8329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " width ::= filled|<number>\n" 8339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " shape ::= circle|square|line\n" 8349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " x1,x2 ::= <number>\n" 8359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " y1,y2 ::= <number>\n" 8369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Numbers are floating point numbers describing points relative to\n" 8389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " the top left of the output PNG as pixel coordinates. The 'width'\n" 8399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " parameter is either the width of the line (in output pixels) used\n" 8409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " to draw the shape or 'filled' to indicate that the shape should\n" 8419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " be filled with the color.\n" 8429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Colors are interpreted loosely to give access to the eight full\n" 8449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " intensity RGB values:\n" 8459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " black, red, green, blue, yellow, cyan, purple, white,\n" 8479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8489b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " Cyan is full intensity blue+green; RGB(0,1,1), plus the following\n" 8499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " lower intensity values:\n" 8509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " brown: red+orange: RGB(0.5, 0.125, 0) (dark red+orange)\n" 8529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " pink: red+white: RGB(1.0, 0.5, 0.5)\n" 8539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " orange: red+yellow: RGB(1.0, 0.5, 0)\n" 8549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " gray: black+white: RGB(0.5, 0.5, 0.5)\n" 8559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " The RGB values are selected to make detection of aliasing errors\n" 8579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " easy. The names are selected to make the description of errors\n" 8589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " easy.\n" 8599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett "\n" 8609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " The PNG is written to stdout, if --8bit is given a 32bpp RGBA sRGB\n" 8619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " file is produced, otherwise a 64bpp RGBA linear encoded file is\n" 8629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett " written.\n"); 8639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett } 8649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett 8659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett return 1; 8669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett} 8679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* SIMPLIFIED_WRITE && STDIO */ 868