#include "imrender.h"
#include <limits.h>
+int
+i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
+ i_color src;
+ i_color work;
+ int dest_alpha;
+ int remains;
+
+ if (!col->channel[3])
+ return 0;
+
+ switch (im->channels) {
+ case 1:
+ work = *col;
+ i_adapt_colors(2, 4, &work, 1);
+ i_gpix(im, x, y, &src);
+ remains = 255 - work.channel[1];
+ src.channel[0] = (src.channel[0] * remains
+ + work.channel[0] * work.channel[1]) / 255;
+ return i_ppix(im, x, y, &src);
+
+ case 2:
+ work = *col;
+ i_adapt_colors(2, 4, &work, 1);
+ i_gpix(im, x, y, &src);
+ dest_alpha = work.channel[1] + remains * src.channel[1] / 255;
+ if (work.channel[1] == 255) {
+ return i_ppix(im, x, y, &work);
+ }
+ else {
+ src.channel[0] = (work.channel[1] * work.channel[0]
+ + remains * src.channel[0] * src.channel[1] / 255) / dest_alpha;
+ src.channel[1] = dest_alpha;
+ return i_ppix(im, x, y, &src);
+ }
+
+ case 3:
+ work = *col;
+ i_gpix(im, x, y, &src);
+ remains = 255 - work.channel[3];
+ src.channel[0] = (src.channel[0] * remains
+ + work.channel[0] * work.channel[3]) / 255;
+ src.channel[1] = (src.channel[1] * remains
+ + work.channel[1] * work.channel[3]) / 255;
+ src.channel[2] = (src.channel[2] * remains
+ + work.channel[2] * work.channel[3]) / 255;
+ return i_ppix(im, x, y, &src);
+
+ case 4:
+ work = *col;
+ i_gpix(im, x, y, &src);
+ dest_alpha = work.channel[3] + remains * src.channel[3] / 255;
+ if (work.channel[3] == 255) {
+ return i_ppix(im, x, y, &work);
+ }
+ else {
+ src.channel[0] = (work.channel[3] * work.channel[0]
+ + remains * src.channel[0] * src.channel[3] / 255) / dest_alpha;
+ src.channel[1] = (work.channel[3] * work.channel[1]
+ + remains * src.channel[1] * src.channel[3] / 255) / dest_alpha;
+ src.channel[2] = (work.channel[3] * work.channel[2]
+ + remains * src.channel[2] * src.channel[3] / 255) / dest_alpha;
+ src.channel[3] = dest_alpha;
+ return i_ppix(im, x, y, &src);
+ }
+ }
+ return 0;
+}
+
static void
cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm,
int bxmin, int bxmax, int bymin, int bymax);
double *xvals, *yvals;
int count;
- arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
+ arc_poly(&count, &xvals, &yvals, x+0.5, y+0.5, rad, d1, d2);
i_poly_aa(im, count, xvals, yvals, val);
i_mmarray_dst(&dot);
}
+/*
+=item i_circle_out(im, x, y, r, col)
+
+=category Drawing
+=synopsis i_circle_out(im, 50, 50, 45, &color);
+
+Draw a circle outline centered at (x,y) with radius r,
+non-anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(x, y) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=back
+
+Returns non-zero on success.
+
+Implementation:
+
+=cut
+*/
+
+int
+i_circle_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
+ const i_color *col) {
+ i_img_dim x, y;
+ i_img_dim dx, dy;
+ int error;
+
+ i_clear_error();
+
+ if (r < 0) {
+ i_push_error(0, "circle: radius must be non-negative");
+ return 0;
+ }
+
+ i_ppix(im, xc+r, yc, col);
+ i_ppix(im, xc-r, yc, col);
+ i_ppix(im, xc, yc+r, col);
+ i_ppix(im, xc, yc-r, col);
+
+ x = 0;
+ y = r;
+ dx = 1;
+ dy = -2 * r;
+ error = 1 - r;
+ while (x < y) {
+ if (error >= 0) {
+ --y;
+ dy += 2;
+ error += dy;
+ }
+ ++x;
+ dx += 2;
+ error += dx;
+
+ i_ppix(im, xc + x, yc + y, col);
+ i_ppix(im, xc + x, yc - y, col);
+ i_ppix(im, xc - x, yc + y, col);
+ i_ppix(im, xc - x, yc - y, col);
+ if (x != y) {
+ i_ppix(im, xc + y, yc + x, col);
+ i_ppix(im, xc + y, yc - x, col);
+ i_ppix(im, xc - y, yc + x, col);
+ i_ppix(im, xc - y, yc - x, col);
+ }
+ }
+
+ return 1;
+}
+
+/*
+=item arc_seg(angle)
+
+Convert an angle in degrees into an angle measure we can generate
+simply from the numbers we have when drawing the circle.
+
+=back
+*/
+
+static i_img_dim
+arc_seg(double angle, int scale) {
+ i_img_dim seg = (angle + 45) / 90;
+ double remains = angle - seg * 90; /* should be in the range [-45,45] */
+ int sign = remains < 0 ? -1 : remains ? 1 : 0;
+
+ while (seg > 4)
+ seg -= 4;
+ if (seg == 4 && remains > 0)
+ seg = 0;
+
+ return scale * (seg * 2 + sin(remains * PI/180));
+}
+
+/*
+=item i_arc_out(im, x, y, r, d1, d2, col)
+
+=category Drawing
+=synopsis i_arc_out(im, 50, 50, 45, 45, 135, &color);
+
+Draw an arc outline centered at (x,y) with radius r, non-anti-aliased
+over the angle range d1 through d2 degrees.
+
+Parameters:
+
+=over
+
+=item *
+
+(x, y) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+d1, d2 - the range of angles to draw the arc over, in degrees.
+
+=back
+
+Returns non-zero on success.
+
+Implementation:
+
+=cut
+*/
+
+int
+i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
+ float d1, float d2, const i_color *col) {
+ i_img_dim x, y;
+ i_img_dim dx, dy;
+ int error;
+ i_img_dim segs[2][2];
+ int seg_count;
+ i_img_dim sin_th;
+ i_img_dim seg_d1, seg_d2;
+ int seg_num;
+ double inv_r;
+ i_img_dim scale = r + 1;
+ i_img_dim seg1 = scale * 2;
+ i_img_dim seg2 = scale * 4;
+ i_img_dim seg3 = scale * 6;
+ i_img_dim seg4 = scale * 8;
+
+ i_clear_error();
+
+ if (r <= 0) {
+ i_push_error(0, "arc: radius must be non-negative");
+ return 0;
+ }
+ if (d1 + 360 <= d2)
+ return i_circle_out(im, xc, yc, r, col);
+
+ if (d1 < 0)
+ d1 += 360 * floor((-d1 + 359) / 360);
+ if (d2 < 0)
+ d2 += 360 * floor((-d2 + 359) / 360);
+ d1 = fmod(d1, 360);
+ d2 = fmod(d2, 360);
+ seg_d1 = arc_seg(d1, scale);
+ seg_d2 = arc_seg(d2, scale);
+ if (seg_d2 < seg_d1) {
+ /* split into two segments */
+ segs[0][0] = 0;
+ segs[0][1] = seg_d2;
+ segs[1][0] = seg_d1;
+ segs[1][1] = seg4;
+ seg_count = 2;
+ }
+ else {
+ segs[0][0] = seg_d1;
+ segs[0][1] = seg_d2;
+ seg_count = 1;
+ }
+
+ for (seg_num = 0; seg_num < seg_count; ++seg_num) {
+ i_img_dim seg_start = segs[seg_num][0];
+ i_img_dim seg_end = segs[seg_num][1];
+ if (seg_start == 0)
+ i_ppix(im, xc+r, yc, col);
+ if (seg_start <= seg1 && seg_end >= seg1)
+ i_ppix(im, xc, yc+r, col);
+ if (seg_start <= seg2 && seg_end >= seg2)
+ i_ppix(im, xc-r, yc, col);
+ if (seg_start <= seg3 && seg_end >= seg3)
+ i_ppix(im, xc, yc-r, col);
+
+ y = 0;
+ x = r;
+ dy = 1;
+ dx = -2 * r;
+ error = 1 - r;
+ while (y < x) {
+ if (error >= 0) {
+ --x;
+ dx += 2;
+ error += dx;
+ }
+ ++y;
+ dy += 2;
+ error += dy;
+
+ sin_th = y;
+ if (seg_start <= sin_th && seg_end >= sin_th)
+ i_ppix(im, xc + x, yc + y, col);
+ if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+ i_ppix(im, xc + y, yc + x, col);
+
+ if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+ i_ppix(im, xc - y, yc + x, col);
+ if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+ i_ppix(im, xc - x, yc + y, col);
+
+ if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+ i_ppix(im, xc - x, yc - y, col);
+ if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+ i_ppix(im, xc - y, yc - x, col);
+
+ if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+ i_ppix(im, xc + y, yc - x, col);
+ if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+ i_ppix(im, xc + x, yc - y, col);
+ }
+ }
+
+ return 1;
+}
+
+static double
+cover(i_img_dim r, i_img_dim j) {
+ float rjsqrt = sqrt(r*r - j*j);
+
+ return ceil(rjsqrt) - rjsqrt;
+}
+
+/*
+=item i_circle_out_aa(im, xc, yc, r, col)
+
+=synopsis i_circle_out_aa(im, 50, 50, 45, &color);
+
+Draw a circle outline centered at (x,y) with radius r, anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(xc, yc) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+col - an i_color for the color to draw in.
+
+=back
+
+Returns non-zero on success.
+
+=cut
+
+Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics
+Gems.
+
+I use floating point for I<D> since for large circles the precision of
+a [0,255] value isn't sufficient when approaching the end of the
+octant.
+
+*/
+
+int
+i_circle_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_color *col) {
+ i_img_dim i, j;
+ double t;
+ i_color workc = *col;
+ int orig_alpha = col->channel[3];
+
+ i_clear_error();
+ if (r <= 0) {
+ i_push_error(0, "arc: radius must be non-negative");
+ return 0;
+ }
+ i = r;
+ j = 0;
+ t = 0;
+ i_ppix_norm(im, xc+i, yc+j, col);
+ i_ppix_norm(im, xc-i, yc+j, col);
+ i_ppix_norm(im, xc+j, yc+i, col);
+ i_ppix_norm(im, xc+j, yc-i, col);
+
+ while (i > j+1) {
+ double d;
+ int cv, inv_cv;
+ i_color p;
+ int ch;
+ j++;
+ d = cover(r, j);
+ cv = (int)(d * 255 + 0.5);
+ inv_cv = 255-cv;
+ if (d < t) {
+ --i;
+ }
+ if (inv_cv) {
+ workc.channel[3] = orig_alpha * inv_cv / 255;
+ i_ppix_norm(im, xc+i, yc+j, &workc);
+ i_ppix_norm(im, xc-i, yc+j, &workc);
+ i_ppix_norm(im, xc+i, yc-j, &workc);
+ i_ppix_norm(im, xc-i, yc-j, &workc);
+
+ if (i != j) {
+ i_ppix_norm(im, xc+j, yc+i, &workc);
+ i_ppix_norm(im, xc-j, yc+i, &workc);
+ i_ppix_norm(im, xc+j, yc-i, &workc);
+ i_ppix_norm(im, xc-j, yc-i, &workc);
+ }
+ }
+ if (cv && i > j) {
+ workc.channel[3] = orig_alpha * cv / 255;
+ i_ppix_norm(im, xc+i-1, yc+j, &workc);
+ i_ppix_norm(im, xc-i+1, yc+j, &workc);
+ i_ppix_norm(im, xc+i-1, yc-j, &workc);
+ i_ppix_norm(im, xc-i+1, yc-j, &workc);
+
+ if (j != i-1) {
+ i_ppix_norm(im, xc+j, yc+i-1, &workc);
+ i_ppix_norm(im, xc-j, yc+i-1, &workc);
+ i_ppix_norm(im, xc+j, yc-i+1, &workc);
+ i_ppix_norm(im, xc-j, yc-i+1, &workc);
+ }
+ }
+ t = d;
+ }
+
+ return 1;
+}
+
+/*
+=item i_arc_out_aa(im, xc, yc, r, d1, d2, col)
+
+=synopsis i_arc_out_aa(im, 50, 50, 45, 45, 125, &color);
+
+Draw a circle arc outline centered at (x,y) with radius r, from angle
+d1 degrees through angle d2 degrees, anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(xc, yc) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+d1, d2 - the range of angle in degrees to draw the arc through. If
+d2-d1 >= 360 a full circle is drawn.
+
+=back
+
+Returns non-zero on success.
+
+=cut
+
+Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics
+Gems.
+
+*/
+
+int
+i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, float d1, float d2, const i_color *col) {
+ i_img_dim i, j;
+ double t;
+ i_color workc = *col;
+ i_img_dim segs[2][2];
+ int seg_count;
+ i_img_dim sin_th;
+ i_img_dim seg_d1, seg_d2;
+ int seg_num;
+ int orig_alpha = col->channel[3];
+ i_img_dim scale = r + 1;
+ i_img_dim seg1 = scale * 2;
+ i_img_dim seg2 = scale * 4;
+ i_img_dim seg3 = scale * 6;
+ i_img_dim seg4 = scale * 8;
+
+ i_clear_error();
+ if (r <= 0) {
+ i_push_error(0, "arc: radius must be non-negative");
+ return 0;
+ }
+ if (d1 + 360 <= d2)
+ return i_circle_out_aa(im, xc, yc, r, col);
+
+ if (d1 < 0)
+ d1 += 360 * floor((-d1 + 359) / 360);
+ if (d2 < 0)
+ d2 += 360 * floor((-d2 + 359) / 360);
+ d1 = fmod(d1, 360);
+ d2 = fmod(d2, 360);
+ seg_d1 = arc_seg(d1, scale);
+ seg_d2 = arc_seg(d2, scale);
+ if (seg_d2 < seg_d1) {
+ /* split into two segments */
+ segs[0][0] = 0;
+ segs[0][1] = seg_d2;
+ segs[1][0] = seg_d1;
+ segs[1][1] = seg4;
+ seg_count = 2;
+ }
+ else {
+ segs[0][0] = seg_d1;
+ segs[0][1] = seg_d2;
+ seg_count = 1;
+ }
+
+ for (seg_num = 0; seg_num < seg_count; ++seg_num) {
+ i_img_dim seg_start = segs[seg_num][0];
+ i_img_dim seg_end = segs[seg_num][1];
+
+ i = r;
+ j = 0;
+ t = 0;
+
+ if (seg_start == 0)
+ i_ppix_norm(im, xc+i, yc+j, col);
+ if (seg_start <= seg1 && seg_end >= seg1)
+ i_ppix_norm(im, xc+j, yc+i, col);
+ if (seg_start <= seg2 && seg_end >= seg2)
+ i_ppix_norm(im, xc-i, yc+j, col);
+ if (seg_start <= seg3 && seg_end >= seg3)
+ i_ppix_norm(im, xc+j, yc-i, col);
+
+ while (i > j+1) {
+ int cv, inv_cv;
+ i_color p;
+ int ch;
+ double d;
+ j++;
+ d = cover(r, j);
+ cv = (int)(d * 255 + 0.5);
+ inv_cv = 255-cv;
+ if (d < t) {
+ --i;
+ }
+ sin_th = j;
+ if (inv_cv) {
+ workc.channel[3] = orig_alpha * inv_cv / 255;
+
+ if (seg_start <= sin_th && seg_end >= sin_th)
+ i_ppix_norm(im, xc+i, yc+j, &workc);
+ if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+ i_ppix_norm(im, xc-i, yc+j, &workc);
+ if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+ i_ppix_norm(im, xc+i, yc-j, &workc);
+ if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+ i_ppix_norm(im, xc-i, yc-j, &workc);
+
+ if (i != j) {
+ if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+ i_ppix_norm(im, xc+j, yc+i, &workc);
+ if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+ i_ppix_norm(im, xc-j, yc+i, &workc);
+ if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+ i_ppix_norm(im, xc+j, yc-i, &workc);
+ if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+ i_ppix_norm(im, xc-j, yc-i, &workc);
+ }
+ }
+ if (cv && i > j) {
+ workc.channel[3] = orig_alpha * cv / 255;
+ if (seg_start <= sin_th && seg_end >= sin_th)
+ i_ppix_norm(im, xc+i-1, yc+j, &workc);
+ if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+ i_ppix_norm(im, xc-i+1, yc+j, &workc);
+ if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+ i_ppix_norm(im, xc+i-1, yc-j, &workc);
+ if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+ i_ppix_norm(im, xc-i+1, yc-j, &workc);
+
+ if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+ i_ppix_norm(im, xc+j, yc+i-1, &workc);
+ if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+ i_ppix_norm(im, xc-j, yc+i-1, &workc);
+ if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+ i_ppix_norm(im, xc+j, yc-i+1, &workc);
+ if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+ i_ppix_norm(im, xc-j, yc-i+1, &workc);
+ }
+ t = d;
+ }
+ }
+
+ return 1;
+}
+
/*
=item i_box(im, x1, y1, x2, y2, color)
#!perl -w
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl test.pl'
-
-######################### We start with some black magic to print on failure.
-
-# Change 1..1 below to 1..last_test_to_print .
-# (It may become useful if the test is moved to ./t subdirectory.)
use strict;
-use Test::More tests => 43;
-my $loaded;
+use Test::More tests => 235;
+use Imager ':all';
+use Imager::Test qw(is_color3);
+use constant PI => 3.14159265358979;
-BEGIN { use_ok(Imager=>':all'); }
init_log("testout/t21draw.log",1);
my $redobj = NC(255, 0, 0);
my $blue = { hue=>240, saturation=>1, value=>1 };
my $white = '#FFFFFF';
-my $img = Imager->new(xsize=>100, ysize=>500);
-
-ok($img->box(color=>$blueobj, xmin=>10, ymin=>10, xmax=>48, ymax=>18),
- "box with color obj");
-ok($img->box(color=>$blue, xmin=>10, ymin=>20, xmax=>48, ymax=>28),
- "box with color");
-ok($img->box(color=>$redobj, xmin=>10, ymin=>30, xmax=>28, ymax=>48, filled=>1),
- "filled box with color obj");
-ok($img->box(color=>$red, xmin=>30, ymin=>30, xmax=>48, ymax=>48, filled=>1),
- "filled box with color");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>24, color=>$redobj),
- "filled arc with colorobj");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>20, color=>$green),
- "filled arc with colorobj");
-ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$white, d1=>325, d2=>225),
- "filled arc with color");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$blue, d1=>225, d2=>325),
- "filled arc with color");
-ok($img->arc('x'=>75, 'y'=>25, r=>15, color=>$green, aa=>1),
- "filled arc with color");
-
-ok($img->line(color=>$blueobj, x1=>5, y1=>55, x2=>35, y2=>95),
- "line with colorobj");
-
-# FIXME - neither the start nor end-point is set for a non-aa line
-my $c = Imager::i_get_pixel($img->{IMG}, 5, 55);
-ok(color_cmp($c, $blueobj) == 0, "# TODO start point not set");
-
-ok($img->line(color=>$red, x1=>10, y1=>55, x2=>40, y2=>95, aa=>1),
- "aa line with color");
-ok($img->line(color=>$green, x1=>15, y1=>55, x2=>45, y2=>95, antialias=>1),
- "antialias line with color");
-
-ok($img->polyline(points=>[ [ 55, 55 ], [ 90, 60 ], [ 95, 95] ],
- color=>$redobj),
- "polyline points with color obj");
-ok($img->polyline('x'=>[ 55, 85, 90 ], 'y'=>[60, 65, 95], color=>$green, aa=>1),
- "polyline xy with color aa");
-ok($img->polyline('x'=>[ 55, 80, 85 ], 'y'=>[65, 70, 95], color=>$green,
- antialias=>1),
- "polyline xy with color antialias");
-
-ok($img->setpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], color=>$red),
- "set array of pixels");
-ok($img->setpixel('x'=>39, 'y'=>55, color=>$green),
- "set single pixel");
-use Imager::Color::Float;
-my $flred = Imager::Color::Float->new(1, 0, 0, 0);
-my $flgreen = Imager::Color::Float->new(0, 1, 0, 0);
-ok($img->setpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59], color=>$flred),
- "set array of float pixels");
-ok($img->setpixel('x'=>45, 'y'=>55, color=>$flgreen),
- "set single float pixel");
-my @gp = $img->getpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59]);
-ok(grep($_->isa('Imager::Color'), @gp) == 3, "check getpixel result type");
-ok(grep(color_cmp($_, NC(255, 0, 0)) == 0, @gp) == 3,
- "check getpixel result colors");
-my $gp = $img->getpixel('x'=>45, 'y'=>55);
-ok($gp->isa('Imager::Color'), "check scalar getpixel type");
-ok(color_cmp($gp, NC(0, 255, 0)) == 0, "check scalar getpixel color");
-@gp = $img->getpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], type=>'float');
-ok(grep($_->isa('Imager::Color::Float'), @gp) == 3,
- "check getpixel float result type");
-ok(grep(color_cmp($_, $flred) == 0, @gp) == 3,
- "check getpixel float result type");
-$gp = $img->getpixel('x'=>39, 'y'=>55, type=>'float');
-ok($gp->isa('Imager::Color::Float'), "check scalar float getpixel type");
-ok(color_cmp($gp, $flgreen) == 0, "check scalar float getpixel color");
-
-# more complete arc tests
-ok($img->arc(x=>25, 'y'=>125, r=>20, d1=>315, d2=>45, color=>$greenobj),
- "color arc through angle 0");
-# use diff combine here to make sure double writing is noticable
-ok($img->arc(x=>75, 'y'=>125, r=>20, d1=>315, d2=>45,
- fill => { solid=>$blueobj, combine => 'diff' }),
- "fill arc through angle 0");
-ok($img->arc(x=>25, 'y'=>175, r=>20, d1=>315, d2=>225, color=>$redobj),
- "concave color arc");
-angle_marker($img, 25, 175, 23, 315, 225);
-ok($img->arc(x=>75, 'y'=>175, r=>20, d1=>315, d2=>225,
- fill => { solid=>$greenobj, combine=>'diff' }),
- "concave fill arc");
-angle_marker($img, 75, 175, 23, 315, 225);
-ok($img->arc(x=>25, y=>225, r=>20, d1=>135, d2=>45, color=>$redobj),
- "another concave color arc");
-angle_marker($img, 25, 225, 23, 45, 135);
-ok($img->arc(x=>75, y=>225, r=>20, d1=>135, d2=>45,
- fill => { solid=>$blueobj, combine=>'diff' }),
- "another concave fillarc");
-angle_marker($img, 75, 225, 23, 45, 135);
-ok($img->arc(x=>25, y=>275, r=>20, d1=>135, d2=>45, color=>$redobj, aa=>1),
- "concave color arc aa");
-ok($img->arc(x=>75, y=>275, r=>20, d1=>135, d2=>45,
- fill => { solid=>$blueobj, combine=>'diff' }, aa=>1),
- "concave fill arc aa");
-
-ok($img->circle(x=>25, y=>325, r=>20, color=>$redobj),
- "color circle no aa");
-ok($img->circle(x=>75, y=>325, r=>20, color=>$redobj, aa=>1),
- "color circle aa");
-ok($img->circle(x=>25, 'y'=>375, r=>20,
- fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
- "fill circle no aa");
-ok($img->circle(x=>75, 'y'=>375, r=>20, aa=>1,
- fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
- "fill circle aa");
-
-ok($img->arc(x=>50, y=>450, r=>45, d1=>135, d2=>45,
- fill => { solid=>$blueobj, combine=>'diff' }),
- "another concave fillarc");
-angle_marker($img, 50, 450, 47, 45, 135);
-
-ok($img->write(file=>'testout/t21draw.ppm'),
- "saving output");
+{
+ my $img = Imager->new(xsize=>100, ysize=>500);
+
+ ok($img->box(color=>$blueobj, xmin=>10, ymin=>10, xmax=>48, ymax=>18),
+ "box with color obj");
+ ok($img->box(color=>$blue, xmin=>10, ymin=>20, xmax=>48, ymax=>28),
+ "box with color");
+ ok($img->box(color=>$redobj, xmin=>10, ymin=>30, xmax=>28, ymax=>48, filled=>1),
+ "filled box with color obj");
+ ok($img->box(color=>$red, xmin=>30, ymin=>30, xmax=>48, ymax=>48, filled=>1),
+ "filled box with color");
+
+ ok($img->arc('x'=>75, 'y'=>25, r=>24, color=>$redobj),
+ "filled arc with colorobj");
+
+ ok($img->arc('x'=>75, 'y'=>25, r=>20, color=>$green),
+ "filled arc with colorobj");
+ ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$white, d1=>325, d2=>225),
+ "filled arc with color");
+
+ ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$blue, d1=>225, d2=>325),
+ "filled arc with color");
+ ok($img->arc('x'=>75, 'y'=>25, r=>15, color=>$green, aa=>1),
+ "filled arc with color");
+
+ ok($img->line(color=>$blueobj, x1=>5, y1=>55, x2=>35, y2=>95),
+ "line with colorobj");
+
+ # FIXME - neither the start nor end-point is set for a non-aa line
+ my $c = Imager::i_get_pixel($img->{IMG}, 5, 55);
+ ok(color_cmp($c, $blueobj) == 0, "# TODO start point not set");
+
+ ok($img->line(color=>$red, x1=>10, y1=>55, x2=>40, y2=>95, aa=>1),
+ "aa line with color");
+ ok($img->line(color=>$green, x1=>15, y1=>55, x2=>45, y2=>95, antialias=>1),
+ "antialias line with color");
+
+ ok($img->polyline(points=>[ [ 55, 55 ], [ 90, 60 ], [ 95, 95] ],
+ color=>$redobj),
+ "polyline points with color obj");
+ ok($img->polyline('x'=>[ 55, 85, 90 ], 'y'=>[60, 65, 95], color=>$green, aa=>1),
+ "polyline xy with color aa");
+ ok($img->polyline('x'=>[ 55, 80, 85 ], 'y'=>[65, 70, 95], color=>$green,
+ antialias=>1),
+ "polyline xy with color antialias");
+
+ ok($img->setpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], color=>$red),
+ "set array of pixels");
+ ok($img->setpixel('x'=>39, 'y'=>55, color=>$green),
+ "set single pixel");
+ use Imager::Color::Float;
+ my $flred = Imager::Color::Float->new(1, 0, 0, 0);
+ my $flgreen = Imager::Color::Float->new(0, 1, 0, 0);
+ ok($img->setpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59], color=>$flred),
+ "set array of float pixels");
+ ok($img->setpixel('x'=>45, 'y'=>55, color=>$flgreen),
+ "set single float pixel");
+ my @gp = $img->getpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59]);
+ ok(grep($_->isa('Imager::Color'), @gp) == 3, "check getpixel result type");
+ ok(grep(color_cmp($_, NC(255, 0, 0)) == 0, @gp) == 3,
+ "check getpixel result colors");
+ my $gp = $img->getpixel('x'=>45, 'y'=>55);
+ ok($gp->isa('Imager::Color'), "check scalar getpixel type");
+ ok(color_cmp($gp, NC(0, 255, 0)) == 0, "check scalar getpixel color");
+ @gp = $img->getpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], type=>'float');
+ ok(grep($_->isa('Imager::Color::Float'), @gp) == 3,
+ "check getpixel float result type");
+ ok(grep(color_cmp($_, $flred) == 0, @gp) == 3,
+ "check getpixel float result type");
+ $gp = $img->getpixel('x'=>39, 'y'=>55, type=>'float');
+ ok($gp->isa('Imager::Color::Float'), "check scalar float getpixel type");
+ ok(color_cmp($gp, $flgreen) == 0, "check scalar float getpixel color");
+
+ # more complete arc tests
+ ok($img->arc(x=>25, 'y'=>125, r=>20, d1=>315, d2=>45, color=>$greenobj),
+ "color arc through angle 0");
+ # use diff combine here to make sure double writing is noticable
+ ok($img->arc(x=>75, 'y'=>125, r=>20, d1=>315, d2=>45,
+ fill => { solid=>$blueobj, combine => 'diff' }),
+ "fill arc through angle 0");
+ ok($img->arc(x=>25, 'y'=>175, r=>20, d1=>315, d2=>225, color=>$redobj),
+ "concave color arc");
+ angle_marker($img, 25, 175, 23, 315, 225);
+ ok($img->arc(x=>75, 'y'=>175, r=>20, d1=>315, d2=>225,
+ fill => { solid=>$greenobj, combine=>'diff' }),
+ "concave fill arc");
+ angle_marker($img, 75, 175, 23, 315, 225);
+ ok($img->arc(x=>25, y=>225, r=>20, d1=>135, d2=>45, color=>$redobj),
+ "another concave color arc");
+ angle_marker($img, 25, 225, 23, 45, 135);
+ ok($img->arc(x=>75, y=>225, r=>20, d1=>135, d2=>45,
+ fill => { solid=>$blueobj, combine=>'diff' }),
+ "another concave fillarc");
+ angle_marker($img, 75, 225, 23, 45, 135);
+ ok($img->arc(x=>25, y=>275, r=>20, d1=>135, d2=>45, color=>$redobj, aa=>1),
+ "concave color arc aa");
+ ok($img->arc(x=>75, y=>275, r=>20, d1=>135, d2=>45,
+ fill => { solid=>$blueobj, combine=>'diff' }, aa=>1),
+ "concave fill arc aa");
+
+ ok($img->circle(x=>25, y=>325, r=>20, color=>$redobj),
+ "color circle no aa");
+ ok($img->circle(x=>75, y=>325, r=>20, color=>$redobj, aa=>1),
+ "color circle aa");
+ ok($img->circle(x=>25, 'y'=>375, r=>20,
+ fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
+ "fill circle no aa");
+ ok($img->circle(x=>75, 'y'=>375, r=>20, aa=>1,
+ fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
+ "fill circle aa");
+
+ ok($img->arc(x=>50, y=>450, r=>45, d1=>135, d2=>45,
+ fill => { solid=>$blueobj, combine=>'diff' }),
+ "another concave fillarc");
+ angle_marker($img, 50, 450, 47, 45, 135);
+
+ ok($img->write(file=>'testout/t21draw.ppm'),
+ "saving output");
+}
+
+{
+ my $im = Imager->new(xsize => 400, ysize => 400);
+ ok($im->arc(x => 200, y => 202, r => 10, filled => 0),
+ "draw circle outline");
+ is_color3($im->getpixel(x => 200, y => 202), 0, 0, 0,
+ "check center not filled");
+ ok($im->arc(x => 198, y => 200, r => 13, filled => 0, color => "#f88"),
+ "draw circle outline");
+ is_color3($im->getpixel(x => 198, y => 200), 0, 0, 0,
+ "check center not filled");
+ ok($im->arc(x => 200, y => 200, r => 24, filled => 0, color => "#0ff"),
+ "draw circle outline");
+ my $r = 40;
+ while ($r < 180) {
+ ok($im->arc(x => 200, y => 200, r => $r, filled => 0, color => "#ff0"),
+ "draw circle outline r $r");
+ $r += 15;
+ }
+ ok($im->write(file => "testout/t21circout.ppm"),
+ "save arc outline");
+}
+
+{
+ my $im = Imager->new(xsize => 400, ysize => 400);
+ {
+ my $lc = Imager::Color->new(32, 32, 32);
+ my $an = 0;
+ while ($an < 360) {
+ my $an_r = $an * PI / 180;
+ my $ca = cos($an_r);
+ my $sa = sin($an_r);
+ $im->line(aa => 1, color => $lc,
+ x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa,
+ x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa);
+ $an += 5;
+ }
+ }
+ my $d1 = 0;
+ my $r = 20;
+ while ($d1 < 350) {
+ ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0),
+ "draw arc outline r$r d1$d1 len 300");
+ ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00'),
+ "draw arc outline r$r d1$d1 len 40");
+ $d1 += 15;
+ $r += 6;
+ }
+ is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0,
+ "check center not filled");
+ ok($im->write(file => "testout/t21arcout.ppm"),
+ "save arc outline");
+}
+
+{
+ my $im = Imager->new(xsize => 400, ysize => 400);
+ ok($im->arc(x => 197, y => 201, r => 10, filled => 0, aa => 1, color => 'white'),
+ "draw circle outline");
+ is_color3($im->getpixel(x => 197, y => 201), 0, 0, 0,
+ "check center not filled");
+ ok($im->arc(x => 197, y => 205, r => 13, filled => 0, color => "#f88", aa => 1),
+ "draw circle outline");
+ is_color3($im->getpixel(x => 197, y => 205), 0, 0, 0,
+ "check center not filled");
+ ok($im->arc(x => 190, y => 215, r => 24, filled => 0, color => [0,0, 255, 128], aa => 1),
+ "draw circle outline");
+ my $r = 40;
+ while ($r < 190) {
+ ok($im->arc(x => 197, y => 201, r => $r, filled => 0, aa => 1, color => '#ff0'), "draw aa circle rad $r");
+ $r += 7;
+ }
+ ok($im->write(file => "testout/t21aacircout.ppm"),
+ "save arc outline");
+}
+
+{
+ my $im = Imager->new(xsize => 400, ysize => 400);
+ {
+ my $lc = Imager::Color->new(32, 32, 32);
+ my $an = 0;
+ while ($an < 360) {
+ my $an_r = $an * PI / 180;
+ my $ca = cos($an_r);
+ my $sa = sin($an_r);
+ $im->line(aa => 1, color => $lc,
+ x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa,
+ x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa);
+ $an += 5;
+ }
+ }
+ my $d1 = 0;
+ my $r = 20;
+ while ($d1 < 350) {
+ ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0, aa => 1),
+ "draw aa arc outline r$r d1$d1 len 300");
+ ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00', aa => 1),
+ "draw aa arc outline r$r d1$d1 len 40");
+ $d1 += 15;
+ $r += 6;
+ }
+ is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0,
+ "check center not filled");
+ ok($im->write(file => "testout/t21aaarcout.ppm"),
+ "save arc outline");
+}
+
+{
+ my $im = Imager->new(xsize => 400, ysize => 400);
+
+ my $an = 0;
+ my $step = 15;
+ while ($an <= 360-$step) {
+ my $cx = int(200 + 20 * cos(($an+$step/2) * PI / 180));
+ my $cy = int(200 + 20 * sin(($an+$step/2) * PI / 180));
+
+ ok($im->arc(x => $cx, y => $cy, aa => 1, color => "#fff",
+ d1 => $an, d2 => $an+$step, filled => 0, r => 170),
+ "angle starting from $an");
+ ok($im->arc(x => $cx, y => $cy, aa => 1, color => "#ff0",
+ d1 => $an, d2 => $an+$step, r => 168),
+ "filled angle starting from $an");
+
+ $an += $step;
+ }
+ ok($im->write(file => "testout/t21aaarcs.ppm"),
+ "save arc outline");
+}
+
malloc_state();
+unless ($ENV{IMAGER_KEEP_FILES}) {
+ unlink "testout/t21draw.ppm";
+ unlink "testout/t21circout.ppm";
+ unlink "testout/t21aacircout.ppm";
+ unlink "testout/t21arcout.ppm";
+ unlink "testout/t21aaarcout.ppm";
+ unlink "testout/t21aaarcs.ppm";
+}
+
sub color_cmp {
my ($l, $r) = @_;
my @l = $l->rgba;
|| $l[2] <=> $r[2];
}
-use constant PI => 4 * atan2(1,1);
-
sub angle_marker {
my ($img, $x, $y, $radius, @angles) = @_;