xref: /aosp_15_r20/external/libpng/contrib/tools/genpng.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker /* genpng
2*a67afe4dSAndroid Build Coastguard Worker  *
3*a67afe4dSAndroid Build Coastguard Worker  * COPYRIGHT: Written by John Cunningham Bowler, 2015.
4*a67afe4dSAndroid Build Coastguard Worker  * Revised by Glenn Randers-Pehrson, 2017, to add buffer-size check.
5*a67afe4dSAndroid Build Coastguard Worker  * To the extent possible under law, the authors have waived all copyright and
6*a67afe4dSAndroid Build Coastguard Worker  * related or neighboring rights to this work.  This work is published from:
7*a67afe4dSAndroid Build Coastguard Worker  * United States.
8*a67afe4dSAndroid Build Coastguard Worker  *
9*a67afe4dSAndroid Build Coastguard Worker  * Generate a PNG with an alpha channel, correctly.
10*a67afe4dSAndroid Build Coastguard Worker  *
11*a67afe4dSAndroid Build Coastguard Worker  * This is a test case generator; the resultant PNG files are only of interest
12*a67afe4dSAndroid Build Coastguard Worker  * to those of us who care about whether the edges of circles are green, red,
13*a67afe4dSAndroid Build Coastguard Worker  * or yellow.
14*a67afe4dSAndroid Build Coastguard Worker  *
15*a67afe4dSAndroid Build Coastguard Worker  * The program generates an RGB+Alpha PNG of a given size containing the given
16*a67afe4dSAndroid Build Coastguard Worker  * shapes on a transparent background:
17*a67afe4dSAndroid Build Coastguard Worker  *
18*a67afe4dSAndroid Build Coastguard Worker  *  genpng width height { shape }
19*a67afe4dSAndroid Build Coastguard Worker  *    shape ::= color width shape x1 y1 x2 y2
20*a67afe4dSAndroid Build Coastguard Worker  *
21*a67afe4dSAndroid Build Coastguard Worker  * 'color' is:
22*a67afe4dSAndroid Build Coastguard Worker  *
23*a67afe4dSAndroid Build Coastguard Worker  *  black white red green yellow blue brown purple pink orange gray cyan
24*a67afe4dSAndroid Build Coastguard Worker  *
25*a67afe4dSAndroid Build Coastguard Worker  * The point is to have colors that are linguistically meaningful plus that old
26*a67afe4dSAndroid Build Coastguard Worker  * bugbear of the department store dress murders, Cyan, the only color we argue
27*a67afe4dSAndroid Build Coastguard Worker  * about.
28*a67afe4dSAndroid Build Coastguard Worker  *
29*a67afe4dSAndroid Build Coastguard Worker  * 'shape' is:
30*a67afe4dSAndroid Build Coastguard Worker  *
31*a67afe4dSAndroid Build Coastguard Worker  *  circle: an ellipse
32*a67afe4dSAndroid Build Coastguard Worker  *  square: a rectangle
33*a67afe4dSAndroid Build Coastguard Worker  *  line: a straight line
34*a67afe4dSAndroid Build Coastguard Worker  *
35*a67afe4dSAndroid Build Coastguard Worker  * Each shape is followed by four numbers, these are two points in the output
36*a67afe4dSAndroid Build Coastguard Worker  * coordinate space (as real numbers) which describe the circle, square, or
37*a67afe4dSAndroid Build Coastguard Worker  * line.  The shape is filled if it is preceded by 'filled' (not valid for
38*a67afe4dSAndroid Build Coastguard Worker  * 'line') or is drawn with a line, in which case the width of the line must
39*a67afe4dSAndroid Build Coastguard Worker  * precede the shape.
40*a67afe4dSAndroid Build Coastguard Worker  *
41*a67afe4dSAndroid Build Coastguard Worker  * The whole set of information can be repeated as many times as desired:
42*a67afe4dSAndroid Build Coastguard Worker  *
43*a67afe4dSAndroid Build Coastguard Worker  *    shape ::= color width shape x1 y1 x2 y2
44*a67afe4dSAndroid Build Coastguard Worker  *
45*a67afe4dSAndroid Build Coastguard Worker  *    color ::= black|white|red|green|yellow|blue
46*a67afe4dSAndroid Build Coastguard Worker  *    color ::= brown|purple|pink|orange|gray|cyan
47*a67afe4dSAndroid Build Coastguard Worker  *    width ::= filled
48*a67afe4dSAndroid Build Coastguard Worker  *    width ::= <number>
49*a67afe4dSAndroid Build Coastguard Worker  *    shape ::= circle|square|line
50*a67afe4dSAndroid Build Coastguard Worker  *    x1    ::= <number>
51*a67afe4dSAndroid Build Coastguard Worker  *    x2    ::= <number>
52*a67afe4dSAndroid Build Coastguard Worker  *    y1    ::= <number>
53*a67afe4dSAndroid Build Coastguard Worker  *    y2    ::= <number>
54*a67afe4dSAndroid Build Coastguard Worker  *
55*a67afe4dSAndroid Build Coastguard Worker  * The output PNG is generated by down-sampling a 4x supersampled image using
56*a67afe4dSAndroid Build Coastguard Worker  * a bi-cubic filter.  The bi-cubic has a 2 (output) pixel width, so an 8x8
57*a67afe4dSAndroid Build Coastguard Worker  * array of super-sampled points contribute to each output pixel.  The value of
58*a67afe4dSAndroid Build Coastguard Worker  * a super-sampled point is found using an unfiltered, aliased, infinite
59*a67afe4dSAndroid Build Coastguard Worker  * precision image: Each shape from the last to the first is checked to see if
60*a67afe4dSAndroid Build Coastguard Worker  * the point is in the drawn area and, if it is, the color of the point is the
61*a67afe4dSAndroid Build Coastguard Worker  * color of the shape and the alpha is 1, if not the previous shape is checked.
62*a67afe4dSAndroid Build Coastguard Worker  *
63*a67afe4dSAndroid Build Coastguard Worker  * This is an aliased algorithm because no filtering is done; a point is either
64*a67afe4dSAndroid Build Coastguard Worker  * inside or outside each shape and 'close' points do not contribute to the
65*a67afe4dSAndroid Build Coastguard Worker  * sample.  The down-sampling is relied on to correct the error of not using
66*a67afe4dSAndroid Build Coastguard Worker  * a filter.
67*a67afe4dSAndroid Build Coastguard Worker  *
68*a67afe4dSAndroid Build Coastguard Worker  * The line end-caps are 'flat'; they go through the points.  The square line
69*a67afe4dSAndroid Build Coastguard Worker  * joins are mitres; the outside of the lines are continued to the point of
70*a67afe4dSAndroid Build Coastguard Worker  * intersection.
71*a67afe4dSAndroid Build Coastguard Worker  */
72*a67afe4dSAndroid Build Coastguard Worker 
73*a67afe4dSAndroid Build Coastguard Worker #include <stddef.h>
74*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
75*a67afe4dSAndroid Build Coastguard Worker #include <string.h>
76*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
77*a67afe4dSAndroid Build Coastguard Worker #include <math.h>
78*a67afe4dSAndroid Build Coastguard Worker 
79*a67afe4dSAndroid Build Coastguard Worker /* Normally use <png.h> here to get the installed libpng, but this is done to
80*a67afe4dSAndroid Build Coastguard Worker  * ensure the code picks up the local libpng implementation:
81*a67afe4dSAndroid Build Coastguard Worker  */
82*a67afe4dSAndroid Build Coastguard Worker #include "../../png.h"
83*a67afe4dSAndroid Build Coastguard Worker 
84*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
85*a67afe4dSAndroid Build Coastguard Worker 
86*a67afe4dSAndroid Build Coastguard Worker static const struct color
87*a67afe4dSAndroid Build Coastguard Worker {
88*a67afe4dSAndroid Build Coastguard Worker    const char *name;
89*a67afe4dSAndroid Build Coastguard Worker    double      red;
90*a67afe4dSAndroid Build Coastguard Worker    double      green;
91*a67afe4dSAndroid Build Coastguard Worker    double      blue;
92*a67afe4dSAndroid Build Coastguard Worker } colors[] =
93*a67afe4dSAndroid Build Coastguard Worker /* color ::= black|white|red|green|yellow|blue
94*a67afe4dSAndroid Build Coastguard Worker  * color ::= brown|purple|pink|orange|gray|cyan
95*a67afe4dSAndroid Build Coastguard Worker  */
96*a67afe4dSAndroid Build Coastguard Worker {
97*a67afe4dSAndroid Build Coastguard Worker    { "black",   0,    0,  0 },
98*a67afe4dSAndroid Build Coastguard Worker    { "white",   1,    1,  1 },
99*a67afe4dSAndroid Build Coastguard Worker    { "red",     1,    0,  0 },
100*a67afe4dSAndroid Build Coastguard Worker    { "green",   0,    1,  0 },
101*a67afe4dSAndroid Build Coastguard Worker    { "yellow",  1,    1,  0 },
102*a67afe4dSAndroid Build Coastguard Worker    { "blue",    0,    0,  1 },
103*a67afe4dSAndroid Build Coastguard Worker    { "brown",  .5, .125,  0 },
104*a67afe4dSAndroid Build Coastguard Worker    { "purple",  1,    0,  1 },
105*a67afe4dSAndroid Build Coastguard Worker    { "pink",    1,   .5, .5 },
106*a67afe4dSAndroid Build Coastguard Worker    { "orange",  1,   .5,  0 },
107*a67afe4dSAndroid Build Coastguard Worker    { "gray",    0,   .5, .5 },
108*a67afe4dSAndroid Build Coastguard Worker    { "cyan",    0,    1,  1 }
109*a67afe4dSAndroid Build Coastguard Worker };
110*a67afe4dSAndroid Build Coastguard Worker #define color_count ((sizeof colors)/(sizeof colors[0]))
111*a67afe4dSAndroid Build Coastguard Worker 
112*a67afe4dSAndroid Build Coastguard Worker static const struct color *
color_of(const char * arg)113*a67afe4dSAndroid Build Coastguard Worker color_of(const char *arg)
114*a67afe4dSAndroid Build Coastguard Worker {
115*a67afe4dSAndroid Build Coastguard Worker    int icolor = color_count;
116*a67afe4dSAndroid Build Coastguard Worker 
117*a67afe4dSAndroid Build Coastguard Worker    while (--icolor >= 0)
118*a67afe4dSAndroid Build Coastguard Worker    {
119*a67afe4dSAndroid Build Coastguard Worker       if (strcmp(colors[icolor].name, arg) == 0)
120*a67afe4dSAndroid Build Coastguard Worker          return colors+icolor;
121*a67afe4dSAndroid Build Coastguard Worker    }
122*a67afe4dSAndroid Build Coastguard Worker 
123*a67afe4dSAndroid Build Coastguard Worker    fprintf(stderr, "genpng: invalid color %s\n", arg);
124*a67afe4dSAndroid Build Coastguard Worker    exit(1);
125*a67afe4dSAndroid Build Coastguard Worker }
126*a67afe4dSAndroid Build Coastguard Worker 
127*a67afe4dSAndroid Build Coastguard Worker static double
width_of(const char * arg)128*a67afe4dSAndroid Build Coastguard Worker width_of(const char *arg)
129*a67afe4dSAndroid Build Coastguard Worker {
130*a67afe4dSAndroid Build Coastguard Worker    if (strcmp(arg, "filled") == 0)
131*a67afe4dSAndroid Build Coastguard Worker       return 0;
132*a67afe4dSAndroid Build Coastguard Worker 
133*a67afe4dSAndroid Build Coastguard Worker    else
134*a67afe4dSAndroid Build Coastguard Worker    {
135*a67afe4dSAndroid Build Coastguard Worker       char *ep = NULL;
136*a67afe4dSAndroid Build Coastguard Worker       double w = strtod(arg, &ep);
137*a67afe4dSAndroid Build Coastguard Worker 
138*a67afe4dSAndroid Build Coastguard Worker       if (ep != NULL && *ep == 0 && w > 0)
139*a67afe4dSAndroid Build Coastguard Worker          return w;
140*a67afe4dSAndroid Build Coastguard Worker    }
141*a67afe4dSAndroid Build Coastguard Worker 
142*a67afe4dSAndroid Build Coastguard Worker    fprintf(stderr, "genpng: invalid line width %s\n", arg);
143*a67afe4dSAndroid Build Coastguard Worker    exit(1);
144*a67afe4dSAndroid Build Coastguard Worker }
145*a67afe4dSAndroid Build Coastguard Worker 
146*a67afe4dSAndroid Build Coastguard Worker static double
coordinate_of(const char * arg)147*a67afe4dSAndroid Build Coastguard Worker coordinate_of(const char *arg)
148*a67afe4dSAndroid Build Coastguard Worker {
149*a67afe4dSAndroid Build Coastguard Worker    char *ep = NULL;
150*a67afe4dSAndroid Build Coastguard Worker    double w = strtod(arg, &ep);
151*a67afe4dSAndroid Build Coastguard Worker 
152*a67afe4dSAndroid Build Coastguard Worker    if (ep != NULL && *ep == 0)
153*a67afe4dSAndroid Build Coastguard Worker       return w;
154*a67afe4dSAndroid Build Coastguard Worker 
155*a67afe4dSAndroid Build Coastguard Worker    fprintf(stderr, "genpng: invalid coordinate value %s\n", arg);
156*a67afe4dSAndroid Build Coastguard Worker    exit(1);
157*a67afe4dSAndroid Build Coastguard Worker }
158*a67afe4dSAndroid Build Coastguard Worker 
159*a67afe4dSAndroid Build Coastguard Worker struct arg; /* forward declaration */
160*a67afe4dSAndroid Build Coastguard Worker 
161*a67afe4dSAndroid Build Coastguard Worker typedef int (*shape_fn_ptr)(const struct arg *arg, double x, double y);
162*a67afe4dSAndroid Build Coastguard Worker    /* A function to determine if (x,y) is inside the shape.
163*a67afe4dSAndroid Build Coastguard Worker     *
164*a67afe4dSAndroid Build Coastguard Worker     * There are two implementations:
165*a67afe4dSAndroid Build Coastguard Worker     *
166*a67afe4dSAndroid Build Coastguard Worker     *    inside_fn: returns true if the point is inside
167*a67afe4dSAndroid Build Coastguard Worker     *    check_fn:  returns;
168*a67afe4dSAndroid Build Coastguard Worker     *       -1: the point is outside the shape by more than the filter width (2)
169*a67afe4dSAndroid Build Coastguard Worker     *        0: the point may be inside the shape
170*a67afe4dSAndroid Build Coastguard Worker     *       +1: the point is inside the shape by more than the filter width
171*a67afe4dSAndroid Build Coastguard Worker     */
172*a67afe4dSAndroid Build Coastguard Worker #define OUTSIDE (-1)
173*a67afe4dSAndroid Build Coastguard Worker #define INSIDE  (1)
174*a67afe4dSAndroid Build Coastguard Worker 
175*a67afe4dSAndroid Build Coastguard Worker struct arg
176*a67afe4dSAndroid Build Coastguard Worker {
177*a67afe4dSAndroid Build Coastguard Worker    const struct color *color;
178*a67afe4dSAndroid Build Coastguard Worker    shape_fn_ptr        inside_fn;
179*a67afe4dSAndroid Build Coastguard Worker    shape_fn_ptr        check_fn;
180*a67afe4dSAndroid Build Coastguard Worker    double              width; /* line width, 0 for 'filled' */
181*a67afe4dSAndroid Build Coastguard Worker    double              x1, y1, x2, y2;
182*a67afe4dSAndroid Build Coastguard Worker };
183*a67afe4dSAndroid Build Coastguard Worker 
184*a67afe4dSAndroid Build Coastguard Worker /* IMPLEMENTATION NOTE:
185*a67afe4dSAndroid Build Coastguard Worker  *
186*a67afe4dSAndroid Build Coastguard Worker  * We want the contribution of each shape to the sample corresponding to each
187*a67afe4dSAndroid Build Coastguard Worker  * pixel.  This could be obtained by super sampling the image to infinite
188*a67afe4dSAndroid Build Coastguard Worker  * dimensions, finding each point within the shape and assigning that a value
189*a67afe4dSAndroid Build Coastguard Worker  * '1' while leaving every point outside the shape with value '0' then
190*a67afe4dSAndroid Build Coastguard Worker  * downsampling to the image size with sinc; computationally very expensive.
191*a67afe4dSAndroid Build Coastguard Worker  *
192*a67afe4dSAndroid Build Coastguard Worker  * Approximations are as follows:
193*a67afe4dSAndroid Build Coastguard Worker  *
194*a67afe4dSAndroid Build Coastguard Worker  * 1) If the pixel coordinate is within the shape assume the sample has the
195*a67afe4dSAndroid Build Coastguard Worker  *    shape color and is opaque, else assume there is no contribution from
196*a67afe4dSAndroid Build Coastguard Worker  *    the shape.
197*a67afe4dSAndroid Build Coastguard Worker  *
198*a67afe4dSAndroid Build Coastguard Worker  *    This is the equivalent of aliased rendering or resampling an image with
199*a67afe4dSAndroid Build Coastguard Worker  *    a block filter.  The maximum error in the calculated alpha (which will
200*a67afe4dSAndroid Build Coastguard Worker  *    always be 0 or 1) is 0.5.
201*a67afe4dSAndroid Build Coastguard Worker  *
202*a67afe4dSAndroid Build Coastguard Worker  * 2) If the shape is within a square of size 1x1 centered on the pixel assume
203*a67afe4dSAndroid Build Coastguard Worker  *    that the shape obscures an amount of the pixel equal to its area within
204*a67afe4dSAndroid Build Coastguard Worker  *    that square.
205*a67afe4dSAndroid Build Coastguard Worker  *
206*a67afe4dSAndroid Build Coastguard Worker  *    This is the equivalent of 'pixel coverage' alpha calculation or resampling
207*a67afe4dSAndroid Build Coastguard Worker  *    an image with a bi-linear filter.  The maximum error is over 0.2, but the
208*a67afe4dSAndroid Build Coastguard Worker  *    results are often acceptable.
209*a67afe4dSAndroid Build Coastguard Worker  *
210*a67afe4dSAndroid Build Coastguard Worker  *    This can be approximated by applying (1) to a super-sampled image then
211*a67afe4dSAndroid Build Coastguard Worker  *    downsampling with a bi-linear filter.  The error in the super-sampled
212*a67afe4dSAndroid Build Coastguard Worker  *    image is 0.5 per sample, but the resampling reduces this.
213*a67afe4dSAndroid Build Coastguard Worker  *
214*a67afe4dSAndroid Build Coastguard Worker  * 3) Use a better filter with a super-sampled image; in the limit this is the
215*a67afe4dSAndroid Build Coastguard Worker  *    sinc() approach.
216*a67afe4dSAndroid Build Coastguard Worker  *
217*a67afe4dSAndroid Build Coastguard Worker  * 4) Do the geometric calculation; a bivariate definite integral across the
218*a67afe4dSAndroid Build Coastguard Worker  *    shape, unfortunately this means evaluating Si(x), the integral of sinc(x),
219*a67afe4dSAndroid Build Coastguard Worker  *    which is still a lot of math.
220*a67afe4dSAndroid Build Coastguard Worker  *
221*a67afe4dSAndroid Build Coastguard Worker  * This code uses approach (3) with a bi-cubic filter and 8x super-sampling
222*a67afe4dSAndroid Build Coastguard Worker  * and method (1) for the super-samples.  This means that the sample is either
223*a67afe4dSAndroid Build Coastguard Worker  * 0 or 1, depending on whether the sub-pixel is within or outside the shape.
224*a67afe4dSAndroid Build Coastguard Worker  * The bi-cubic weights are also fixed and the 16 required weights are
225*a67afe4dSAndroid Build Coastguard Worker  * pre-computed here (note that the 'scale' setting will need to be changed if
226*a67afe4dSAndroid Build Coastguard Worker  * 'super' is increased).
227*a67afe4dSAndroid Build Coastguard Worker  *
228*a67afe4dSAndroid Build Coastguard Worker  * The code also calculates a sum to the edge of the filter. This is not
229*a67afe4dSAndroid Build Coastguard Worker  * currently used by could be used to optimize the calculation.
230*a67afe4dSAndroid Build Coastguard Worker  */
231*a67afe4dSAndroid Build Coastguard Worker #if 0 /* bc code */
232*a67afe4dSAndroid Build Coastguard Worker scale=10
233*a67afe4dSAndroid Build Coastguard Worker super=8
234*a67afe4dSAndroid Build Coastguard Worker define bicubic(x) {
235*a67afe4dSAndroid Build Coastguard Worker    if (x <= 1) return (1.5*x - 2.5)*x*x + 1;
236*a67afe4dSAndroid Build Coastguard Worker    if (x <  2) return (((2.5 - 0.5*x)*x - 4)*x + 2);
237*a67afe4dSAndroid Build Coastguard Worker    return 0;
238*a67afe4dSAndroid Build Coastguard Worker }
239*a67afe4dSAndroid Build Coastguard Worker define sum(x) {
240*a67afe4dSAndroid Build Coastguard Worker    auto s;
241*a67afe4dSAndroid Build Coastguard Worker    s = 0;
242*a67afe4dSAndroid Build Coastguard Worker    while (x < 2*super) {
243*a67afe4dSAndroid Build Coastguard Worker       s = s + bicubic(x/super);
244*a67afe4dSAndroid Build Coastguard Worker       x = x + 1;
245*a67afe4dSAndroid Build Coastguard Worker    }
246*a67afe4dSAndroid Build Coastguard Worker    return s;
247*a67afe4dSAndroid Build Coastguard Worker }
248*a67afe4dSAndroid Build Coastguard Worker define results(x) {
249*a67afe4dSAndroid Build Coastguard Worker    auto b, s;
250*a67afe4dSAndroid Build Coastguard Worker    b = bicubic(x/super);
251*a67afe4dSAndroid Build Coastguard Worker    s = sum(x);
252*a67afe4dSAndroid Build Coastguard Worker 
253*a67afe4dSAndroid Build Coastguard Worker    print "   /*", x, "*/ { ", b, ", ", s, " }";
254*a67afe4dSAndroid Build Coastguard Worker    return 1;
255*a67afe4dSAndroid Build Coastguard Worker }
256*a67afe4dSAndroid Build Coastguard Worker x=0
257*a67afe4dSAndroid Build Coastguard Worker while (x<2*super) {
258*a67afe4dSAndroid Build Coastguard Worker    x = x + results(x)
259*a67afe4dSAndroid Build Coastguard Worker    if (x < 2*super) print ","
260*a67afe4dSAndroid Build Coastguard Worker    print "\n"
261*a67afe4dSAndroid Build Coastguard Worker }
262*a67afe4dSAndroid Build Coastguard Worker quit
263*a67afe4dSAndroid Build Coastguard Worker #endif
264*a67afe4dSAndroid Build Coastguard Worker 
265*a67afe4dSAndroid Build Coastguard Worker #define BICUBIC1(x) /*     |x| <= 1 */ ((1.5*(x)* - 2.5)*(x)*(x) + 1)
266*a67afe4dSAndroid Build Coastguard Worker #define BICUBIC2(x) /* 1 < |x| <  2 */ (((2.5 - 0.5*(x))*(x) - 4)*(x) + 2)
267*a67afe4dSAndroid Build Coastguard Worker #define FILTER_WEIGHT 9 /* Twice the first sum below */
268*a67afe4dSAndroid Build Coastguard Worker #define FILTER_WIDTH  2 /* Actually half the width; -2..+2 */
269*a67afe4dSAndroid Build Coastguard Worker #define FILTER_STEPS  8 /* steps per filter unit */
270*a67afe4dSAndroid Build Coastguard Worker static const double
271*a67afe4dSAndroid Build Coastguard Worker bicubic[16][2] =
272*a67afe4dSAndroid Build Coastguard Worker {
273*a67afe4dSAndroid Build Coastguard Worker    /* These numbers are exact; the weight for the filter is 1/9, but this
274*a67afe4dSAndroid Build Coastguard Worker     * would make the numbers inexact, so it is not included here.
275*a67afe4dSAndroid Build Coastguard Worker     */
276*a67afe4dSAndroid Build Coastguard Worker    /*          bicubic      sum        */
277*a67afe4dSAndroid Build Coastguard Worker    /* 0*/ { 1.0000000000, 4.5000000000 },
278*a67afe4dSAndroid Build Coastguard Worker    /* 1*/ {  .9638671875, 3.5000000000 },
279*a67afe4dSAndroid Build Coastguard Worker    /* 2*/ {  .8671875000, 2.5361328125 },
280*a67afe4dSAndroid Build Coastguard Worker    /* 3*/ {  .7275390625, 1.6689453125 },
281*a67afe4dSAndroid Build Coastguard Worker    /* 4*/ {  .5625000000,  .9414062500 },
282*a67afe4dSAndroid Build Coastguard Worker    /* 5*/ {  .3896484375,  .3789062500 },
283*a67afe4dSAndroid Build Coastguard Worker    /* 6*/ {  .2265625000, -.0107421875 },
284*a67afe4dSAndroid Build Coastguard Worker    /* 7*/ {  .0908203125, -.2373046875 },
285*a67afe4dSAndroid Build Coastguard Worker    /* 8*/ {            0, -.3281250000 },
286*a67afe4dSAndroid Build Coastguard Worker    /* 9*/ { -.0478515625, -.3281250000 },
287*a67afe4dSAndroid Build Coastguard Worker    /*10*/ { -.0703125000, -.2802734375 },
288*a67afe4dSAndroid Build Coastguard Worker    /*11*/ { -.0732421875, -.2099609375 },
289*a67afe4dSAndroid Build Coastguard Worker    /*12*/ { -.0625000000, -.1367187500 },
290*a67afe4dSAndroid Build Coastguard Worker    /*13*/ { -.0439453125, -.0742187500 },
291*a67afe4dSAndroid Build Coastguard Worker    /*14*/ { -.0234375000, -.0302734375 },
292*a67afe4dSAndroid Build Coastguard Worker    /*15*/ { -.0068359375, -.0068359375 }
293*a67afe4dSAndroid Build Coastguard Worker };
294*a67afe4dSAndroid Build Coastguard Worker 
295*a67afe4dSAndroid Build Coastguard Worker static double
alpha_calc(const struct arg * arg,double x,double y)296*a67afe4dSAndroid Build Coastguard Worker alpha_calc(const struct arg *arg, double x, double y)
297*a67afe4dSAndroid Build Coastguard Worker {
298*a67afe4dSAndroid Build Coastguard Worker    /* For [x-2..x+2],[y-2,y+2] calculate the weighted bicubic given a function
299*a67afe4dSAndroid Build Coastguard Worker     * which tells us whether a point is inside or outside the shape.  First
300*a67afe4dSAndroid Build Coastguard Worker     * check if we need to do this at all:
301*a67afe4dSAndroid Build Coastguard Worker     */
302*a67afe4dSAndroid Build Coastguard Worker    switch (arg->check_fn(arg, x, y))
303*a67afe4dSAndroid Build Coastguard Worker    {
304*a67afe4dSAndroid Build Coastguard Worker       case OUTSIDE:
305*a67afe4dSAndroid Build Coastguard Worker          return 0; /* all samples outside the shape */
306*a67afe4dSAndroid Build Coastguard Worker 
307*a67afe4dSAndroid Build Coastguard Worker       case INSIDE:
308*a67afe4dSAndroid Build Coastguard Worker          return 1; /* all samples inside the shape */
309*a67afe4dSAndroid Build Coastguard Worker 
310*a67afe4dSAndroid Build Coastguard Worker       default:
311*a67afe4dSAndroid Build Coastguard Worker       {
312*a67afe4dSAndroid Build Coastguard Worker          int dy;
313*a67afe4dSAndroid Build Coastguard Worker          double alpha = 0;
314*a67afe4dSAndroid Build Coastguard Worker 
315*a67afe4dSAndroid Build Coastguard Worker #        define FILTER_D (FILTER_WIDTH*FILTER_STEPS-1)
316*a67afe4dSAndroid Build Coastguard Worker          for (dy=-FILTER_D; dy<=FILTER_D; ++dy)
317*a67afe4dSAndroid Build Coastguard Worker          {
318*a67afe4dSAndroid Build Coastguard Worker             double wy = bicubic[abs(dy)][0];
319*a67afe4dSAndroid Build Coastguard Worker 
320*a67afe4dSAndroid Build Coastguard Worker             if (wy != 0)
321*a67afe4dSAndroid Build Coastguard Worker             {
322*a67afe4dSAndroid Build Coastguard Worker                double alphay = 0;
323*a67afe4dSAndroid Build Coastguard Worker                int dx;
324*a67afe4dSAndroid Build Coastguard Worker 
325*a67afe4dSAndroid Build Coastguard Worker                for (dx=-FILTER_D; dx<=FILTER_D; ++dx)
326*a67afe4dSAndroid Build Coastguard Worker                {
327*a67afe4dSAndroid Build Coastguard Worker                   double wx = bicubic[abs(dx)][0];
328*a67afe4dSAndroid Build Coastguard Worker 
329*a67afe4dSAndroid Build Coastguard Worker                   if (wx != 0 && arg->inside_fn(arg, x+dx/16, y+dy/16))
330*a67afe4dSAndroid Build Coastguard Worker                      alphay += wx;
331*a67afe4dSAndroid Build Coastguard Worker                }
332*a67afe4dSAndroid Build Coastguard Worker 
333*a67afe4dSAndroid Build Coastguard Worker                alpha += wy * alphay;
334*a67afe4dSAndroid Build Coastguard Worker             }
335*a67afe4dSAndroid Build Coastguard Worker          }
336*a67afe4dSAndroid Build Coastguard Worker 
337*a67afe4dSAndroid Build Coastguard Worker          /* This needs to be weighted for each dimension: */
338*a67afe4dSAndroid Build Coastguard Worker          return alpha / (FILTER_WEIGHT*FILTER_WEIGHT);
339*a67afe4dSAndroid Build Coastguard Worker       }
340*a67afe4dSAndroid Build Coastguard Worker    }
341*a67afe4dSAndroid Build Coastguard Worker }
342*a67afe4dSAndroid Build Coastguard Worker 
343*a67afe4dSAndroid Build Coastguard Worker /* These are the shape functions. */
344*a67afe4dSAndroid Build Coastguard Worker /* "square",
345*a67afe4dSAndroid Build Coastguard Worker  * { inside_square_filled, check_square_filled },
346*a67afe4dSAndroid Build Coastguard Worker  * { inside_square, check_square }
347*a67afe4dSAndroid Build Coastguard Worker  */
348*a67afe4dSAndroid Build Coastguard Worker static int
square_check(double x,double y,double x1,double y1,double x2,double y2)349*a67afe4dSAndroid Build Coastguard Worker square_check(double x, double y, double x1, double y1, double x2, double y2)
350*a67afe4dSAndroid Build Coastguard Worker    /* Is x,y inside the square (x1,y1)..(x2,y2)? */
351*a67afe4dSAndroid Build Coastguard Worker {
352*a67afe4dSAndroid Build Coastguard Worker    /* Do a modified Cohen-Sutherland on one point, bit patterns that indicate
353*a67afe4dSAndroid Build Coastguard Worker     * 'outside' are:
354*a67afe4dSAndroid Build Coastguard Worker     *
355*a67afe4dSAndroid Build Coastguard Worker     *   x<x1 | x<y1 | x<x2 | x<y2
356*a67afe4dSAndroid Build Coastguard Worker     *    0      x      0      x     To the right
357*a67afe4dSAndroid Build Coastguard Worker     *    1      x      1      x     To the left
358*a67afe4dSAndroid Build Coastguard Worker     *    x      0      x      0     Below
359*a67afe4dSAndroid Build Coastguard Worker     *    x      1      x      1     Above
360*a67afe4dSAndroid Build Coastguard Worker     *
361*a67afe4dSAndroid Build Coastguard Worker     * So 'inside' is (x<x1) != (x<x2) && (y<y1) != (y<y2);
362*a67afe4dSAndroid Build Coastguard Worker     */
363*a67afe4dSAndroid Build Coastguard Worker    return ((x<x1) ^ (x<x2)) & ((y<y1) ^ (y<y2));
364*a67afe4dSAndroid Build Coastguard Worker }
365*a67afe4dSAndroid Build Coastguard Worker 
366*a67afe4dSAndroid Build Coastguard Worker static int
inside_square_filled(const struct arg * arg,double x,double y)367*a67afe4dSAndroid Build Coastguard Worker inside_square_filled(const struct arg *arg, double x, double y)
368*a67afe4dSAndroid Build Coastguard Worker {
369*a67afe4dSAndroid Build Coastguard Worker    return square_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2);
370*a67afe4dSAndroid Build Coastguard Worker }
371*a67afe4dSAndroid Build Coastguard Worker 
372*a67afe4dSAndroid Build Coastguard Worker static int
square_check_line(const struct arg * arg,double x,double y,double w)373*a67afe4dSAndroid Build Coastguard Worker square_check_line(const struct arg *arg, double x, double y, double w)
374*a67afe4dSAndroid Build Coastguard Worker    /* Check for a point being inside the boundaries implied by the given arg
375*a67afe4dSAndroid Build Coastguard Worker     * and assuming a width 2*w each side of the boundaries.  This returns the
376*a67afe4dSAndroid Build Coastguard Worker     * 'check' INSIDE/OUTSIDE/0 result but note the semantics:
377*a67afe4dSAndroid Build Coastguard Worker     *
378*a67afe4dSAndroid Build Coastguard Worker     *          +--------------+
379*a67afe4dSAndroid Build Coastguard Worker     *          |              |   OUTSIDE
380*a67afe4dSAndroid Build Coastguard Worker     *          |   INSIDE     |
381*a67afe4dSAndroid Build Coastguard Worker     *          |              |
382*a67afe4dSAndroid Build Coastguard Worker     *          +--------------+
383*a67afe4dSAndroid Build Coastguard Worker     *
384*a67afe4dSAndroid Build Coastguard Worker     * And '0' means within the line boundaries.
385*a67afe4dSAndroid Build Coastguard Worker     */
386*a67afe4dSAndroid Build Coastguard Worker {
387*a67afe4dSAndroid Build Coastguard Worker    double cx = (arg->x1+arg->x2)/2;
388*a67afe4dSAndroid Build Coastguard Worker    double wx = fabs(arg->x1-arg->x2)/2;
389*a67afe4dSAndroid Build Coastguard Worker    double cy = (arg->y1+arg->y2)/2;
390*a67afe4dSAndroid Build Coastguard Worker    double wy = fabs(arg->y1-arg->y2)/2;
391*a67afe4dSAndroid Build Coastguard Worker 
392*a67afe4dSAndroid Build Coastguard Worker    if (square_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w))
393*a67afe4dSAndroid Build Coastguard Worker    {
394*a67afe4dSAndroid Build Coastguard Worker       /* Inside, but maybe too far; check for the redundant case where
395*a67afe4dSAndroid Build Coastguard Worker        * the lines overlap:
396*a67afe4dSAndroid Build Coastguard Worker        */
397*a67afe4dSAndroid Build Coastguard Worker       wx -= w;
398*a67afe4dSAndroid Build Coastguard Worker       wy -= w;
399*a67afe4dSAndroid Build Coastguard Worker       if (wx > 0 && wy > 0 && square_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy))
400*a67afe4dSAndroid Build Coastguard Worker          return INSIDE; /* between (inside) the boundary lines. */
401*a67afe4dSAndroid Build Coastguard Worker 
402*a67afe4dSAndroid Build Coastguard Worker       return 0; /* inside the lines themselves. */
403*a67afe4dSAndroid Build Coastguard Worker    }
404*a67afe4dSAndroid Build Coastguard Worker 
405*a67afe4dSAndroid Build Coastguard Worker    return OUTSIDE; /* outside the boundary lines. */
406*a67afe4dSAndroid Build Coastguard Worker }
407*a67afe4dSAndroid Build Coastguard Worker 
408*a67afe4dSAndroid Build Coastguard Worker static int
check_square_filled(const struct arg * arg,double x,double y)409*a67afe4dSAndroid Build Coastguard Worker check_square_filled(const struct arg *arg, double x, double y)
410*a67afe4dSAndroid Build Coastguard Worker {
411*a67afe4dSAndroid Build Coastguard Worker    /* The filter extends +/-FILTER_WIDTH each side of each output point, so
412*a67afe4dSAndroid Build Coastguard Worker     * the check has to expand and contract the square by that amount; '0'
413*a67afe4dSAndroid Build Coastguard Worker     * means close enough to the edge of the square that the bicubic filter has
414*a67afe4dSAndroid Build Coastguard Worker     * to be run, OUTSIDE means alpha==0, INSIDE means alpha==1.
415*a67afe4dSAndroid Build Coastguard Worker     */
416*a67afe4dSAndroid Build Coastguard Worker    return square_check_line(arg, x, y, FILTER_WIDTH);
417*a67afe4dSAndroid Build Coastguard Worker }
418*a67afe4dSAndroid Build Coastguard Worker 
419*a67afe4dSAndroid Build Coastguard Worker static int
inside_square(const struct arg * arg,double x,double y)420*a67afe4dSAndroid Build Coastguard Worker inside_square(const struct arg *arg, double x, double y)
421*a67afe4dSAndroid Build Coastguard Worker {
422*a67afe4dSAndroid Build Coastguard Worker    /* Return true if within the drawn lines, else false, no need to distinguish
423*a67afe4dSAndroid Build Coastguard Worker     * INSIDE vs OUTSIDE here:
424*a67afe4dSAndroid Build Coastguard Worker     */
425*a67afe4dSAndroid Build Coastguard Worker    return square_check_line(arg, x, y, arg->width/2) == 0;
426*a67afe4dSAndroid Build Coastguard Worker }
427*a67afe4dSAndroid Build Coastguard Worker 
428*a67afe4dSAndroid Build Coastguard Worker static int
check_square(const struct arg * arg,double x,double y)429*a67afe4dSAndroid Build Coastguard Worker check_square(const struct arg *arg, double x, double y)
430*a67afe4dSAndroid Build Coastguard Worker {
431*a67afe4dSAndroid Build Coastguard Worker    /* So for this function a result of 'INSIDE' means inside the actual lines.
432*a67afe4dSAndroid Build Coastguard Worker     */
433*a67afe4dSAndroid Build Coastguard Worker    double w = arg->width/2;
434*a67afe4dSAndroid Build Coastguard Worker 
435*a67afe4dSAndroid Build Coastguard Worker    if (square_check_line(arg, x, y, w+FILTER_WIDTH) == 0)
436*a67afe4dSAndroid Build Coastguard Worker    {
437*a67afe4dSAndroid Build Coastguard Worker       /* Somewhere close to the boundary lines. If far enough inside one of
438*a67afe4dSAndroid Build Coastguard Worker        * them then we can return INSIDE:
439*a67afe4dSAndroid Build Coastguard Worker        */
440*a67afe4dSAndroid Build Coastguard Worker       w -= FILTER_WIDTH;
441*a67afe4dSAndroid Build Coastguard Worker 
442*a67afe4dSAndroid Build Coastguard Worker       if (w > 0 && square_check_line(arg, x, y, w) == 0)
443*a67afe4dSAndroid Build Coastguard Worker          return INSIDE;
444*a67afe4dSAndroid Build Coastguard Worker 
445*a67afe4dSAndroid Build Coastguard Worker       /* Point is somewhere in the filter region: */
446*a67afe4dSAndroid Build Coastguard Worker       return 0;
447*a67afe4dSAndroid Build Coastguard Worker    }
448*a67afe4dSAndroid Build Coastguard Worker 
449*a67afe4dSAndroid Build Coastguard Worker    else /* Inside or outside the square by more than w+FILTER_WIDTH. */
450*a67afe4dSAndroid Build Coastguard Worker       return OUTSIDE;
451*a67afe4dSAndroid Build Coastguard Worker }
452*a67afe4dSAndroid Build Coastguard Worker 
453*a67afe4dSAndroid Build Coastguard Worker /* "circle",
454*a67afe4dSAndroid Build Coastguard Worker  * { inside_circle_filled, check_circle_filled },
455*a67afe4dSAndroid Build Coastguard Worker  * { inside_circle, check_circle }
456*a67afe4dSAndroid Build Coastguard Worker  *
457*a67afe4dSAndroid Build Coastguard Worker  * The functions here are analogous to the square ones; however, they check
458*a67afe4dSAndroid Build Coastguard Worker  * the corresponding ellipse as opposed to the rectangle.
459*a67afe4dSAndroid Build Coastguard Worker  */
460*a67afe4dSAndroid Build Coastguard Worker static int
circle_check(double x,double y,double x1,double y1,double x2,double y2)461*a67afe4dSAndroid Build Coastguard Worker circle_check(double x, double y, double x1, double y1, double x2, double y2)
462*a67afe4dSAndroid Build Coastguard Worker {
463*a67afe4dSAndroid Build Coastguard Worker    if (square_check(x, y, x1, y1, x2, y2))
464*a67afe4dSAndroid Build Coastguard Worker    {
465*a67afe4dSAndroid Build Coastguard Worker       /* Inside the square, so maybe inside the circle too: */
466*a67afe4dSAndroid Build Coastguard Worker       const double cx = (x1 + x2)/2;
467*a67afe4dSAndroid Build Coastguard Worker       const double cy = (y1 + y2)/2;
468*a67afe4dSAndroid Build Coastguard Worker       const double dx = x1 - x2;
469*a67afe4dSAndroid Build Coastguard Worker       const double dy = y1 - y2;
470*a67afe4dSAndroid Build Coastguard Worker 
471*a67afe4dSAndroid Build Coastguard Worker       x = (x - cx)/dx;
472*a67afe4dSAndroid Build Coastguard Worker       y = (y - cy)/dy;
473*a67afe4dSAndroid Build Coastguard Worker 
474*a67afe4dSAndroid Build Coastguard Worker       /* It is outside if the distance from the center is more than half the
475*a67afe4dSAndroid Build Coastguard Worker        * diameter:
476*a67afe4dSAndroid Build Coastguard Worker        */
477*a67afe4dSAndroid Build Coastguard Worker       return x*x+y*y < .25;
478*a67afe4dSAndroid Build Coastguard Worker    }
479*a67afe4dSAndroid Build Coastguard Worker 
480*a67afe4dSAndroid Build Coastguard Worker    return 0; /* outside */
481*a67afe4dSAndroid Build Coastguard Worker }
482*a67afe4dSAndroid Build Coastguard Worker 
483*a67afe4dSAndroid Build Coastguard Worker static int
inside_circle_filled(const struct arg * arg,double x,double y)484*a67afe4dSAndroid Build Coastguard Worker inside_circle_filled(const struct arg *arg, double x, double y)
485*a67afe4dSAndroid Build Coastguard Worker {
486*a67afe4dSAndroid Build Coastguard Worker    return circle_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2);
487*a67afe4dSAndroid Build Coastguard Worker }
488*a67afe4dSAndroid Build Coastguard Worker 
489*a67afe4dSAndroid Build Coastguard Worker static int
circle_check_line(const struct arg * arg,double x,double y,double w)490*a67afe4dSAndroid Build Coastguard Worker circle_check_line(const struct arg *arg, double x, double y, double w)
491*a67afe4dSAndroid Build Coastguard Worker    /* Check for a point being inside the boundaries implied by the given arg
492*a67afe4dSAndroid Build Coastguard Worker     * and assuming a width 2*w each side of the boundaries.  This function has
493*a67afe4dSAndroid Build Coastguard Worker     * the same semantic as square_check_line but tests the circle.
494*a67afe4dSAndroid Build Coastguard Worker     */
495*a67afe4dSAndroid Build Coastguard Worker {
496*a67afe4dSAndroid Build Coastguard Worker    double cx = (arg->x1+arg->x2)/2;
497*a67afe4dSAndroid Build Coastguard Worker    double wx = fabs(arg->x1-arg->x2)/2;
498*a67afe4dSAndroid Build Coastguard Worker    double cy = (arg->y1+arg->y2)/2;
499*a67afe4dSAndroid Build Coastguard Worker    double wy = fabs(arg->y1-arg->y2)/2;
500*a67afe4dSAndroid Build Coastguard Worker 
501*a67afe4dSAndroid Build Coastguard Worker    if (circle_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w))
502*a67afe4dSAndroid Build Coastguard Worker    {
503*a67afe4dSAndroid Build Coastguard Worker       /* Inside, but maybe too far; check for the redundant case where
504*a67afe4dSAndroid Build Coastguard Worker        * the lines overlap:
505*a67afe4dSAndroid Build Coastguard Worker        */
506*a67afe4dSAndroid Build Coastguard Worker       wx -= w;
507*a67afe4dSAndroid Build Coastguard Worker       wy -= w;
508*a67afe4dSAndroid Build Coastguard Worker       if (wx > 0 && wy > 0 && circle_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy))
509*a67afe4dSAndroid Build Coastguard Worker          return INSIDE; /* between (inside) the boundary lines. */
510*a67afe4dSAndroid Build Coastguard Worker 
511*a67afe4dSAndroid Build Coastguard Worker       return 0; /* inside the lines themselves. */
512*a67afe4dSAndroid Build Coastguard Worker    }
513*a67afe4dSAndroid Build Coastguard Worker 
514*a67afe4dSAndroid Build Coastguard Worker    return OUTSIDE; /* outside the boundary lines. */
515*a67afe4dSAndroid Build Coastguard Worker }
516*a67afe4dSAndroid Build Coastguard Worker 
517*a67afe4dSAndroid Build Coastguard Worker static int
check_circle_filled(const struct arg * arg,double x,double y)518*a67afe4dSAndroid Build Coastguard Worker check_circle_filled(const struct arg *arg, double x, double y)
519*a67afe4dSAndroid Build Coastguard Worker {
520*a67afe4dSAndroid Build Coastguard Worker    return circle_check_line(arg, x, y, FILTER_WIDTH);
521*a67afe4dSAndroid Build Coastguard Worker }
522*a67afe4dSAndroid Build Coastguard Worker 
523*a67afe4dSAndroid Build Coastguard Worker static int
inside_circle(const struct arg * arg,double x,double y)524*a67afe4dSAndroid Build Coastguard Worker inside_circle(const struct arg *arg, double x, double y)
525*a67afe4dSAndroid Build Coastguard Worker {
526*a67afe4dSAndroid Build Coastguard Worker    return circle_check_line(arg, x, y, arg->width/2) == 0;
527*a67afe4dSAndroid Build Coastguard Worker }
528*a67afe4dSAndroid Build Coastguard Worker 
529*a67afe4dSAndroid Build Coastguard Worker static int
check_circle(const struct arg * arg,double x,double y)530*a67afe4dSAndroid Build Coastguard Worker check_circle(const struct arg *arg, double x, double y)
531*a67afe4dSAndroid Build Coastguard Worker {
532*a67afe4dSAndroid Build Coastguard Worker    /* Exactly as the 'square' code.  */
533*a67afe4dSAndroid Build Coastguard Worker    double w = arg->width/2;
534*a67afe4dSAndroid Build Coastguard Worker 
535*a67afe4dSAndroid Build Coastguard Worker    if (circle_check_line(arg, x, y, w+FILTER_WIDTH) == 0)
536*a67afe4dSAndroid Build Coastguard Worker    {
537*a67afe4dSAndroid Build Coastguard Worker       w -= FILTER_WIDTH;
538*a67afe4dSAndroid Build Coastguard Worker 
539*a67afe4dSAndroid Build Coastguard Worker       if (w > 0 && circle_check_line(arg, x, y, w) == 0)
540*a67afe4dSAndroid Build Coastguard Worker          return INSIDE;
541*a67afe4dSAndroid Build Coastguard Worker 
542*a67afe4dSAndroid Build Coastguard Worker       /* Point is somewhere in the filter region: */
543*a67afe4dSAndroid Build Coastguard Worker       return 0;
544*a67afe4dSAndroid Build Coastguard Worker    }
545*a67afe4dSAndroid Build Coastguard Worker 
546*a67afe4dSAndroid Build Coastguard Worker    else /* Inside or outside the square by more than w+FILTER_WIDTH. */
547*a67afe4dSAndroid Build Coastguard Worker       return OUTSIDE;
548*a67afe4dSAndroid Build Coastguard Worker }
549*a67afe4dSAndroid Build Coastguard Worker 
550*a67afe4dSAndroid Build Coastguard Worker /* "line",
551*a67afe4dSAndroid Build Coastguard Worker  * { NULL, NULL },  There is no 'filled' line.
552*a67afe4dSAndroid Build Coastguard Worker  * { inside_line, check_line }
553*a67afe4dSAndroid Build Coastguard Worker  */
554*a67afe4dSAndroid Build Coastguard Worker static int
line_check(double x,double y,double x1,double y1,double x2,double y2,double w,double expand)555*a67afe4dSAndroid Build Coastguard Worker line_check(double x, double y, double x1, double y1, double x2, double y2,
556*a67afe4dSAndroid Build Coastguard Worker    double w, double expand)
557*a67afe4dSAndroid Build Coastguard Worker {
558*a67afe4dSAndroid Build Coastguard Worker    /* Shift all the points to (arg->x1, arg->y1) */
559*a67afe4dSAndroid Build Coastguard Worker    double lx = x2 - x1;
560*a67afe4dSAndroid Build Coastguard Worker    double ly = y2 - y1;
561*a67afe4dSAndroid Build Coastguard Worker    double len2 = lx*lx + ly*ly;
562*a67afe4dSAndroid Build Coastguard Worker    double cross, dot;
563*a67afe4dSAndroid Build Coastguard Worker 
564*a67afe4dSAndroid Build Coastguard Worker    x -= x1;
565*a67afe4dSAndroid Build Coastguard Worker    y -= y1;
566*a67afe4dSAndroid Build Coastguard Worker 
567*a67afe4dSAndroid Build Coastguard Worker    /* The dot product is the distance down the line, the cross product is
568*a67afe4dSAndroid Build Coastguard Worker     * the distance away from the line:
569*a67afe4dSAndroid Build Coastguard Worker     *
570*a67afe4dSAndroid Build Coastguard Worker     *    distance = |cross| / sqrt(len2)
571*a67afe4dSAndroid Build Coastguard Worker     */
572*a67afe4dSAndroid Build Coastguard Worker    cross = x * ly - y * lx;
573*a67afe4dSAndroid Build Coastguard Worker 
574*a67afe4dSAndroid Build Coastguard Worker    /* If 'distance' is more than w the point is definitely outside the line:
575*a67afe4dSAndroid Build Coastguard Worker     *
576*a67afe4dSAndroid Build Coastguard Worker     *     distance >= w
577*a67afe4dSAndroid Build Coastguard Worker     *     |cross|  >= w * sqrt(len2)
578*a67afe4dSAndroid Build Coastguard Worker     *     cross^2  >= w^2 * len2:
579*a67afe4dSAndroid Build Coastguard Worker     */
580*a67afe4dSAndroid Build Coastguard Worker    if (cross*cross >= (w+expand)*(w+expand)*len2)
581*a67afe4dSAndroid Build Coastguard Worker       return 0; /* outside */
582*a67afe4dSAndroid Build Coastguard Worker 
583*a67afe4dSAndroid Build Coastguard Worker    /* Now find the distance *along* the line; this comes from the dot product
584*a67afe4dSAndroid Build Coastguard Worker     * lx.x+ly.y. The actual distance (in pixels) is:
585*a67afe4dSAndroid Build Coastguard Worker     *
586*a67afe4dSAndroid Build Coastguard Worker     *   distance = dot / sqrt(len2)
587*a67afe4dSAndroid Build Coastguard Worker     */
588*a67afe4dSAndroid Build Coastguard Worker    dot = lx * x + ly * y;
589*a67afe4dSAndroid Build Coastguard Worker 
590*a67afe4dSAndroid Build Coastguard Worker    /* The test for 'outside' is:
591*a67afe4dSAndroid Build Coastguard Worker     *
592*a67afe4dSAndroid Build Coastguard Worker     *    distance < 0 || distance > sqrt(len2)
593*a67afe4dSAndroid Build Coastguard Worker     *                 -> dot / sqrt(len2) > sqrt(len2)
594*a67afe4dSAndroid Build Coastguard Worker     *                 -> dot > len2
595*a67afe4dSAndroid Build Coastguard Worker     *
596*a67afe4dSAndroid Build Coastguard Worker     * But 'expand' is used for the filter width and needs to be handled too:
597*a67afe4dSAndroid Build Coastguard Worker     */
598*a67afe4dSAndroid Build Coastguard Worker    return dot > -expand && dot < len2+expand;
599*a67afe4dSAndroid Build Coastguard Worker }
600*a67afe4dSAndroid Build Coastguard Worker 
601*a67afe4dSAndroid Build Coastguard Worker static int
inside_line(const struct arg * arg,double x,double y)602*a67afe4dSAndroid Build Coastguard Worker inside_line(const struct arg *arg, double x, double y)
603*a67afe4dSAndroid Build Coastguard Worker {
604*a67afe4dSAndroid Build Coastguard Worker    return line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 0);
605*a67afe4dSAndroid Build Coastguard Worker }
606*a67afe4dSAndroid Build Coastguard Worker 
607*a67afe4dSAndroid Build Coastguard Worker static int
check_line(const struct arg * arg,double x,double y)608*a67afe4dSAndroid Build Coastguard Worker check_line(const struct arg *arg, double x, double y)
609*a67afe4dSAndroid Build Coastguard Worker {
610*a67afe4dSAndroid Build Coastguard Worker    /* The end caps of the line must be checked too; it's not enough just to
611*a67afe4dSAndroid Build Coastguard Worker     * widen the line by FILTER_WIDTH; 'expand' exists for this purpose:
612*a67afe4dSAndroid Build Coastguard Worker     */
613*a67afe4dSAndroid Build Coastguard Worker    if (line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2,
614*a67afe4dSAndroid Build Coastguard Worker        FILTER_WIDTH))
615*a67afe4dSAndroid Build Coastguard Worker    {
616*a67afe4dSAndroid Build Coastguard Worker       /* Inside the line+filter; far enough inside that the filter isn't
617*a67afe4dSAndroid Build Coastguard Worker        * required?
618*a67afe4dSAndroid Build Coastguard Worker        */
619*a67afe4dSAndroid Build Coastguard Worker       if (arg->width > 2*FILTER_WIDTH &&
620*a67afe4dSAndroid Build Coastguard Worker           line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2,
621*a67afe4dSAndroid Build Coastguard Worker              -FILTER_WIDTH))
622*a67afe4dSAndroid Build Coastguard Worker          return INSIDE;
623*a67afe4dSAndroid Build Coastguard Worker 
624*a67afe4dSAndroid Build Coastguard Worker       return 0;
625*a67afe4dSAndroid Build Coastguard Worker    }
626*a67afe4dSAndroid Build Coastguard Worker 
627*a67afe4dSAndroid Build Coastguard Worker    return OUTSIDE;
628*a67afe4dSAndroid Build Coastguard Worker }
629*a67afe4dSAndroid Build Coastguard Worker 
630*a67afe4dSAndroid Build Coastguard Worker static const struct
631*a67afe4dSAndroid Build Coastguard Worker {
632*a67afe4dSAndroid Build Coastguard Worker    const char    *name;
633*a67afe4dSAndroid Build Coastguard Worker    shape_fn_ptr   function[2/*fill,line*/][2];
634*a67afe4dSAndroid Build Coastguard Worker #  define         FN_INSIDE 0
635*a67afe4dSAndroid Build Coastguard Worker #  define         FN_CHECK 1
636*a67afe4dSAndroid Build Coastguard Worker } shape_defs[] =
637*a67afe4dSAndroid Build Coastguard Worker {
638*a67afe4dSAndroid Build Coastguard Worker    {  "square",
639*a67afe4dSAndroid Build Coastguard Worker       {  { inside_square_filled, check_square_filled },
640*a67afe4dSAndroid Build Coastguard Worker          { inside_square, check_square } }
641*a67afe4dSAndroid Build Coastguard Worker    },
642*a67afe4dSAndroid Build Coastguard Worker    {  "circle",
643*a67afe4dSAndroid Build Coastguard Worker       {  { inside_circle_filled, check_circle_filled },
644*a67afe4dSAndroid Build Coastguard Worker          { inside_circle, check_circle } }
645*a67afe4dSAndroid Build Coastguard Worker    },
646*a67afe4dSAndroid Build Coastguard Worker    {  "line",
647*a67afe4dSAndroid Build Coastguard Worker       {  { NULL, NULL },
648*a67afe4dSAndroid Build Coastguard Worker          { inside_line, check_line } }
649*a67afe4dSAndroid Build Coastguard Worker    }
650*a67afe4dSAndroid Build Coastguard Worker };
651*a67afe4dSAndroid Build Coastguard Worker 
652*a67afe4dSAndroid Build Coastguard Worker #define shape_count ((sizeof shape_defs)/(sizeof shape_defs[0]))
653*a67afe4dSAndroid Build Coastguard Worker 
654*a67afe4dSAndroid Build Coastguard Worker static shape_fn_ptr
shape_of(const char * arg,double width,int f)655*a67afe4dSAndroid Build Coastguard Worker shape_of(const char *arg, double width, int f)
656*a67afe4dSAndroid Build Coastguard Worker {
657*a67afe4dSAndroid Build Coastguard Worker    unsigned int i;
658*a67afe4dSAndroid Build Coastguard Worker 
659*a67afe4dSAndroid Build Coastguard Worker    for (i=0; i<shape_count; ++i) if (strcmp(shape_defs[i].name, arg) == 0)
660*a67afe4dSAndroid Build Coastguard Worker    {
661*a67afe4dSAndroid Build Coastguard Worker       shape_fn_ptr fn = shape_defs[i].function[width != 0][f];
662*a67afe4dSAndroid Build Coastguard Worker 
663*a67afe4dSAndroid Build Coastguard Worker       if (fn != NULL)
664*a67afe4dSAndroid Build Coastguard Worker          return fn;
665*a67afe4dSAndroid Build Coastguard Worker 
666*a67afe4dSAndroid Build Coastguard Worker       fprintf(stderr, "genpng: %s %s not supported\n",
667*a67afe4dSAndroid Build Coastguard Worker          width == 0 ? "filled" : "unfilled", arg);
668*a67afe4dSAndroid Build Coastguard Worker       exit(1);
669*a67afe4dSAndroid Build Coastguard Worker    }
670*a67afe4dSAndroid Build Coastguard Worker 
671*a67afe4dSAndroid Build Coastguard Worker    fprintf(stderr, "genpng: %s: not a valid shape name\n", arg);
672*a67afe4dSAndroid Build Coastguard Worker    exit(1);
673*a67afe4dSAndroid Build Coastguard Worker }
674*a67afe4dSAndroid Build Coastguard Worker 
675*a67afe4dSAndroid Build Coastguard Worker static void
parse_arg(struct arg * arg,const char ** argv)676*a67afe4dSAndroid Build Coastguard Worker parse_arg(struct arg *arg, const char **argv/*7 arguments*/)
677*a67afe4dSAndroid Build Coastguard Worker {
678*a67afe4dSAndroid Build Coastguard Worker    /* shape ::= color width shape x1 y1 x2 y2 */
679*a67afe4dSAndroid Build Coastguard Worker    arg->color = color_of(argv[0]);
680*a67afe4dSAndroid Build Coastguard Worker    arg->width = width_of(argv[1]);
681*a67afe4dSAndroid Build Coastguard Worker    arg->inside_fn = shape_of(argv[2], arg->width, FN_INSIDE);
682*a67afe4dSAndroid Build Coastguard Worker    arg->check_fn = shape_of(argv[2], arg->width, FN_CHECK);
683*a67afe4dSAndroid Build Coastguard Worker    arg->x1 = coordinate_of(argv[3]);
684*a67afe4dSAndroid Build Coastguard Worker    arg->y1 = coordinate_of(argv[4]);
685*a67afe4dSAndroid Build Coastguard Worker    arg->x2 = coordinate_of(argv[5]);
686*a67afe4dSAndroid Build Coastguard Worker    arg->y2 = coordinate_of(argv[6]);
687*a67afe4dSAndroid Build Coastguard Worker }
688*a67afe4dSAndroid Build Coastguard Worker 
689*a67afe4dSAndroid Build Coastguard Worker static png_uint_32
read_wh(const char * name,const char * str)690*a67afe4dSAndroid Build Coastguard Worker read_wh(const char *name, const char *str)
691*a67afe4dSAndroid Build Coastguard Worker    /* read a PNG width or height */
692*a67afe4dSAndroid Build Coastguard Worker {
693*a67afe4dSAndroid Build Coastguard Worker    char *ep = NULL;
694*a67afe4dSAndroid Build Coastguard Worker    unsigned long ul = strtoul(str, &ep, 10);
695*a67afe4dSAndroid Build Coastguard Worker 
696*a67afe4dSAndroid Build Coastguard Worker    if (ep != NULL && *ep == 0 && ul > 0 && ul <= 0x7fffffff)
697*a67afe4dSAndroid Build Coastguard Worker       return (png_uint_32)/*SAFE*/ul;
698*a67afe4dSAndroid Build Coastguard Worker 
699*a67afe4dSAndroid Build Coastguard Worker    fprintf(stderr, "genpng: %s: invalid number %s\n", name, str);
700*a67afe4dSAndroid Build Coastguard Worker    exit(1);
701*a67afe4dSAndroid Build Coastguard Worker }
702*a67afe4dSAndroid Build Coastguard Worker 
703*a67afe4dSAndroid Build Coastguard Worker static void
pixel(png_uint_16p p,struct arg * args,int nargs,double x,double y)704*a67afe4dSAndroid Build Coastguard Worker pixel(png_uint_16p p, struct arg *args, int nargs, double x, double y)
705*a67afe4dSAndroid Build Coastguard Worker {
706*a67afe4dSAndroid Build Coastguard Worker    /* Fill in the pixel by checking each shape (args[nargs]) for effects on
707*a67afe4dSAndroid Build Coastguard Worker     * the corresponding sample:
708*a67afe4dSAndroid Build Coastguard Worker     */
709*a67afe4dSAndroid Build Coastguard Worker    double r=0, g=0, b=0, a=0;
710*a67afe4dSAndroid Build Coastguard Worker 
711*a67afe4dSAndroid Build Coastguard Worker    while (--nargs >= 0 && a != 1)
712*a67afe4dSAndroid Build Coastguard Worker    {
713*a67afe4dSAndroid Build Coastguard Worker       /* NOTE: alpha_calc can return a value outside the range 0..1 with the
714*a67afe4dSAndroid Build Coastguard Worker        * bicubic filter.
715*a67afe4dSAndroid Build Coastguard Worker        */
716*a67afe4dSAndroid Build Coastguard Worker       const double alpha = alpha_calc(args+nargs, x, y) * (1-a);
717*a67afe4dSAndroid Build Coastguard Worker 
718*a67afe4dSAndroid Build Coastguard Worker       r += alpha * args[nargs].color->red;
719*a67afe4dSAndroid Build Coastguard Worker       g += alpha * args[nargs].color->green;
720*a67afe4dSAndroid Build Coastguard Worker       b += alpha * args[nargs].color->blue;
721*a67afe4dSAndroid Build Coastguard Worker       a += alpha;
722*a67afe4dSAndroid Build Coastguard Worker    }
723*a67afe4dSAndroid Build Coastguard Worker 
724*a67afe4dSAndroid Build Coastguard Worker    /* 'a' may be negative or greater than 1; if it is, negative clamp the
725*a67afe4dSAndroid Build Coastguard Worker     * pixel to 0 if >1 clamp r/g/b:
726*a67afe4dSAndroid Build Coastguard Worker     */
727*a67afe4dSAndroid Build Coastguard Worker    if (a > 0)
728*a67afe4dSAndroid Build Coastguard Worker    {
729*a67afe4dSAndroid Build Coastguard Worker       if (a > 1)
730*a67afe4dSAndroid Build Coastguard Worker       {
731*a67afe4dSAndroid Build Coastguard Worker          if (r > 1) r = 1;
732*a67afe4dSAndroid Build Coastguard Worker          if (g > 1) g = 1;
733*a67afe4dSAndroid Build Coastguard Worker          if (b > 1) b = 1;
734*a67afe4dSAndroid Build Coastguard Worker          a = 1;
735*a67afe4dSAndroid Build Coastguard Worker       }
736*a67afe4dSAndroid Build Coastguard Worker 
737*a67afe4dSAndroid Build Coastguard Worker       /* And fill in the pixel: */
738*a67afe4dSAndroid Build Coastguard Worker       p[0] = (png_uint_16)/*SAFE*/round(r * 65535);
739*a67afe4dSAndroid Build Coastguard Worker       p[1] = (png_uint_16)/*SAFE*/round(g * 65535);
740*a67afe4dSAndroid Build Coastguard Worker       p[2] = (png_uint_16)/*SAFE*/round(b * 65535);
741*a67afe4dSAndroid Build Coastguard Worker       p[3] = (png_uint_16)/*SAFE*/round(a * 65535);
742*a67afe4dSAndroid Build Coastguard Worker    }
743*a67afe4dSAndroid Build Coastguard Worker 
744*a67afe4dSAndroid Build Coastguard Worker    else
745*a67afe4dSAndroid Build Coastguard Worker       p[3] = p[2] = p[1] = p[0] = 0;
746*a67afe4dSAndroid Build Coastguard Worker }
747*a67afe4dSAndroid Build Coastguard Worker 
748*a67afe4dSAndroid Build Coastguard Worker int
main(int argc,const char ** argv)749*a67afe4dSAndroid Build Coastguard Worker main(int argc, const char **argv)
750*a67afe4dSAndroid Build Coastguard Worker {
751*a67afe4dSAndroid Build Coastguard Worker    int convert_to_8bit = 0;
752*a67afe4dSAndroid Build Coastguard Worker 
753*a67afe4dSAndroid Build Coastguard Worker    /* There is one option: --8bit: */
754*a67afe4dSAndroid Build Coastguard Worker    if (argc > 1 && strcmp(argv[1], "--8bit") == 0)
755*a67afe4dSAndroid Build Coastguard Worker       --argc, ++argv, convert_to_8bit = 1;
756*a67afe4dSAndroid Build Coastguard Worker 
757*a67afe4dSAndroid Build Coastguard Worker    if (argc >= 3)
758*a67afe4dSAndroid Build Coastguard Worker    {
759*a67afe4dSAndroid Build Coastguard Worker       png_uint_16p buffer;
760*a67afe4dSAndroid Build Coastguard Worker       int nshapes;
761*a67afe4dSAndroid Build Coastguard Worker       png_image image;
762*a67afe4dSAndroid Build Coastguard Worker #     define max_shapes 256
763*a67afe4dSAndroid Build Coastguard Worker       struct arg arg_list[max_shapes];
764*a67afe4dSAndroid Build Coastguard Worker 
765*a67afe4dSAndroid Build Coastguard Worker       /* The libpng Simplified API write code requires a fully initialized
766*a67afe4dSAndroid Build Coastguard Worker        * structure.
767*a67afe4dSAndroid Build Coastguard Worker        */
768*a67afe4dSAndroid Build Coastguard Worker       memset(&image, 0, sizeof image);
769*a67afe4dSAndroid Build Coastguard Worker       image.version = PNG_IMAGE_VERSION;
770*a67afe4dSAndroid Build Coastguard Worker       image.opaque = NULL;
771*a67afe4dSAndroid Build Coastguard Worker       image.width = read_wh("width", argv[1]);
772*a67afe4dSAndroid Build Coastguard Worker       image.height = read_wh("height", argv[2]);
773*a67afe4dSAndroid Build Coastguard Worker       image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
774*a67afe4dSAndroid Build Coastguard Worker       image.flags = 0;
775*a67afe4dSAndroid Build Coastguard Worker       image.colormap_entries = 0;
776*a67afe4dSAndroid Build Coastguard Worker 
777*a67afe4dSAndroid Build Coastguard Worker       /* Check the remainder of the arguments */
778*a67afe4dSAndroid Build Coastguard Worker       for (nshapes=0; 3+7*(nshapes+1) <= argc && nshapes < max_shapes;
779*a67afe4dSAndroid Build Coastguard Worker            ++nshapes)
780*a67afe4dSAndroid Build Coastguard Worker          parse_arg(arg_list+nshapes, argv+3+7*nshapes);
781*a67afe4dSAndroid Build Coastguard Worker 
782*a67afe4dSAndroid Build Coastguard Worker       if (3+7*nshapes != argc)
783*a67afe4dSAndroid Build Coastguard Worker       {
784*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "genpng: %s: too many arguments\n", argv[3+7*nshapes]);
785*a67afe4dSAndroid Build Coastguard Worker          return 1;
786*a67afe4dSAndroid Build Coastguard Worker       }
787*a67afe4dSAndroid Build Coastguard Worker 
788*a67afe4dSAndroid Build Coastguard Worker #if 1
789*a67afe4dSAndroid Build Coastguard Worker      /* TO do: determine whether this guard against overflow is necessary.
790*a67afe4dSAndroid Build Coastguard Worker       * This comment in png.h indicates that it should be safe: "libpng will
791*a67afe4dSAndroid Build Coastguard Worker       * refuse to process an image where such an overflow would occur", but
792*a67afe4dSAndroid Build Coastguard Worker       * I don't see where the image gets rejected when the buffer is too
793*a67afe4dSAndroid Build Coastguard Worker       * large before the malloc is attempted.
794*a67afe4dSAndroid Build Coastguard Worker       */
795*a67afe4dSAndroid Build Coastguard Worker       if (image.height > ((size_t)(-1))/(8*image.width)) {
796*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "genpng: image buffer would be too big");
797*a67afe4dSAndroid Build Coastguard Worker          return 1;
798*a67afe4dSAndroid Build Coastguard Worker       }
799*a67afe4dSAndroid Build Coastguard Worker #endif
800*a67afe4dSAndroid Build Coastguard Worker 
801*a67afe4dSAndroid Build Coastguard Worker       /* Create the buffer: */
802*a67afe4dSAndroid Build Coastguard Worker       buffer = malloc(PNG_IMAGE_SIZE(image));
803*a67afe4dSAndroid Build Coastguard Worker 
804*a67afe4dSAndroid Build Coastguard Worker       if (buffer != NULL)
805*a67afe4dSAndroid Build Coastguard Worker       {
806*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 y;
807*a67afe4dSAndroid Build Coastguard Worker 
808*a67afe4dSAndroid Build Coastguard Worker          /* Write each row... */
809*a67afe4dSAndroid Build Coastguard Worker          for (y=0; y<image.height; ++y)
810*a67afe4dSAndroid Build Coastguard Worker          {
811*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 x;
812*a67afe4dSAndroid Build Coastguard Worker 
813*a67afe4dSAndroid Build Coastguard Worker             /* Each pixel in each row: */
814*a67afe4dSAndroid Build Coastguard Worker             for (x=0; x<image.width; ++x)
815*a67afe4dSAndroid Build Coastguard Worker                pixel(buffer + 4*(x + y*image.width), arg_list, nshapes, x, y);
816*a67afe4dSAndroid Build Coastguard Worker          }
817*a67afe4dSAndroid Build Coastguard Worker 
818*a67afe4dSAndroid Build Coastguard Worker          /* Write the result (to stdout) */
819*a67afe4dSAndroid Build Coastguard Worker          if (png_image_write_to_stdio(&image, stdout, convert_to_8bit,
820*a67afe4dSAndroid Build Coastguard Worker              buffer, 0/*row_stride*/, NULL/*colormap*/))
821*a67afe4dSAndroid Build Coastguard Worker          {
822*a67afe4dSAndroid Build Coastguard Worker             free(buffer);
823*a67afe4dSAndroid Build Coastguard Worker             return 0; /* success */
824*a67afe4dSAndroid Build Coastguard Worker          }
825*a67afe4dSAndroid Build Coastguard Worker 
826*a67afe4dSAndroid Build Coastguard Worker          else
827*a67afe4dSAndroid Build Coastguard Worker             fprintf(stderr, "genpng: write stdout: %s\n", image.message);
828*a67afe4dSAndroid Build Coastguard Worker 
829*a67afe4dSAndroid Build Coastguard Worker          free(buffer);
830*a67afe4dSAndroid Build Coastguard Worker       }
831*a67afe4dSAndroid Build Coastguard Worker 
832*a67afe4dSAndroid Build Coastguard Worker       else
833*a67afe4dSAndroid Build Coastguard Worker          fprintf(stderr, "genpng: out of memory: %lu bytes\n",
834*a67afe4dSAndroid Build Coastguard Worker                (unsigned long)PNG_IMAGE_SIZE(image));
835*a67afe4dSAndroid Build Coastguard Worker    }
836*a67afe4dSAndroid Build Coastguard Worker 
837*a67afe4dSAndroid Build Coastguard Worker    else
838*a67afe4dSAndroid Build Coastguard Worker    {
839*a67afe4dSAndroid Build Coastguard Worker       /* Wrong number of arguments */
840*a67afe4dSAndroid Build Coastguard Worker       fprintf(stderr, "genpng: usage: genpng [--8bit] width height {shape}\n"
841*a67afe4dSAndroid Build Coastguard Worker          " Generate a transparent PNG in RGBA (truecolor+alpha) format\n"
842*a67afe4dSAndroid Build Coastguard Worker          " containing the given shape or shapes.  Shapes are defined:\n"
843*a67afe4dSAndroid Build Coastguard Worker          "\n"
844*a67afe4dSAndroid Build Coastguard Worker          "  shape ::= color width shape x1 y1 x2 y2\n"
845*a67afe4dSAndroid Build Coastguard Worker          "  color ::= black|white|red|green|yellow|blue\n"
846*a67afe4dSAndroid Build Coastguard Worker          "  color ::= brown|purple|pink|orange|gray|cyan\n"
847*a67afe4dSAndroid Build Coastguard Worker          "  width ::= filled|<number>\n"
848*a67afe4dSAndroid Build Coastguard Worker          "  shape ::= circle|square|line\n"
849*a67afe4dSAndroid Build Coastguard Worker          "  x1,x2 ::= <number>\n"
850*a67afe4dSAndroid Build Coastguard Worker          "  y1,y2 ::= <number>\n"
851*a67afe4dSAndroid Build Coastguard Worker          "\n"
852*a67afe4dSAndroid Build Coastguard Worker          " Numbers are floating point numbers describing points relative to\n"
853*a67afe4dSAndroid Build Coastguard Worker          " the top left of the output PNG as pixel coordinates.  The 'width'\n"
854*a67afe4dSAndroid Build Coastguard Worker          " parameter is either the width of the line (in output pixels) used\n"
855*a67afe4dSAndroid Build Coastguard Worker          " to draw the shape or 'filled' to indicate that the shape should\n"
856*a67afe4dSAndroid Build Coastguard Worker          " be filled with the color.\n"
857*a67afe4dSAndroid Build Coastguard Worker          "\n"
858*a67afe4dSAndroid Build Coastguard Worker          " Colors are interpreted loosely to give access to the eight full\n"
859*a67afe4dSAndroid Build Coastguard Worker          " intensity RGB values:\n"
860*a67afe4dSAndroid Build Coastguard Worker          "\n"
861*a67afe4dSAndroid Build Coastguard Worker          "  black, red, green, blue, yellow, cyan, purple, white,\n"
862*a67afe4dSAndroid Build Coastguard Worker          "\n"
863*a67afe4dSAndroid Build Coastguard Worker          " Cyan is full intensity blue+green; RGB(0,1,1), plus the following\n"
864*a67afe4dSAndroid Build Coastguard Worker          " lower intensity values:\n"
865*a67afe4dSAndroid Build Coastguard Worker          "\n"
866*a67afe4dSAndroid Build Coastguard Worker          "  brown:  red+orange:  RGB(0.5, 0.125, 0) (dark red+orange)\n"
867*a67afe4dSAndroid Build Coastguard Worker          "  pink:   red+white:   RGB(1.0, 0.5,   0.5)\n"
868*a67afe4dSAndroid Build Coastguard Worker          "  orange: red+yellow:  RGB(1.0, 0.5,   0)\n"
869*a67afe4dSAndroid Build Coastguard Worker          "  gray:   black+white: RGB(0.5, 0.5,   0.5)\n"
870*a67afe4dSAndroid Build Coastguard Worker          "\n"
871*a67afe4dSAndroid Build Coastguard Worker          " The RGB values are selected to make detection of aliasing errors\n"
872*a67afe4dSAndroid Build Coastguard Worker          " easy. The names are selected to make the description of errors\n"
873*a67afe4dSAndroid Build Coastguard Worker          " easy.\n"
874*a67afe4dSAndroid Build Coastguard Worker          "\n"
875*a67afe4dSAndroid Build Coastguard Worker          " The PNG is written to stdout, if --8bit is given a 32bpp RGBA sRGB\n"
876*a67afe4dSAndroid Build Coastguard Worker          " file is produced, otherwise a 64bpp RGBA linear encoded file is\n"
877*a67afe4dSAndroid Build Coastguard Worker          " written.\n");
878*a67afe4dSAndroid Build Coastguard Worker    }
879*a67afe4dSAndroid Build Coastguard Worker 
880*a67afe4dSAndroid Build Coastguard Worker    return 1;
881*a67afe4dSAndroid Build Coastguard Worker }
882*a67afe4dSAndroid Build Coastguard Worker #endif /* SIMPLIFIED_WRITE && STDIO */
883