xref: /PHP-5.6/ext/gd/libgd/gd_arc_f_buggy.c (revision 4dc99457)
1 /* This is potentially great stuff, but fails against the test
2    program at the end. This would probably be much more
3    efficient than the implementation currently in gd.c if the
4    errors in the output were corrected. TBB */
5 
6 #if 0
7 
8 #include "gd.h"
9 #include <math.h>
10 
11 /* Courtesy of F J Franklin. */
12 
13 static gdPoint gdArcClosest (int width, int height, int angle);
14 
15 void
16 gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int width, int height, int color)
17 {
18   gdImageFilledArc (im, cx, cy, width, height, 0, 360, color, gdChord);
19 }
20 
21 void
22 gdImageFilledArc (gdImagePtr im, int cx, int cy, int width, int height, int s, int e, int color, int style)
23 {
24   gdPoint pt[7];
25   gdPoint axis_pt[4];
26 
27   int angle;
28 
29   int have_s = 0;
30   int have_e = 0;
31 
32   int flip_x = 0;
33   int flip_y = 0;
34 
35   int conquer = 0;
36 
37   int i;
38 
39   int a;
40   int b;
41 
42   int x;
43   int y;
44 
45   long s_sin = 0;
46   long s_cos = 0;
47   long e_sin = 0;
48   long e_cos = 0;
49 
50   long w;			/* a * 2 */
51   long h;			/* b * 2 */
52 
53   long x2;			/* x * 2 */
54   long y2;			/* y * 2 */
55   long lx2;			/* x * 2 (line) */
56   long ly2;			/* y * 2 (line) */
57 
58   long ws;			/* (a * 2)^2 */
59   long hs;			/* (b * 2)^2 */
60 
61   long whs;			/* (a * 2)^2 * (b * 2)^2 */
62 
63   long g;			/* decision variable */
64   long lg;			/* decision variable (line) */
65 
66   width = (width & 1) ? (width + 1) : (width);
67   height = (height & 1) ? (height + 1) : (height);
68 
69   a = width / 2;
70   b = height / 2;
71 
72   axis_pt[0].x = a;
73   axis_pt[0].y = 0;
74   axis_pt[1].x = 0;
75   axis_pt[1].y = b;
76   axis_pt[2].x = -a;
77   axis_pt[2].y = 0;
78   axis_pt[3].x = 0;
79   axis_pt[3].y = -b;
80 
81   if (s == e)
82     return;
83 
84   if ((e - s) >= 360)
85     {
86       s = 0;
87       e = 0;
88     }
89 
90   while (s < 0)
91     s += 360;
92   while (s >= 360)
93     s -= 360;
94   while (e < 0)
95     e += 360;
96   while (e >= 360)
97     e -= 360;
98 
99   if (e <= s)
100     e += 360;
101 
102   /* I'm assuming a chord-rule at the moment. Need to add origin to get a
103    * pie-rule, but will need to set chord-rule before recursion...
104    */
105 
106   for (i = 0; i < 4; i++)
107     {
108       if ((s < (i + 1) * 90) && (e > (i + 1) * 90))
109 	{
110 	  gdImageFilledArc (im, cx, cy, width, height, s, (i + 1) * 90, color, gdChord);
111 	  pt[0] = gdArcClosest (width, height, s);
112 	  pt[0].x += cx;
113 	  pt[0].y += cy;
114 	  pt[1].x = cx + axis_pt[(i + 1) & 3].x;
115 	  pt[1].y = cy + axis_pt[(i + 1) & 3].y;
116 	  if (e <= (i + 2) * 90)
117 	    {
118 	      gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, e, color, gdChord);
119 	      pt[2] = gdArcClosest (width, height, e);
120 	      pt[2].x += cx;
121 	      pt[2].y += cy;
122 	      if (style == gdChord)
123 		{
124 		  gdImageFilledPolygon (im, pt, 3, color);
125 		  gdImagePolygon (im, pt, 3, color);
126 		}
127 	      else if (style == gdPie)
128 		{
129 		  pt[3].x = cx;
130 		  pt[3].y = cy;
131 		  gdImageFilledPolygon (im, pt, 4, color);
132 		  gdImagePolygon (im, pt, 4, color);
133 		}
134 	    }
135 	  else
136 	    {
137 	      gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, (i + 2) * 90, color, gdChord);
138 	      pt[2].x = cx + axis_pt[(i + 2) & 3].x;
139 	      pt[2].y = cy + axis_pt[(i + 2) & 3].y;
140 	      if (e <= (i + 3) * 90)
141 		{
142 		  gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, e, color, gdChord);
143 		  pt[3] = gdArcClosest (width, height, e);
144 		  pt[3].x += cx;
145 		  pt[3].y += cy;
146 		  if (style == gdChord)
147 		    {
148 		      gdImageFilledPolygon (im, pt, 4, color);
149 		      gdImagePolygon (im, pt, 4, color);
150 		    }
151 		  else if (style == gdPie)
152 		    {
153 		      pt[4].x = cx;
154 		      pt[4].y = cy;
155 		      gdImageFilledPolygon (im, pt, 5, color);
156 		      gdImagePolygon (im, pt, 5, color);
157 		    }
158 		}
159 	      else
160 		{
161 		  gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, (i + 3) * 90, color, gdChord);
162 		  pt[3].x = cx + axis_pt[(i + 3) & 3].x;
163 		  pt[3].y = cy + axis_pt[(i + 3) & 3].y;
164 		  if (e <= (i + 4) * 90)
165 		    {
166 		      gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, e, color, gdChord);
167 		      pt[4] = gdArcClosest (width, height, e);
168 		      pt[4].x += cx;
169 		      pt[4].y += cy;
170 		      if (style == gdChord)
171 			{
172 			  gdImageFilledPolygon (im, pt, 5, color);
173 			  gdImagePolygon (im, pt, 5, color);
174 			}
175 		      else if (style == gdPie)
176 			{
177 			  pt[5].x = cx;
178 			  pt[5].y = cy;
179 			  gdImageFilledPolygon (im, pt, 6, color);
180 			  gdImagePolygon (im, pt, 6, color);
181 			}
182 		    }
183 		  else
184 		    {
185 		      gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, (i + 4) * 90, color, gdChord);
186 		      pt[4].x = cx + axis_pt[(i + 4) & 3].x;
187 		      pt[4].y = cy + axis_pt[(i + 4) & 3].y;
188 
189 		      gdImageFilledArc (im, cx, cy, width, height, (i + 4) * 90, e, color, gdChord);
190 		      pt[5] = gdArcClosest (width, height, e);
191 		      pt[5].x += cx;
192 		      pt[5].y += cy;
193 		      if (style == gdChord)
194 			{
195 			  gdImageFilledPolygon (im, pt, 6, color);
196 			  gdImagePolygon (im, pt, 6, color);
197 			}
198 		      else if (style == gdPie)
199 			{
200 			  pt[6].x = cx;
201 			  pt[6].y = cy;
202 			  gdImageFilledPolygon (im, pt, 7, color);
203 			  gdImagePolygon (im, pt, 7, color);
204 			}
205 		    }
206 		}
207 	    }
208 	  return;
209 	}
210     }
211 
212   /* At this point we have only arcs that lies within a quadrant -
213    * map this to first quadrant...
214    */
215 
216   if ((s >= 90) && (e <= 180))
217     {
218       angle = s;
219       s = 180 - e;
220       e = 180 - angle;
221       flip_x = 1;
222     }
223   if ((s >= 180) && (e <= 270))
224     {
225       s = s - 180;
226       e = e - 180;
227       flip_x = 1;
228       flip_y = 1;
229     }
230   if ((s >= 270) && (e <= 360))
231     {
232       angle = s;
233       s = 360 - e;
234       e = 360 - angle;
235       flip_y = 1;
236     }
237 
238   if (s == 0)
239     {
240       s_sin = 0;
241       s_cos = (long) ((double) 32768);
242     }
243   else
244     {
245       s_sin = (long) ((double) 32768 * sin ((double) s * M_PI / (double) 180));
246       s_cos = (long) ((double) 32768 * cos ((double) s * M_PI / (double) 180));
247     }
248   if (e == 0)
249     {
250       e_sin = (long) ((double) 32768);
251       e_cos = 0;
252     }
253   else
254     {
255       e_sin = (long) ((double) 32768 * sin ((double) e * M_PI / (double) 180));
256       e_cos = (long) ((double) 32768 * cos ((double) e * M_PI / (double) 180));
257     }
258 
259   w = (long) width;
260   h = (long) height;
261 
262   ws = w * w;
263   hs = h * h;
264 
265   whs = 1;
266   while ((ws > 32768) || (hs > 32768))
267     {
268       ws = (ws + 1) / 2;	/* Unfortunate limitations on integers makes */
269       hs = (hs + 1) / 2;	/* drawing large  ellipses problematic...    */
270       whs *= 2;
271     }
272   while ((ws * hs) > (0x04000000L / whs))
273     {
274       ws = (ws + 1) / 2;
275       hs = (hs + 1) / 2;
276       whs *= 2;
277     }
278   whs *= ws * hs;
279 
280   pt[0].x = w / 2;
281   pt[0].y = 0;
282 
283   pt[2].x = 0;
284   pt[2].y = h / 2;
285 
286   have_s = 0;
287   have_e = 0;
288 
289   if (s == 0)
290     have_s = 1;
291   if (e == 90)
292     have_e = 1;
293 
294   x2 = w;
295   y2 = 0;			/* Starting point is exactly on ellipse */
296 
297   g = x2 - 1;
298   g = g * g * hs + 4 * ws - whs;
299 
300   while ((x2 * hs) > (y2 * ws))	/* Keep |tangent| > 1 */
301     {
302       y2 += 2;
303       g += ws * 4 * (y2 + 1);
304 
305       if (g > 0)		/* Need to drop */
306 	{
307 	  x2 -= 2;
308 	  g -= hs * 4 * x2;
309 	}
310 
311       if ((have_s == 0) && ((s_sin * x2) <= (y2 * s_cos)))
312 	{
313 	  pt[0].x = (int) (x2 / 2);
314 	  pt[0].y = (int) (y2 / 2);
315 	  have_s = 1;
316 	}
317 
318       if ((have_e == 0) && ((e_sin * x2) <= (y2 * e_cos)))
319 	{
320 	  pt[2].x = (int) (x2 / 2);
321 	  pt[2].y = (int) (y2 / 2);
322 	  have_e = 1;
323 	}
324     }
325   pt[1].x = (int) (x2 / 2);
326   pt[1].y = (int) (y2 / 2);
327 
328   x2 = 0;
329   y2 = h;			/* Starting point is exactly on ellipse */
330 
331   g = y2 - 1;
332   g = g * g * ws + 4 * hs - whs;
333 
334   while ((x2 * hs) < (y2 * ws))
335     {
336       x2 += 2;
337       g += hs * 4 * (x2 + 1);
338 
339       if (g > 0)		/* Need to drop */
340 	{
341 	  y2 -= 2;
342 	  g -= ws * 4 * y2;
343 	}
344 
345       if ((have_s == 0) && ((s_sin * x2) >= (y2 * s_cos)))
346 	{
347 	  pt[0].x = (int) (x2 / 2);
348 	  pt[0].y = (int) (y2 / 2);
349 	  have_s = 1;
350 	}
351 
352       if ((have_e == 0) && ((e_sin * x2) >= (y2 * e_cos)))
353 	{
354 	  pt[2].x = (int) (x2 / 2);
355 	  pt[2].y = (int) (y2 / 2);
356 	  have_e = 1;
357 	}
358     }
359 
360   if ((have_s == 0) || (have_e == 0))
361     return;			/* Bizarre case */
362 
363   if (style == gdPie)
364     {
365       pt[3] = pt[0];
366       pt[4] = pt[1];
367       pt[5] = pt[2];
368 
369       pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
370       pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
371       pt[1].x = cx;
372       pt[1].y = cy;
373       pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
374       pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
375       gdImageFilledPolygon (im, pt, 3, color);
376       gdImagePolygon (im, pt, 3, color);
377 
378       pt[0] = pt[3];
379       pt[1] = pt[4];
380       pt[2] = pt[5];
381     }
382 
383   if (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws)))
384     {				/* the points are on different parts of the curve...
385 				 * this is too tricky to try to handle, so divide and conquer:
386 				 */
387       pt[3] = pt[0];
388       pt[4] = pt[1];
389       pt[5] = pt[2];
390 
391       pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
392       pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
393       pt[1].x = cx + (flip_x ? (-pt[1].x) : pt[1].x);
394       pt[1].y = cy + (flip_y ? (-pt[1].y) : pt[1].y);
395       pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
396       pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
397       gdImageFilledPolygon (im, pt, 3, color);
398       gdImagePolygon (im, pt, 3, color);
399 
400       pt[0] = pt[3];
401       pt[2] = pt[4];
402 
403       conquer = 1;
404     }
405 
406   if (conquer || (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) > (e_sin * ws))))
407     {				/* This is the best bit... */
408       /* steep line + ellipse */
409       /* go up & left from pt[0] to pt[2] */
410 
411       x2 = w;
412       y2 = 0;			/* Starting point is exactly on ellipse */
413 
414       g = x2 - 1;
415       g = g * g * hs + 4 * ws - whs;
416 
417       while ((x2 * hs) > (y2 * ws))	/* Keep |tangent| > 1 */
418 	{
419 	  if ((s_sin * x2) <= (y2 * s_cos))
420 	    break;
421 
422 	  y2 += 2;
423 	  g += ws * 4 * (y2 + 1);
424 
425 	  if (g > 0)		/* Need to drop */
426 	    {
427 	      x2 -= 2;
428 	      g -= hs * 4 * x2;
429 	    }
430 	}
431 
432       lx2 = x2;
433       ly2 = y2;
434 
435       lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
436       lg = (lx2 - 1) * (pt[0].y - pt[2].y) - (ly2 + 2) * (pt[0].x - pt[2].x) - lg;
437 
438       while (y2 < (2 * pt[2].y))
439 	{
440 	  y2 += 2;
441 	  g += ws * 4 * (y2 + 1);
442 
443 	  if (g > 0)		/* Need to drop */
444 	    {
445 	      x2 -= 2;
446 	      g -= hs * 4 * x2;
447 	    }
448 
449 	  ly2 += 2;
450 	  lg -= 2 * (pt[0].x - pt[2].x);
451 
452 	  if (lg < 0)		/* Need to drop */
453 	    {
454 	      lx2 -= 2;
455 	      lg -= 2 * (pt[0].y - pt[2].y);
456 	    }
457 
458 	  y = (int) (y2 / 2);
459 	  for (x = (int) (lx2 / 2); x <= (int) (x2 / 2); x++)
460 	    {
461 	      gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
462 			       ((flip_y) ? (cy - y) : (cy + y)), color);
463 	    }
464 	}
465     }
466   if (conquer)
467     {
468       pt[0] = pt[4];
469       pt[2] = pt[5];
470     }
471   if (conquer || (((s_cos * hs) < (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws))))
472     {				/* This is the best bit... */
473       /* gradual line + ellipse */
474       /* go down & right from pt[2] to pt[0] */
475 
476       x2 = 0;
477       y2 = h;			/* Starting point is exactly on ellipse */
478 
479       g = y2 - 1;
480       g = g * g * ws + 4 * hs - whs;
481 
482       while ((x2 * hs) < (y2 * ws))
483 	{
484 	  x2 += 2;
485 	  g += hs * 4 * (x2 + 1);
486 
487 	  if (g > 0)		/* Need to drop */
488 	    {
489 	      y2 -= 2;
490 	      g -= ws * 4 * y2;
491 	    }
492 
493 	  if ((e_sin * x2) >= (y2 * e_cos))
494 	    break;
495 	}
496 
497       lx2 = x2;
498       ly2 = y2;
499 
500       lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
501       lg = (lx2 + 2) * (pt[0].y - pt[2].y) - (ly2 - 1) * (pt[0].x - pt[2].x) - lg;
502 
503       while (x2 < (2 * pt[0].x))
504 	{
505 	  x2 += 2;
506 	  g += hs * 4 * (x2 + 1);
507 
508 	  if (g > 0)		/* Need to drop */
509 	    {
510 	      y2 -= 2;
511 	      g -= ws * 4 * y2;
512 	    }
513 
514 	  lx2 += 2;
515 	  lg += 2 * (pt[0].y - pt[2].y);
516 
517 	  if (lg < 0)		/* Need to drop */
518 	    {
519 	      ly2 -= 2;
520 	      lg += 2 * (pt[0].x - pt[2].x);
521 	    }
522 
523 	  x = (int) (x2 / 2);
524 	  for (y = (int) (ly2 / 2); y <= (int) (y2 / 2); y++)
525 	    {
526 	      gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
527 			       ((flip_y) ? (cy - y) : (cy + y)), color);
528 	    }
529 	}
530     }
531 }
532 
533 static gdPoint
534 gdArcClosest (int width, int height, int angle)
535 {
536   gdPoint pt;
537 
538   int flip_x = 0;
539   int flip_y = 0;
540 
541   long a_sin = 0;
542   long a_cos = 0;
543 
544   long w;			/* a * 2 */
545   long h;			/* b * 2 */
546 
547   long x2;			/* x * 2 */
548   long y2;			/* y * 2 */
549 
550   long ws;			/* (a * 2)^2 */
551   long hs;			/* (b * 2)^2 */
552 
553   long whs;			/* (a * 2)^2 * (b * 2)^2 */
554 
555   long g;			/* decision variable */
556 
557   w = (long) ((width & 1) ? (width + 1) : (width));
558   h = (long) ((height & 1) ? (height + 1) : (height));
559 
560   while (angle < 0)
561     angle += 360;
562   while (angle >= 360)
563     angle -= 360;
564 
565   if (angle == 0)
566     {
567       pt.x = w / 2;
568       pt.y = 0;
569       return (pt);
570     }
571   if (angle == 90)
572     {
573       pt.x = 0;
574       pt.y = h / 2;
575       return (pt);
576     }
577   if (angle == 180)
578     {
579       pt.x = -w / 2;
580       pt.y = 0;
581       return (pt);
582     }
583   if (angle == 270)
584     {
585       pt.x = 0;
586       pt.y = -h / 2;
587       return (pt);
588     }
589 
590   pt.x = 0;
591   pt.y = 0;
592 
593   if ((angle > 90) && (angle < 180))
594     {
595       angle = 180 - angle;
596       flip_x = 1;
597     }
598   if ((angle > 180) && (angle < 270))
599     {
600       angle = angle - 180;
601       flip_x = 1;
602       flip_y = 1;
603     }
604   if ((angle > 270) && (angle < 360))
605     {
606       angle = 360 - angle;
607       flip_y = 1;
608     }
609 
610   a_sin = (long) ((double) 32768 * sin ((double) angle * M_PI / (double) 180));
611   a_cos = (long) ((double) 32768 * cos ((double) angle * M_PI / (double) 180));
612 
613   ws = w * w;
614   hs = h * h;
615 
616   whs = 1;
617   while ((ws > 32768) || (hs > 32768))
618     {
619       ws = (ws + 1) / 2;	/* Unfortunate limitations on integers makes */
620       hs = (hs + 1) / 2;	/* drawing large  ellipses problematic...    */
621       whs *= 2;
622     }
623   while ((ws * hs) > (0x04000000L / whs))
624     {
625       ws = (ws + 1) / 2;
626       hs = (hs + 1) / 2;
627       whs *= 2;
628     }
629   whs *= ws * hs;
630 
631   if ((a_cos * hs) > (a_sin * ws))
632     {
633       x2 = w;
634       y2 = 0;			/* Starting point is exactly on ellipse */
635 
636       g = x2 - 1;
637       g = g * g * hs + 4 * ws - whs;
638 
639       while ((x2 * hs) > (y2 * ws))	/* Keep |tangent| > 1 */
640 	{
641 	  y2 += 2;
642 	  g += ws * 4 * (y2 + 1);
643 
644 	  if (g > 0)		/* Need to drop */
645 	    {
646 	      x2 -= 2;
647 	      g -= hs * 4 * x2;
648 	    }
649 
650 	  if ((a_sin * x2) <= (y2 * a_cos))
651 	    {
652 	      pt.x = (int) (x2 / 2);
653 	      pt.y = (int) (y2 / 2);
654 	      break;
655 	    }
656 	}
657     }
658   else
659     {
660       x2 = 0;
661       y2 = h;			/* Starting point is exactly on ellipse */
662 
663       g = y2 - 1;
664       g = g * g * ws + 4 * hs - whs;
665 
666       while ((x2 * hs) < (y2 * ws))
667 	{
668 	  x2 += 2;
669 	  g += hs * 4 * (x2 + 1);
670 
671 	  if (g > 0)		/* Need to drop */
672 	    {
673 	      y2 -= 2;
674 	      g -= ws * 4 * y2;
675 	    }
676 
677 	  if ((a_sin * x2) >= (y2 * a_cos))
678 	    {
679 	      pt.x = (int) (x2 / 2);
680 	      pt.y = (int) (y2 / 2);
681 	      break;
682 	    }
683 	}
684     }
685 
686   if (flip_x)
687     pt.x = -pt.x;
688   if (flip_y)
689     pt.y = -pt.y;
690 
691   return (pt);
692 }
693 
694 #include "gd.h"
695 #include <string.h>
696 #include <math.h>
697 
698 #define WIDTH	500
699 #define HEIGHT	300
700 
701 int
702 main (int argc, char *argv[])
703 {
704   gdImagePtr im = gdImageCreate (WIDTH, HEIGHT);
705   int white = gdImageColorResolve (im, 0xFF, 0xFF, 0xFF), black = gdImageColorResolve (im, 0, 0, 0),
706     red = gdImageColorResolve (im, 0xFF, 0xA0, 0xA0);
707   FILE *out;
708 
709   /* filled arc - circle */
710   gdImageFilledArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, red, gdPie);
711   gdImageArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, black);
712 
713   /* filled arc - ellipse */
714   gdImageFilledArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, red, gdPie);
715   gdImageArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, black);
716 
717 
718   /* reference lines */
719   gdImageLine (im, 0, HEIGHT / 4, WIDTH, HEIGHT / 4, black);
720   gdImageLine (im, WIDTH / 5, 0, WIDTH / 5, HEIGHT, black);
721   gdImageLine (im, WIDTH / 2, 0, WIDTH / 2, HEIGHT, black);
722   gdImageLine (im, WIDTH / 2, HEIGHT / 4, WIDTH / 2 + 300, HEIGHT / 4 + 300, black);
723   gdImageLine (im, WIDTH / 5, HEIGHT / 4, WIDTH / 5 + 300, HEIGHT / 4 + 300, black);
724 
725   /* TBB: Write img to test/arctest.png */
726   out = fopen ("test/arctest.png", "wb");
727   if (!out)
728     {
729       php_gd_error("Can't create test/arctest.png");
730       exit (1);
731     }
732   gdImagePng (im, out);
733   fclose (out);
734   php_gd_error("Test image written to test/arctest.png");
735   /* Destroy it */
736   gdImageDestroy (im);
737 
738   return 0;
739 }
740 
741 #endif
742