12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187 |
- /*
- * The Python Imaging Library.
- * $Id$
- *
- * a simple drawing package for the Imaging library
- *
- * history:
- * 1996-04-13 fl Created.
- * 1996-04-30 fl Added transforms and polygon support.
- * 1996-08-12 fl Added filled polygons.
- * 1996-11-05 fl Fixed float/int confusion in polygon filler
- * 1997-07-04 fl Support 32-bit images (C++ would have been nice)
- * 1998-09-09 fl Eliminated qsort casts; improved rectangle clipping
- * 1998-09-10 fl Fixed fill rectangle to include lower edge (!)
- * 1998-12-29 fl Added arc, chord, and pieslice primitives
- * 1999-01-10 fl Added some level 2 ("arrow") stuff (experimental)
- * 1999-02-06 fl Added bitmap primitive
- * 1999-07-26 fl Eliminated a compiler warning
- * 1999-07-31 fl Pass ink as void* instead of int
- * 2002-12-10 fl Added experimental RGBA-on-RGB drawing
- * 2004-09-04 fl Support simple wide lines (no joins)
- * 2005-05-25 fl Fixed line width calculation
- *
- * Copyright (c) 1996-2006 by Fredrik Lundh
- * Copyright (c) 1997-2006 by Secret Labs AB.
- *
- * See the README file for information on usage and redistribution.
- */
- /* FIXME: support fill/outline attribute for all filled shapes */
- /* FIXME: support zero-winding fill */
- /* FIXME: add drawing context, support affine transforms */
- /* FIXME: support clip window (and mask?) */
- #include "Imaging.h"
- #include <math.h>
- #define CEIL(v) (int) ceil(v)
- #define FLOOR(v) ((v) >= 0.0 ? (int) (v) : (int) floor(v))
- #define INK8(ink) (*(UINT8*)ink)
- /*
- * Rounds around zero (up=away from zero, down=torwards zero)
- * This guarantees that ROUND_UP|DOWN(f) == -ROUND_UP|DOWN(-f)
- */
- #define ROUND_UP(f) ((int) ((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F)))
- #define ROUND_DOWN(f) ((int) ((f) >= 0.0 ? ceil((f) - 0.5F) : -ceil(fabs(f) - 0.5F)))
- /* -------------------------------------------------------------------- */
- /* Primitives */
- /* -------------------------------------------------------------------- */
- typedef struct {
- /* edge descriptor for polygon engine */
- int d;
- int x0, y0;
- int xmin, ymin, xmax, ymax;
- float dx;
- } Edge;
- /* Type used in "polygon*" functions */
- typedef void (*hline_handler)(Imaging, int, int, int, int);
- static inline void
- point8(Imaging im, int x, int y, int ink)
- {
- if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
- if (strncmp(im->mode, "I;16", 4) == 0) {
- im->image8[y][x*2] = (UINT8) ink;
- im->image8[y][x*2+1] = (UINT8) ink;
- } else {
- im->image8[y][x] = (UINT8) ink;
- }
- }
- }
- static inline void
- point32(Imaging im, int x, int y, int ink)
- {
- if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize)
- im->image32[y][x] = ink;
- }
- static inline void
- point32rgba(Imaging im, int x, int y, int ink)
- {
- unsigned int tmp1;
- if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
- UINT8* out = (UINT8*) im->image[y]+x*4;
- UINT8* in = (UINT8*) &ink;
- out[0] = BLEND(in[3], out[0], in[0], tmp1);
- out[1] = BLEND(in[3], out[1], in[1], tmp1);
- out[2] = BLEND(in[3], out[2], in[2], tmp1);
- }
- }
- static inline void
- hline8(Imaging im, int x0, int y0, int x1, int ink)
- {
- int tmp, pixelwidth;
- if (y0 >= 0 && y0 < im->ysize) {
- if (x0 > x1)
- tmp = x0, x0 = x1, x1 = tmp;
- if (x0 < 0)
- x0 = 0;
- else if (x0 >= im->xsize)
- return;
- if (x1 < 0)
- return;
- else if (x1 >= im->xsize)
- x1 = im->xsize-1;
- if (x0 <= x1) {
- pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
- memset(im->image8[y0] + x0 * pixelwidth, (UINT8) ink,
- (x1 - x0 + 1) * pixelwidth);
- }
- }
- }
- static inline void
- hline32(Imaging im, int x0, int y0, int x1, int ink)
- {
- int tmp;
- INT32* p;
- if (y0 >= 0 && y0 < im->ysize) {
- if (x0 > x1)
- tmp = x0, x0 = x1, x1 = tmp;
- if (x0 < 0)
- x0 = 0;
- else if (x0 >= im->xsize)
- return;
- if (x1 < 0)
- return;
- else if (x1 >= im->xsize)
- x1 = im->xsize-1;
- p = im->image32[y0];
- while (x0 <= x1)
- p[x0++] = ink;
- }
- }
- static inline void
- hline32rgba(Imaging im, int x0, int y0, int x1, int ink)
- {
- int tmp;
- unsigned int tmp1;
- if (y0 >= 0 && y0 < im->ysize) {
- if (x0 > x1)
- tmp = x0, x0 = x1, x1 = tmp;
- if (x0 < 0)
- x0 = 0;
- else if (x0 >= im->xsize)
- return;
- if (x1 < 0)
- return;
- else if (x1 >= im->xsize)
- x1 = im->xsize-1;
- if (x0 <= x1) {
- UINT8* out = (UINT8*) im->image[y0]+x0*4;
- UINT8* in = (UINT8*) &ink;
- while (x0 <= x1) {
- out[0] = BLEND(in[3], out[0], in[0], tmp1);
- out[1] = BLEND(in[3], out[1], in[1], tmp1);
- out[2] = BLEND(in[3], out[2], in[2], tmp1);
- x0++; out += 4;
- }
- }
- }
- }
- static inline void
- line8(Imaging im, int x0, int y0, int x1, int y1, int ink)
- {
- int i, n, e;
- int dx, dy;
- int xs, ys;
- /* normalize coordinates */
- dx = x1-x0;
- if (dx < 0)
- dx = -dx, xs = -1;
- else
- xs = 1;
- dy = y1-y0;
- if (dy < 0)
- dy = -dy, ys = -1;
- else
- ys = 1;
- n = (dx > dy) ? dx : dy;
- if (dx == 0)
- /* vertical */
- for (i = 0; i < dy; i++) {
- point8(im, x0, y0, ink);
- y0 += ys;
- }
- else if (dy == 0)
- /* horizontal */
- for (i = 0; i < dx; i++) {
- point8(im, x0, y0, ink);
- x0 += xs;
- }
- else if (dx > dy) {
- /* bresenham, horizontal slope */
- n = dx;
- dy += dy;
- e = dy - dx;
- dx += dx;
- for (i = 0; i < n; i++) {
- point8(im, x0, y0, ink);
- if (e >= 0) {
- y0 += ys;
- e -= dx;
- }
- e += dy;
- x0 += xs;
- }
- } else {
- /* bresenham, vertical slope */
- n = dy;
- dx += dx;
- e = dx - dy;
- dy += dy;
- for (i = 0; i < n; i++) {
- point8(im, x0, y0, ink);
- if (e >= 0) {
- x0 += xs;
- e -= dy;
- }
- e += dx;
- y0 += ys;
- }
- }
- }
- static inline void
- line32(Imaging im, int x0, int y0, int x1, int y1, int ink)
- {
- int i, n, e;
- int dx, dy;
- int xs, ys;
- /* normalize coordinates */
- dx = x1-x0;
- if (dx < 0)
- dx = -dx, xs = -1;
- else
- xs = 1;
- dy = y1-y0;
- if (dy < 0)
- dy = -dy, ys = -1;
- else
- ys = 1;
- n = (dx > dy) ? dx : dy;
- if (dx == 0)
- /* vertical */
- for (i = 0; i < dy; i++) {
- point32(im, x0, y0, ink);
- y0 += ys;
- }
- else if (dy == 0)
- /* horizontal */
- for (i = 0; i < dx; i++) {
- point32(im, x0, y0, ink);
- x0 += xs;
- }
- else if (dx > dy) {
- /* bresenham, horizontal slope */
- n = dx;
- dy += dy;
- e = dy - dx;
- dx += dx;
- for (i = 0; i < n; i++) {
- point32(im, x0, y0, ink);
- if (e >= 0) {
- y0 += ys;
- e -= dx;
- }
- e += dy;
- x0 += xs;
- }
- } else {
- /* bresenham, vertical slope */
- n = dy;
- dx += dx;
- e = dx - dy;
- dy += dy;
- for (i = 0; i < n; i++) {
- point32(im, x0, y0, ink);
- if (e >= 0) {
- x0 += xs;
- e -= dy;
- }
- e += dx;
- y0 += ys;
- }
- }
- }
- static inline void
- line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink)
- {
- int i, n, e;
- int dx, dy;
- int xs, ys;
- /* normalize coordinates */
- dx = x1-x0;
- if (dx < 0)
- dx = -dx, xs = -1;
- else
- xs = 1;
- dy = y1-y0;
- if (dy < 0)
- dy = -dy, ys = -1;
- else
- ys = 1;
- n = (dx > dy) ? dx : dy;
- if (dx == 0)
- /* vertical */
- for (i = 0; i < dy; i++) {
- point32rgba(im, x0, y0, ink);
- y0 += ys;
- }
- else if (dy == 0)
- /* horizontal */
- for (i = 0; i < dx; i++) {
- point32rgba(im, x0, y0, ink);
- x0 += xs;
- }
- else if (dx > dy) {
- /* bresenham, horizontal slope */
- n = dx;
- dy += dy;
- e = dy - dx;
- dx += dx;
- for (i = 0; i < n; i++) {
- point32rgba(im, x0, y0, ink);
- if (e >= 0) {
- y0 += ys;
- e -= dx;
- }
- e += dy;
- x0 += xs;
- }
- } else {
- /* bresenham, vertical slope */
- n = dy;
- dx += dx;
- e = dx - dy;
- dy += dy;
- for (i = 0; i < n; i++) {
- point32rgba(im, x0, y0, ink);
- if (e >= 0) {
- x0 += xs;
- e -= dy;
- }
- e += dx;
- y0 += ys;
- }
- }
- }
- static int
- x_cmp(const void *x0, const void *x1)
- {
- float diff = *((float*)x0) - *((float*)x1);
- if (diff < 0)
- return -1;
- else if (diff > 0)
- return 1;
- else
- return 0;
- }
- /*
- * Filled polygon draw function using scan line algorithm.
- */
- static inline int
- polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill,
- hline_handler hline)
- {
- Edge** edge_table;
- float* xx;
- int edge_count = 0;
- int ymin = im->ysize - 1;
- int ymax = 0;
- int i;
- if (n <= 0) {
- return 0;
- }
- /* Initialize the edge table and find polygon boundaries */
- /* malloc check ok, using calloc */
- edge_table = calloc(n, sizeof(Edge*));
- if (!edge_table) {
- return -1;
- }
- for (i = 0; i < n; i++) {
- /* This causes the pixels of horizontal edges to be drawn twice :(
- * but without it there are inconsistencies in ellipses */
- if (e[i].ymin == e[i].ymax) {
- (*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink);
- continue;
- }
- if (ymin > e[i].ymin) {
- ymin = e[i].ymin;
- }
- if (ymax < e[i].ymax) {
- ymax = e[i].ymax;
- }
- edge_table[edge_count++] = (e + i);
- }
- if (ymin < 0) {
- ymin = 0;
- }
- if (ymax > im->ysize) {
- ymax = im->ysize;
- }
- /* Process the edge table with a scan line searching for intersections */
- /* malloc check ok, using calloc */
- xx = calloc(edge_count * 2, sizeof(float));
- if (!xx) {
- free(edge_table);
- return -1;
- }
- for (; ymin <= ymax; ymin++) {
- int j = 0;
- for (i = 0; i < edge_count; i++) {
- Edge* current = edge_table[i];
- if (ymin >= current->ymin && ymin <= current->ymax) {
- xx[j++] = (ymin - current->y0) * current->dx + current->x0;
- }
- /* Needed to draw consistent polygons */
- if (ymin == current->ymax && ymin < ymax) {
- xx[j] = xx[j - 1];
- j++;
- }
- }
- qsort(xx, j, sizeof(float), x_cmp);
- for (i = 1; i < j; i += 2) {
- (*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
- }
- }
- free(xx);
- free(edge_table);
- return 0;
- }
- static inline int
- polygon8(Imaging im, int n, Edge *e, int ink, int eofill)
- {
- return polygon_generic(im, n, e, ink, eofill, hline8);
- }
- static inline int
- polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
- {
- return polygon_generic(im, n, e, ink, eofill, hline32);
- }
- static inline int
- polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
- {
- return polygon_generic(im, n, e, ink, eofill, hline32rgba);
- }
- static inline void
- add_edge(Edge *e, int x0, int y0, int x1, int y1)
- {
- /* printf("edge %d %d %d %d\n", x0, y0, x1, y1); */
- if (x0 <= x1)
- e->xmin = x0, e->xmax = x1;
- else
- e->xmin = x1, e->xmax = x0;
- if (y0 <= y1)
- e->ymin = y0, e->ymax = y1;
- else
- e->ymin = y1, e->ymax = y0;
- if (y0 == y1) {
- e->d = 0;
- e->dx = 0.0;
- } else {
- e->dx = ((float)(x1-x0)) / (y1-y0);
- if (y0 == e->ymin)
- e->d = 1;
- else
- e->d = -1;
- }
- e->x0 = x0;
- e->y0 = y0;
- }
- typedef struct {
- void (*point)(Imaging im, int x, int y, int ink);
- void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
- void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
- int (*polygon)(Imaging im, int n, Edge *e, int ink, int eofill);
- } DRAW;
- DRAW draw8 = { point8, hline8, line8, polygon8 };
- DRAW draw32 = { point32, hline32, line32, polygon32 };
- DRAW draw32rgba = { point32rgba, hline32rgba, line32rgba, polygon32rgba };
- /* -------------------------------------------------------------------- */
- /* Interface */
- /* -------------------------------------------------------------------- */
- #define DRAWINIT()\
- if (im->image8) {\
- draw = &draw8;\
- ink = INK8(ink_);\
- } else {\
- draw = (op) ? &draw32rgba : &draw32; \
- memcpy(&ink, ink_, sizeof(ink)); \
- }
- int
- ImagingDrawPoint(Imaging im, int x0, int y0, const void* ink_, int op)
- {
- DRAW* draw;
- INT32 ink;
- DRAWINIT();
- draw->point(im, x0, y0, ink);
- return 0;
- }
- int
- ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void* ink_,
- int op)
- {
- DRAW* draw;
- INT32 ink;
- DRAWINIT();
- draw->line(im, x0, y0, x1, y1, ink);
- return 0;
- }
- int
- ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
- const void* ink_, int width, int op)
- {
- DRAW* draw;
- INT32 ink;
- int dx, dy;
- double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min;
- int dxmin, dxmax, dymin, dymax;
- Edge e[4];
- DRAWINIT();
- dx = x1-x0;
- dy = y1-y0;
- if (dx == 0 && dy == 0) {
- draw->point(im, x0, y0, ink);
- return 0;
- }
- big_hypotenuse = sqrt((double) (dx*dx + dy*dy));
- small_hypotenuse = (width - 1) / 2.0;
- ratio_max = ROUND_UP(small_hypotenuse) / big_hypotenuse;
- ratio_min = ROUND_DOWN(small_hypotenuse) / big_hypotenuse;
- dxmin = ROUND_DOWN(ratio_min * dy);
- dxmax = ROUND_DOWN(ratio_max * dy);
- dymin = ROUND_DOWN(ratio_min * dx);
- dymax = ROUND_DOWN(ratio_max * dx);
- {
- int vertices[4][2] = {
- {x0 - dxmin, y0 + dymax},
- {x1 - dxmin, y1 + dymax},
- {x1 + dxmax, y1 - dymin},
- {x0 + dxmax, y0 - dymin}
- };
- add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
- add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
- add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
- add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
- draw->polygon(im, 4, e, ink, 0);
- }
- return 0;
- }
- int
- ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1,
- const void* ink_, int fill, int width, int op)
- {
- int i;
- int y;
- int tmp;
- DRAW* draw;
- INT32 ink;
- DRAWINIT();
- if (y0 > y1)
- tmp = y0, y0 = y1, y1 = tmp;
- if (fill) {
- if (y0 < 0)
- y0 = 0;
- else if (y0 >= im->ysize)
- return 0;
- if (y1 < 0)
- return 0;
- else if (y1 > im->ysize)
- y1 = im->ysize;
- for (y = y0; y <= y1; y++)
- draw->hline(im, x0, y, x1, ink);
- } else {
- /* outline */
- if (width == 0) {
- width = 1;
- }
- for (i = 0; i < width; i++) {
- draw->hline(im, x0, y0+i, x1, ink);
- draw->hline(im, x0, y1-i, x1, ink);
- draw->line(im, x1-i, y0, x1-i, y1, ink);
- draw->line(im, x0+i, y1, x0+i, y0, ink);
- }
- }
- return 0;
- }
- int
- ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_,
- int fill, int op)
- {
- int i, n;
- DRAW* draw;
- INT32 ink;
- if (count <= 0)
- return 0;
- DRAWINIT();
- if (fill) {
- /* Build edge list */
- /* malloc check ok, using calloc */
- Edge* e = calloc(count, sizeof(Edge));
- if (!e) {
- (void) ImagingError_MemoryError();
- return -1;
- }
- for (i = n = 0; i < count-1; i++)
- add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3]);
- if (xy[i+i] != xy[0] || xy[i+i+1] != xy[1])
- add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[0], xy[1]);
- draw->polygon(im, n, e, ink, 0);
- free(e);
- } else {
- /* Outline */
- for (i = 0; i < count-1; i++)
- draw->line(im, xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3], ink);
- draw->line(im, xy[i+i], xy[i+i+1], xy[0], xy[1], ink);
- }
- return 0;
- }
- int
- ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void* ink,
- int op)
- {
- return ImagingFill2(
- im, ink, bitmap,
- x0, y0, x0 + bitmap->xsize, y0 + bitmap->ysize
- );
- }
- /* -------------------------------------------------------------------- */
- /* standard shapes */
- #define ARC 0
- #define CHORD 1
- #define PIESLICE 2
- static void
- ellipsePoint(int cx, int cy, int w, int h,
- float i, int *x, int *y)
- {
- float i_cos, i_sin;
- float x_f, y_f;
- double modf_int;
- i_cos = cos(i*M_PI/180);
- i_sin = sin(i*M_PI/180);
- x_f = (i_cos * w/2) + cx;
- y_f = (i_sin * h/2) + cy;
- if (modf(x_f, &modf_int) == 0.5) {
- *x = i_cos > 0 ? FLOOR(x_f) : CEIL(x_f);
- } else {
- *x = FLOOR(x_f + 0.5);
- }
- if (modf(y_f, &modf_int) == 0.5) {
- *y = i_sin > 0 ? FLOOR(y_f) : CEIL(y_f);
- } else {
- *y = FLOOR(y_f + 0.5);
- }
- }
- static int
- ellipse(Imaging im, int x0, int y0, int x1, int y1,
- float start, float end, const void* ink_, int fill,
- int width, int mode, int op)
- {
- float i;
- int inner;
- int n;
- int maxEdgeCount;
- int w, h;
- int x, y;
- int cx, cy;
- int lx = 0, ly = 0;
- int sx = 0, sy = 0;
- int lx_inner = 0, ly_inner = 0;
- int sx_inner = 0, sy_inner = 0;
- DRAW* draw;
- INT32 ink;
- Edge* e;
- DRAWINIT();
- while (end < start)
- end += 360;
- if (end - start > 360) {
- // no need to go in loops
- end = start + 361;
- }
- w = x1 - x0;
- h = y1 - y0;
- if (w <= 0 || h <= 0)
- return 0;
- cx = (x0 + x1) / 2;
- cy = (y0 + y1) / 2;
- if (!fill && width <= 1) {
- for (i = start; i < end+1; i++) {
- if (i > end) {
- i = end;
- }
- ellipsePoint(cx, cy, w, h, i, &x, &y);
- if (i != start)
- draw->line(im, lx, ly, x, y, ink);
- else
- sx = x, sy = y;
- lx = x, ly = y;
- }
- if (i != start) {
- if (mode == PIESLICE) {
- if (x != cx || y != cy) {
- draw->line(im, x, y, cx, cy, ink);
- draw->line(im, cx, cy, sx, sy, ink);
- }
- } else if (mode == CHORD) {
- if (x != sx || y != sy)
- draw->line(im, x, y, sx, sy, ink);
- }
- }
- } else {
- inner = (mode == ARC || !fill) ? 1 : 0;
- // Build edge list
- // malloc check UNDONE, FLOAT?
- maxEdgeCount = ceil(end - start);
- if (inner) {
- maxEdgeCount *= 2;
- }
- maxEdgeCount += 3;
- e = calloc(maxEdgeCount, sizeof(Edge));
- if (!e) {
- ImagingError_MemoryError();
- return -1;
- }
- // Outer circle
- n = 0;
- for (i = start; i < end+1; i++) {
- if (i > end) {
- i = end;
- }
- ellipsePoint(cx, cy, w, h, i, &x, &y);
- if (i == start) {
- sx = x, sy = y;
- } else {
- add_edge(&e[n++], lx, ly, x, y);
- }
- lx = x, ly = y;
- }
- if (n == 0)
- return 0;
- if (inner) {
- // Inner circle
- x0 += width - 1;
- y0 += width - 1;
- x1 -= width - 1;
- y1 -= width - 1;
- w = x1 - x0;
- h = y1 - y0;
- if (w <= 0 || h <= 0) {
- // ARC with no gap in the middle is a PIESLICE
- mode = PIESLICE;
- inner = 0;
- } else {
- for (i = start; i < end+1; i++) {
- if (i > end) {
- i = end;
- }
- ellipsePoint(cx, cy, w, h, i, &x, &y);
- if (i == start)
- sx_inner = x, sy_inner = y;
- else
- add_edge(&e[n++], lx_inner, ly_inner, x, y);
- lx_inner = x, ly_inner = y;
- }
- }
- }
- if (end - start < 360) {
- // Close polygon
- if (mode == PIESLICE) {
- if (x != cx || y != cy) {
- add_edge(&e[n++], sx, sy, cx, cy);
- add_edge(&e[n++], cx, cy, lx, ly);
- if (inner) {
- ImagingDrawWideLine(im, sx, sy, cx, cy, &ink, width, op);
- ImagingDrawWideLine(im, cx, cy, lx, ly, &ink, width, op);
- }
- }
- } else if (mode == CHORD) {
- add_edge(&e[n++], sx, sy, lx, ly);
- if (inner) {
- add_edge(&e[n++], sx_inner, sy_inner, lx_inner, ly_inner);
- }
- } else if (mode == ARC) {
- add_edge(&e[n++], sx, sy, sx_inner, sy_inner);
- add_edge(&e[n++], lx, ly, lx_inner, ly_inner);
- }
- }
- draw->polygon(im, n, e, ink, 0);
- free(e);
- }
- return 0;
- }
- int
- ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1,
- float start, float end, const void* ink, int width, int op)
- {
- return ellipse(im, x0, y0, x1, y1, start, end, ink, 0, width, ARC, op);
- }
- int
- ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1,
- float start, float end, const void* ink, int fill,
- int width, int op)
- {
- return ellipse(im, x0, y0, x1, y1, start, end, ink, fill, width, CHORD, op);
- }
- int
- ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1,
- const void* ink, int fill, int width, int op)
- {
- return ellipse(im, x0, y0, x1, y1, 0, 360, ink, fill, width, CHORD, op);
- }
- int
- ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1,
- float start, float end, const void* ink, int fill,
- int width, int op)
- {
- return ellipse(im, x0, y0, x1, y1, start, end, ink, fill, width, PIESLICE, op);
- }
- /* -------------------------------------------------------------------- */
- /* experimental level 2 ("arrow") graphics stuff. this implements
- portions of the arrow api on top of the Edge structure. the
- semantics are ok, except that "curve" flattens the bezier curves by
- itself */
- struct ImagingOutlineInstance {
- float x0, y0;
- float x, y;
- int count;
- Edge *edges;
- int size;
- };
- ImagingOutline
- ImagingOutlineNew(void)
- {
- ImagingOutline outline;
- outline = calloc(1, sizeof(struct ImagingOutlineInstance));
- if (!outline)
- return (ImagingOutline) ImagingError_MemoryError();
- outline->edges = NULL;
- outline->count = outline->size = 0;
- ImagingOutlineMove(outline, 0, 0);
- return outline;
- }
- void
- ImagingOutlineDelete(ImagingOutline outline)
- {
- if (!outline)
- return;
- if (outline->edges)
- free(outline->edges);
- free(outline);
- }
- static Edge*
- allocate(ImagingOutline outline, int extra)
- {
- Edge* e;
- if (outline->count + extra > outline->size) {
- /* expand outline buffer */
- outline->size += extra + 25;
- if (!outline->edges) {
- /* malloc check ok, uses calloc for overflow */
- e = calloc(outline->size, sizeof(Edge));
- } else {
- if (outline->size > INT_MAX / sizeof(Edge)) {
- return NULL;
- }
- /* malloc check ok, overflow checked above */
- e = realloc(outline->edges, outline->size * sizeof(Edge));
- }
- if (!e)
- return NULL;
- outline->edges = e;
- }
- e = outline->edges + outline->count;
- outline->count += extra;
- return e;
- }
- int
- ImagingOutlineMove(ImagingOutline outline, float x0, float y0)
- {
- outline->x = outline->x0 = x0;
- outline->y = outline->y0 = y0;
- return 0;
- }
- int
- ImagingOutlineLine(ImagingOutline outline, float x1, float y1)
- {
- Edge* e;
- e = allocate(outline, 1);
- if (!e)
- return -1; /* out of memory */
- add_edge(e, (int) outline->x, (int) outline->y, (int) x1, (int) y1);
- outline->x = x1;
- outline->y = y1;
- return 0;
- }
- int
- ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
- float x2, float y2, float x3, float y3)
- {
- Edge* e;
- int i;
- float xo, yo;
- #define STEPS 32
- e = allocate(outline, STEPS);
- if (!e)
- return -1; /* out of memory */
- xo = outline->x;
- yo = outline->y;
- /* flatten the bezier segment */
- for (i = 1; i <= STEPS; i++) {
- float t = ((float) i) / STEPS;
- float t2 = t*t;
- float t3 = t2*t;
- float u = 1.0F - t;
- float u2 = u*u;
- float u3 = u2*u;
- float x = outline->x*u3 + 3*(x1*t*u2 + x2*t2*u) + x3*t3 + 0.5;
- float y = outline->y*u3 + 3*(y1*t*u2 + y2*t2*u) + y3*t3 + 0.5;
- add_edge(e++, xo, yo, (int) x, (int) y);
- xo = x, yo = y;
- }
- outline->x = xo;
- outline->y = yo;
- return 0;
- }
- int
- ImagingOutlineClose(ImagingOutline outline)
- {
- if (outline->x == outline->x0 && outline->y == outline->y0)
- return 0;
- return ImagingOutlineLine(outline, outline->x0, outline->y0);
- }
- int
- ImagingOutlineTransform(ImagingOutline outline, double a[6])
- {
- Edge *eIn;
- Edge *eOut;
- int i, n;
- int x0, y0, x1, y1;
- int X0, Y0, X1, Y1;
- double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
- double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
- eIn = outline->edges;
- n = outline->count;
- /* FIXME: ugly! */
- outline->edges = NULL;
- outline->count = outline->size = 0;
- eOut = allocate(outline, n);
- if (!eOut) {
- outline->edges = eIn;
- outline->count = outline->size = n;
- ImagingError_MemoryError();
- return -1;
- }
- for (i = 0; i < n; i++) {
- x0 = eIn->x0;
- y0 = eIn->y0;
- /* FIXME: ouch! */
- if (eIn->x0 == eIn->xmin)
- x1 = eIn->xmax;
- else
- x1 = eIn->xmin;
- if (eIn->y0 == eIn->ymin)
- y1 = eIn->ymax;
- else
- y1 = eIn->ymin;
- /* full moon tonight! if this doesn't work, you may need to
- upgrade your compiler (make sure you have the right service
- pack) */
- X0 = (int) (a0*x0 + a1*y0 + a2);
- Y0 = (int) (a3*x0 + a4*y0 + a5);
- X1 = (int) (a0*x1 + a1*y1 + a2);
- Y1 = (int) (a3*x1 + a4*y1 + a5);
- add_edge(eOut, X0, Y0, X1, Y1);
- eIn++;
- eOut++;
- }
- free(eIn);
- return 0;
- }
- int
- ImagingDrawOutline(Imaging im, ImagingOutline outline, const void* ink_,
- int fill, int op)
- {
- DRAW* draw;
- INT32 ink;
- DRAWINIT();
- draw->polygon(im, outline->count, outline->edges, ink, 0);
- return 0;
- }
|