Powered by Pair ImageMagick logo
Image Magick
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Globals | Related Pages

ImageMagick-6.1.1/magick/draw.c

Go to the documentation of this file.
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % DDDD RRRR AAA W W % 00007 % D D R R A A W W % 00008 % D D RRRR AAAAA W W W % 00009 % D D R RN A A WW WW % 00010 % DDDD R R A A W W % 00011 % % 00012 % % 00013 % ImageMagick Image Drawing Methods % 00014 % % 00015 % % 00016 % Software Design % 00017 % John Cristy % 00018 % July 1998 % 00019 % % 00020 % % 00021 % Copyright 1999-2004 ImageMagick Studio LLC, a non-profit organization % 00022 % dedicated to making software imaging solutions freely available. % 00023 % % 00024 % You may not use this file except in compliance with the License. You may % 00025 % obtain a copy of the License at % 00026 % % 00027 % http://www.imagemagick.org/www/Copyright.html % 00028 % % 00029 % Unless required by applicable law or agreed to in writing, software % 00030 % distributed under the License is distributed on an "AS IS" BASIS, % 00031 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00032 % See the License for the specific language governing permissions and % 00033 % limitations under the License. % 00034 % % 00035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00036 % 00037 % Bill Radcliffe of Corbis (www.corbis.com) contributed the polygon 00038 % rendering code based on Paul Heckbert's "Concave Polygon Scan Conversion", 00039 % Graphics Gems, 1990. Leonard Rosenthal and David Harr of Appligent 00040 % (www.appligent.com) contributed the dash pattern, linecap stroking 00041 % algorithm, and minor rendering improvements. 00042 % 00043 */ 00044 00045 /* 00046 Include declarations. 00047 */ 00048 #include "magick/studio.h" 00049 #include "magick/annotate.h" 00050 #include "magick/attribute.h" 00051 #include "magick/blob.h" 00052 #include "magick/color.h" 00053 #include "magick/composite.h" 00054 #include "magick/composite_private.h" 00055 #include "magick/constitute.h" 00056 #include "magick/draw.h" 00057 #include "magick/draw_private.h" 00058 #include "magick/enhance.h" 00059 #include "magick/error.h" 00060 #include "magick/error_private.h" 00061 #include "magick/gem.h" 00062 #include "magick/geometry.h" 00063 #include "magick/log.h" 00064 #include "magick/monitor.h" 00065 #include "magick/option.h" 00066 #include "magick/paint.h" 00067 #include "magick/string_.h" 00068 #include "magick/token.h" 00069 #include "magick/transform.h" 00070 #include "magick/utility.h" 00071 00072 /* 00073 Define declarations. 00074 */ 00075 #define BezierQuantum 200 00076 00077 /* 00078 Typedef declarations. 00079 */ 00080 typedef struct _EdgeInfo 00081 { 00082 SegmentInfo 00083 bounds; 00084 00085 MagickRealType 00086 scanline; 00087 00088 PointInfo 00089 *points; 00090 00091 unsigned long 00092 number_points; 00093 00094 long 00095 direction; 00096 00097 MagickBooleanType 00098 ghostline; 00099 00100 unsigned long 00101 highwater; 00102 } EdgeInfo; 00103 00104 typedef struct _ElementInfo 00105 { 00106 MagickRealType 00107 cx, 00108 cy, 00109 major, 00110 minor, 00111 angle; 00112 } ElementInfo; 00113 00114 typedef struct _PolygonInfo 00115 { 00116 EdgeInfo 00117 *edges; 00118 00119 unsigned long 00120 number_edges; 00121 } PolygonInfo; 00122 00123 typedef enum 00124 { 00125 MoveToCode, 00126 OpenCode, 00127 GhostlineCode, 00128 LineToCode, 00129 EndCode 00130 } PathInfoCode; 00131 00132 typedef struct _PathInfo 00133 { 00134 PointInfo 00135 point; 00136 00137 PathInfoCode 00138 code; 00139 } PathInfo; 00140 00141 /* 00142 Forward declarations. 00143 */ 00144 static PrimitiveInfo 00145 *TraceStrokePolygon(const DrawInfo *,const PrimitiveInfo *); 00146 00147 static MagickBooleanType 00148 DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *); 00149 00150 static unsigned long 00151 TracePath(PrimitiveInfo *,const char *); 00152 00153 static void 00154 #if defined(MagickFuture) 00155 DestroyGradientInfo(GradientInfo *), 00156 #endif 00157 TraceArc(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo), 00158 TraceArcPath(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo, 00159 const double,const MagickBooleanType,const MagickBooleanType), 00160 TraceBezier(PrimitiveInfo *,const unsigned long), 00161 TraceCircle(PrimitiveInfo *,const PointInfo,const PointInfo), 00162 TraceEllipse(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo), 00163 TraceLine(PrimitiveInfo *,const PointInfo,const PointInfo), 00164 TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo), 00165 TraceRoundRectangle(PrimitiveInfo *,const PointInfo,const PointInfo, 00166 PointInfo), 00167 TraceSquareLinecap(PrimitiveInfo *,const unsigned long,const double); 00168 00169 /* 00170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00171 % % 00172 % % 00173 % % 00174 % G e t A f f i n e M a t r i x % 00175 % % 00176 % % 00177 % % 00178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00179 % 00180 % GetAffineMatrixRx() returns an AffineMatrix initialized to the identity 00181 % matrix. 00182 % 00183 % The format of the GetAffineMatrix method is: 00184 % 00185 % void GetAffineMatrix(AffineMatrix *affine_matrix) 00186 % 00187 % A description of each parameter follows: 00188 % 00189 % o affine_matrix: The affine matrix. 00190 % 00191 % 00192 */ 00193 MagickExport void GetAffineMatrix(AffineMatrix *affine_matrix) 00194 { 00195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00196 assert(affine_matrix != (AffineMatrix *) NULL); 00197 (void) ResetMagickMemory(affine_matrix,0,sizeof(*affine_matrix)); 00198 affine_matrix->sx=1.0; 00199 affine_matrix->sy=1.0; 00200 } 00201 00202 /* 00203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00204 % % 00205 % % 00206 % % 00207 % C l o n e D r a w I n f o % 00208 % % 00209 % % 00210 % % 00211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00212 % 00213 % CloneDrawInfo() makes a copy of the given draw info structure. If NULL 00214 % is specified, a new image info structure is created initialized to 00215 % default values. 00216 % 00217 % The format of the CloneDrawInfo method is: 00218 % 00219 % DrawInfo *CloneDrawInfo(const ImageInfo *image_info, 00220 % const DrawInfo *draw_info) 00221 % 00222 % A description of each parameter follows: 00223 % 00224 % o image_info: The image info. 00225 % 00226 % o draw_info: The draw info. 00227 % 00228 % 00229 */ 00230 MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info, 00231 const DrawInfo *draw_info) 00232 { 00233 DrawInfo 00234 *clone_info; 00235 00236 clone_info=(DrawInfo *) AcquireMagickMemory(sizeof(*clone_info)); 00237 if (clone_info == (DrawInfo *) NULL) 00238 ThrowMagickFatalException(ResourceLimitFatalError, 00239 "UnableToAllocateDrawInfo",image_info->filename); 00240 GetDrawInfo(image_info,clone_info); 00241 if (draw_info == (DrawInfo *) NULL) 00242 return(clone_info); 00243 if (clone_info->primitive != (char *) NULL) 00244 (void) CloneString(&clone_info->primitive,draw_info->primitive); 00245 if (draw_info->geometry != (char *) NULL) 00246 (void) CloneString(&clone_info->geometry,draw_info->geometry); 00247 clone_info->viewbox=draw_info->viewbox; 00248 clone_info->affine=draw_info->affine; 00249 clone_info->gravity=draw_info->gravity; 00250 clone_info->fill=draw_info->fill; 00251 clone_info->stroke=draw_info->stroke; 00252 clone_info->stroke_width=draw_info->stroke_width; 00253 if (draw_info->fill_pattern != (Image *) NULL) 00254 clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue, 00255 &draw_info->fill_pattern->exception); 00256 else 00257 if (draw_info->tile != (Image *) NULL) 00258 clone_info->fill_pattern=CloneImage(draw_info->tile,0,0,MagickTrue, 00259 &draw_info->tile->exception); 00260 clone_info->tile=(Image *) NULL; /* tile is deprecated */ 00261 if (draw_info->stroke_pattern != (Image *) NULL) 00262 clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0, 00263 MagickTrue,&draw_info->stroke_pattern->exception); 00264 clone_info->stroke_antialias=draw_info->stroke_antialias; 00265 clone_info->text_antialias=draw_info->text_antialias; 00266 clone_info->fill_rule=draw_info->fill_rule; 00267 clone_info->linecap=draw_info->linecap; 00268 clone_info->linejoin=draw_info->linejoin; 00269 clone_info->miterlimit=draw_info->miterlimit; 00270 clone_info->dash_offset=draw_info->dash_offset; 00271 clone_info->decorate=draw_info->decorate; 00272 clone_info->compose=draw_info->compose; 00273 if (draw_info->text != (char *) NULL) 00274 (void) CloneString(&clone_info->text,draw_info->text); 00275 if (draw_info->font != (char *) NULL) 00276 (void) CloneString(&clone_info->font,draw_info->font); 00277 if (draw_info->metrics != (char *) NULL) 00278 (void) CloneString(&clone_info->metrics,draw_info->metrics); 00279 if (draw_info->family != (char *) NULL) 00280 (void) CloneString(&clone_info->family,draw_info->family); 00281 clone_info->style=draw_info->style; 00282 clone_info->stretch=draw_info->stretch; 00283 clone_info->weight=draw_info->weight; 00284 if (draw_info->encoding != (char *) NULL) 00285 (void) CloneString(&clone_info->encoding,draw_info->encoding); 00286 clone_info->pointsize=draw_info->pointsize; 00287 if (draw_info->density != (char *) NULL) 00288 (void) CloneString(&clone_info->density,draw_info->density); 00289 clone_info->align=draw_info->align; 00290 clone_info->undercolor=draw_info->undercolor; 00291 clone_info->border_color=draw_info->border_color; 00292 if (draw_info->server_name != (char *) NULL) 00293 (void) CloneString(&clone_info->server_name,draw_info->server_name); 00294 if (draw_info->dash_pattern != (double *) NULL) 00295 { 00296 register long 00297 x; 00298 00299 for (x=0; draw_info->dash_pattern[x] != 0.0; x++); 00300 clone_info->dash_pattern=(double *) 00301 AcquireMagickMemory((size_t) (x+1)*sizeof(*clone_info->dash_pattern)); 00302 if (clone_info->dash_pattern == (double *) NULL) 00303 ThrowMagickFatalException(ResourceLimitFatalError, 00304 "UnableToAllocateDashPattern",image_info->filename); 00305 (void) CopyMagickMemory(clone_info->dash_pattern,draw_info->dash_pattern, 00306 (size_t) (x+1)*sizeof(*clone_info->dash_pattern)); 00307 } 00308 if (draw_info->clip_path != (char *) NULL) 00309 (void) CloneString(&clone_info->clip_path,draw_info->clip_path); 00310 clone_info->bounds=draw_info->bounds; 00311 clone_info->clip_units=draw_info->clip_units; 00312 clone_info->render=draw_info->render; 00313 clone_info->opacity=draw_info->opacity; 00314 clone_info->element_reference=draw_info->element_reference; 00315 clone_info->debug=IsEventLogging(); 00316 return(clone_info); 00317 } 00318 00319 /* 00320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00321 % % 00322 % % 00323 % % 00324 + C o n v e r t P a t h T o P o l y g o n % 00325 % % 00326 % % 00327 % % 00328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00329 % 00330 % ConvertPathToPolygon() converts a path to the more efficient sorted 00331 % rendering form. 00332 % 00333 % The format of the ConvertPathToPolygon method is: 00334 % 00335 % PolygonInfo *ConvertPathToPolygon(const DrawInfo *draw_info, 00336 % const PathInfo *path_info) 00337 % 00338 % A description of each parameter follows: 00339 % 00340 % o Method ConvertPathToPolygon returns the path in a more efficient sorted 00341 % rendering form of type PolygonInfo. 00342 % 00343 % o draw_info: Specifies a pointer to an DrawInfo structure. 00344 % 00345 % o path_info: Specifies a pointer to an PathInfo structure. 00346 % 00347 % 00348 */ 00349 00350 #if defined(__cplusplus) || defined(c_plusplus) 00351 extern "C" { 00352 #endif 00353 00354 static int CompareEdges(const void *x,const void *y) 00355 { 00356 register const EdgeInfo 00357 *p, 00358 *q; 00359 00360 /* 00361 Compare two edges. 00362 */ 00363 p=(EdgeInfo *) x; 00364 q=(EdgeInfo *) y; 00365 if ((p->points[0].y-MagickEpsilon) > q->points[0].y) 00366 return(1); 00367 if ((p->points[0].y+MagickEpsilon) < q->points[0].y) 00368 return(-1); 00369 if ((p->points[0].x-MagickEpsilon) > q->points[0].x) 00370 return(1); 00371 if ((p->points[0].x+MagickEpsilon) < q->points[0].x) 00372 return(-1); 00373 if (((p->points[1].x-p->points[0].x)*(q->points[1].y-q->points[0].y)- 00374 (p->points[1].y-p->points[0].y)*(q->points[1].x-q->points[0].x)) > 0.0) 00375 return(1); 00376 return(-1); 00377 } 00378 00379 #if defined(__cplusplus) || defined(c_plusplus) 00380 } 00381 #endif 00382 00383 static void LogPolygonInfo(const PolygonInfo *polygon_info) 00384 { 00385 register EdgeInfo 00386 *p; 00387 00388 register long 00389 i, 00390 j; 00391 00392 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin active-edge"); 00393 p=polygon_info->edges; 00394 for (i=0; i < (long) polygon_info->number_edges; i++) 00395 { 00396 (void) LogMagickEvent(DrawEvent,GetMagickModule()," edge %lu:",i); 00397 (void) LogMagickEvent(DrawEvent,GetMagickModule()," direction: %s", 00398 p->direction != MagickFalse ? "down" : "up"); 00399 (void) LogMagickEvent(DrawEvent,GetMagickModule()," ghostline: %s", 00400 p->ghostline != MagickFalse ? "transparent" : "opaque"); 00401 (void) LogMagickEvent(DrawEvent,GetMagickModule(), 00402 " bounds: %g,%g - %g,%g",p->bounds.x1,p->bounds.y1,p->bounds.x2, 00403 p->bounds.y2); 00404 for (j=0; j < (long) p->number_points; j++) 00405 (void) LogMagickEvent(DrawEvent,GetMagickModule()," %g,%g", 00406 p->points[j].x,p->points[j].y); 00407 p++; 00408 } 00409 (void) LogMagickEvent(DrawEvent,GetMagickModule()," end active-edge"); 00410 } 00411 00412 static void ReversePoints(PointInfo *points,const unsigned long number_points) 00413 { 00414 PointInfo 00415 point; 00416 00417 register long 00418 i; 00419 00420 for (i=0; i < (long) (number_points >> 1); i++) 00421 { 00422 point=points[i]; 00423 points[i]=points[number_points-(i+1)]; 00424 points[number_points-(i+1)]=point; 00425 } 00426 } 00427 00428 static PolygonInfo *ConvertPathToPolygon(const DrawInfo *draw_info, 00429 const PathInfo *path_info) 00430 { 00431 long 00432 direction, 00433 next_direction; 00434 00435 PointInfo 00436 point, 00437 *points; 00438 00439 PolygonInfo 00440 *polygon_info; 00441 00442 SegmentInfo 00443 bounds; 00444 00445 register long 00446 i, 00447 n; 00448 00449 MagickBooleanType 00450 ghostline; 00451 00452 unsigned long 00453 edge, 00454 number_edges, 00455 number_points; 00456 00457 /* 00458 Convert a path to the more efficient sorted rendering form. 00459 */ 00460 polygon_info=(PolygonInfo *) AcquireMagickMemory(sizeof(*polygon_info)); 00461 if (polygon_info == (PolygonInfo *) NULL) 00462 return((PolygonInfo *) NULL); 00463 number_edges=16; 00464 polygon_info->edges=(EdgeInfo *) 00465 AcquireMagickMemory((size_t) number_edges*sizeof(*polygon_info->edges)); 00466 if (polygon_info->edges == (EdgeInfo *) NULL) 00467 return((PolygonInfo *) NULL); 00468 direction=0; 00469 edge=0; 00470 ghostline=MagickFalse; 00471 n=0; 00472 number_points=0; 00473 points=(PointInfo *) NULL; 00474 (void) ResetMagickMemory(&point,0,sizeof(point)); 00475 (void) ResetMagickMemory(&bounds,0,sizeof(bounds)); 00476 for (i=0; path_info[i].code != EndCode; i++) 00477 { 00478 if ((path_info[i].code == MoveToCode) || (path_info[i].code == OpenCode) || 00479 (path_info[i].code == GhostlineCode)) 00480 { 00481 /* 00482 Move to. 00483 */ 00484 if ((points != (PointInfo *) NULL) && (n >= 2)) 00485 { 00486 if (edge == number_edges) 00487 { 00488 number_edges<<=1; 00489 polygon_info->edges=(EdgeInfo *) ResizeMagickMemory( 00490 polygon_info->edges,(size_t) number_edges* 00491 sizeof(*polygon_info->edges)); 00492 if (polygon_info->edges == (EdgeInfo *) NULL) 00493 return((PolygonInfo *) NULL); 00494 } 00495 polygon_info->edges[edge].number_points=(unsigned long) n; 00496 polygon_info->edges[edge].scanline=(-1.0); 00497 polygon_info->edges[edge].highwater=0; 00498 polygon_info->edges[edge].ghostline=ghostline; 00499 polygon_info->edges[edge].direction=(long) (direction > 0); 00500 if (direction < 0) 00501 ReversePoints(points,(unsigned long) n); 00502 polygon_info->edges[edge].points=points; 00503 polygon_info->edges[edge].bounds=bounds; 00504 polygon_info->edges[edge].bounds.y1=points[0].y; 00505 polygon_info->edges[edge].bounds.y2=points[n-1].y; 00506 points=(PointInfo *) NULL; 00507 ghostline=MagickFalse; 00508 edge++; 00509 } 00510 if (points == (PointInfo *) NULL) 00511 { 00512 number_points=16; 00513 points=(PointInfo *) 00514 AcquireMagickMemory((size_t) number_points*sizeof(*points)); 00515 if (points == (PointInfo *) NULL) 00516 return((PolygonInfo *) NULL); 00517 } 00518 ghostline=(MagickBooleanType) (path_info[i].code == GhostlineCode); 00519 point=path_info[i].point; 00520 points[0]=point; 00521 bounds.x1=point.x; 00522 bounds.x2=point.x; 00523 direction=0; 00524 n=1; 00525 continue; 00526 } 00527 /* 00528 Line to. 00529 */ 00530 next_direction=((path_info[i].point.y > point.y) || 00531 ((path_info[i].point.y == point.y) && 00532 (path_info[i].point.x > point.x))) ? 1 : -1; 00533 if ((direction != 0) && (direction != next_direction)) 00534 { 00535 /* 00536 New edge. 00537 */ 00538 point=points[n-1]; 00539 if (edge == number_edges) 00540 { 00541 number_edges<<=1; 00542 polygon_info->edges=(EdgeInfo *) ResizeMagickMemory( 00543 polygon_info->edges,(size_t) number_edges* 00544 sizeof(*polygon_info->edges)); 00545 if (polygon_info->edges == (EdgeInfo *) NULL) 00546 return((PolygonInfo *) NULL); 00547 } 00548 polygon_info->edges[edge].number_points=(unsigned long) n; 00549 polygon_info->edges[edge].scanline=(-1.0); 00550 polygon_info->edges[edge].highwater=0; 00551 polygon_info->edges[edge].ghostline=ghostline; 00552 polygon_info->edges[edge].direction=(long) (direction > 0); 00553 if (direction < 0) 00554 ReversePoints(points,(unsigned long) n); 00555 polygon_info->edges[edge].points=points; 00556 polygon_info->edges[edge].bounds=bounds; 00557 polygon_info->edges[edge].bounds.y1=points[0].y; 00558 polygon_info->edges[edge].bounds.y2=points[n-1].y; 00559 number_points=16; 00560 points=(PointInfo *) 00561 AcquireMagickMemory((size_t) number_points*sizeof(*points)); 00562 if (points == (PointInfo *) NULL) 00563 return((PolygonInfo *) NULL); 00564 n=1; 00565 ghostline=MagickFalse; 00566 points[0]=point; 00567 bounds.x1=point.x; 00568 bounds.x2=point.x; 00569 edge++; 00570 } 00571 direction=next_direction; 00572 if (points == (PointInfo *) NULL) 00573 continue; 00574 if (n == (long) number_points) 00575 { 00576 number_points<<=1; 00577 points=(PointInfo *) 00578 ResizeMagickMemory(points,(size_t) number_points*sizeof(*points)); 00579 if (points == (PointInfo *) NULL) 00580 return((PolygonInfo *) NULL); 00581 } 00582 point=path_info[i].point; 00583 points[n]=point; 00584 if (point.x < bounds.x1) 00585 bounds.x1=point.x; 00586 if (point.x > bounds.x2) 00587 bounds.x2=point.x; 00588 n++; 00589 } 00590 if (points != (PointInfo *) NULL) 00591 { 00592 if (n < 2) 00593 points=(PointInfo *) RelinquishMagickMemory(points); 00594 else 00595 { 00596 if (edge == number_edges) 00597 { 00598 number_edges<<=1; 00599 polygon_info->edges=(EdgeInfo *) ResizeMagickMemory( 00600 polygon_info->edges,(size_t) number_edges* 00601 sizeof(*polygon_info->edges)); 00602 if (polygon_info->edges == (EdgeInfo *) NULL) 00603 return((PolygonInfo *) NULL); 00604 } 00605 polygon_info->edges[edge].number_points=(unsigned long) n; 00606 polygon_info->edges[edge].scanline=(-1.0); 00607 polygon_info->edges[edge].highwater=0; 00608 polygon_info->edges[edge].ghostline=ghostline; 00609 polygon_info->edges[edge].direction=(long) (direction > 0); 00610 if (direction < 0) 00611 ReversePoints(points,(unsigned long) n); 00612 polygon_info->edges[edge].points=points; 00613 polygon_info->edges[edge].bounds=bounds; 00614 polygon_info->edges[edge].bounds.y1=points[0].y; 00615 polygon_info->edges[edge].bounds.y2=points[n-1].y; 00616 ghostline=MagickFalse; 00617 edge++; 00618 } 00619 } 00620 polygon_info->number_edges=edge; 00621 qsort(polygon_info->edges,(size_t) polygon_info->number_edges, 00622 sizeof(*polygon_info->edges),CompareEdges); 00623 if (IsEventLogging() != MagickFalse) 00624 LogPolygonInfo(polygon_info); 00625 return(polygon_info); 00626 } 00627 00628 /* 00629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00630 % % 00631 % % 00632 % % 00633 + C o n v e r t P r i m i t i v e T o P a t h % 00634 % % 00635 % % 00636 % % 00637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00638 % 00639 % ConvertPrimitiveToPath() converts a PrimitiveInfo structure into a vector 00640 % path structure. 00641 % 00642 % The format of the ConvertPrimitiveToPath method is: 00643 % 00644 % PathInfo *ConvertPrimitiveToPath(const DrawInfo *draw_info, 00645 % const PrimitiveInfo *primitive_info) 00646 % 00647 % A description of each parameter follows: 00648 % 00649 % o Method ConvertPrimitiveToPath returns a vector path structure of type 00650 % PathInfo. 00651 % 00652 % o draw_info: a structure of type DrawInfo. 00653 % 00654 % o primitive_info: Specifies a pointer to an PrimitiveInfo structure. 00655 % 00656 % 00657 */ 00658 00659 static void LogPathInfo(const PathInfo *path_info) 00660 { 00661 register const PathInfo 00662 *p; 00663 00664 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin vector-path"); 00665 for (p=path_info; p->code != EndCode; p++) 00666 (void) LogMagickEvent(DrawEvent,GetMagickModule(), 00667 " %g,%g %s",p->point.x,p->point.y,p->code == GhostlineCode ? 00668 "moveto ghostline" : p->code == OpenCode ? "moveto open" : 00669 p->code == MoveToCode ? "moveto" : p->code == LineToCode ? "lineto" : 00670 "?"); 00671 (void) LogMagickEvent(DrawEvent,GetMagickModule()," end vector-path"); 00672 } 00673 00674 static PathInfo *ConvertPrimitiveToPath(const DrawInfo *draw_info, 00675 const PrimitiveInfo *primitive_info) 00676 { 00677 long 00678 coordinates, 00679 start; 00680 00681 PathInfo 00682 *path_info; 00683 00684 PathInfoCode 00685 code; 00686 00687 PointInfo 00688 p, 00689 q; 00690 00691 register long 00692 i, 00693 n; 00694 00695 /* 00696 Converts a PrimitiveInfo structure into a vector path structure. 00697 */ 00698 switch (primitive_info->primitive) 00699 { 00700 case PointPrimitive: 00701 case ColorPrimitive: 00702 case MattePrimitive: 00703 case TextPrimitive: 00704 case ImagePrimitive: 00705 return((PathInfo *) NULL); 00706 default: 00707 break; 00708 } 00709 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++); 00710 path_info=(PathInfo *) 00711 AcquireMagickMemory((size_t) (2*i+3)*sizeof(*path_info)); 00712 if (path_info == (PathInfo *) NULL) 00713 return((PathInfo *) NULL); 00714 coordinates=0; 00715 n=0; 00716 q.x=(-1); 00717 q.y=(-1); 00718 start=0; 00719 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) 00720 { 00721 code=LineToCode; 00722 if (coordinates <= 0) 00723 { 00724 coordinates=(long) primitive_info[i].coordinates; 00725 p=primitive_info[i].point; 00726 start=n; 00727 code=MoveToCode; 00728 } 00729 coordinates--; 00730 /* 00731 Eliminate duplicate points. 00732 */ 00733 if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) > MagickEpsilon) || 00734 (fabs(q.y-primitive_info[i].point.y) > MagickEpsilon)) 00735 { 00736 path_info[n].code=code; 00737 path_info[n].point=primitive_info[i].point; 00738 q=primitive_info[i].point; 00739 n++; 00740 } 00741 if (coordinates > 0) 00742 continue; 00743 if ((fabs(p.x-primitive_info[i].point.x) <= MagickEpsilon) && 00744 (fabs(p.y-primitive_info[i].point.y) <= MagickEpsilon)) 00745 continue; 00746 /* 00747 Mark the p point as open if it does not match the q. 00748 */ 00749 path_info[start].code=OpenCode; 00750 path_info[n].code=GhostlineCode; 00751 path_info[n].point=primitive_info[i].point; 00752 n++; 00753 path_info[n].code=LineToCode; 00754 path_info[n].point=p; 00755 n++; 00756 } 00757 path_info[n].code=EndCode; 00758 path_info[n].point.x=0.0; 00759 path_info[n].point.y=0.0; 00760 if (IsEventLogging() != MagickFalse) 00761 LogPathInfo(path_info); 00762 return(path_info); 00763 } 00764 00765 /* 00766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00767 % % 00768 % % 00769 % % 00770 % D e s t r o y D r a w I n f o % 00771 % % 00772 % % 00773 % % 00774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00775 % 00776 % DestroyDrawInfo() deallocates memory associated with an DrawInfo 00777 % structure. 00778 % 00779 % The format of the DestroyDrawInfo method is: 00780 % 00781 % DrawInfo *DestroyDrawInfo(DrawInfo *draw_info) 00782 % 00783 % A description of each parameter follows: 00784 % 00785 % o draw_info: The draw info. 00786 % 00787 % 00788 */ 00789 MagickExport DrawInfo *DestroyDrawInfo(DrawInfo *draw_info) 00790 { 00791 if (draw_info->debug != MagickFalse) 00792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00793 assert(draw_info != (DrawInfo *) NULL); 00794 assert(draw_info->signature == MagickSignature); 00795 if (draw_info->primitive != (char *) NULL) 00796 draw_info->primitive=(char *) RelinquishMagickMemory(draw_info->primitive); 00797 if (draw_info->text != (char *) NULL) 00798 draw_info->text=(char *) RelinquishMagickMemory(draw_info->text); 00799 if (draw_info->geometry != (char *) NULL) 00800 draw_info->geometry=(char *) RelinquishMagickMemory(draw_info->geometry); 00801 if (draw_info->tile != (Image *) NULL) 00802 draw_info->tile=DestroyImage(draw_info->tile); 00803 if (draw_info->fill_pattern != (Image *) NULL) 00804 draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern); 00805 if (draw_info->stroke_pattern != (Image *) NULL) 00806 draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern); 00807 if (draw_info->font != (char *) NULL) 00808 draw_info->font=(char *) RelinquishMagickMemory(draw_info->font); 00809 if (draw_info->metrics != (char *) NULL) 00810 draw_info->metrics=(char *) RelinquishMagickMemory(draw_info->metrics); 00811 if (draw_info->family != (char *) NULL) 00812 draw_info->family=(char *) RelinquishMagickMemory(draw_info->family); 00813 if (draw_info->encoding != (char *) NULL) 00814 draw_info->encoding=(char *) RelinquishMagickMemory(draw_info->encoding); 00815 if (draw_info->density != (char *) NULL) 00816 draw_info->density=(char *) RelinquishMagickMemory(draw_info->density); 00817 if (draw_info->server_name != (char *) NULL) 00818 draw_info->server_name=(char *) 00819 RelinquishMagickMemory(draw_info->server_name); 00820 if (draw_info->dash_pattern != (double *) NULL) 00821 draw_info->dash_pattern=(double *) 00822 RelinquishMagickMemory(draw_info->dash_pattern); 00823 if (draw_info->clip_path != (char *) NULL) 00824 draw_info->clip_path=(char *) RelinquishMagickMemory(draw_info->clip_path); 00825 draw_info=(DrawInfo *) RelinquishMagickMemory(draw_info); 00826 return(draw_info); 00827 } 00828 00829 /* 00830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00831 % % 00832 % % 00833 % % 00834 + D e s t r o y E d g e % 00835 % % 00836 % % 00837 % % 00838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00839 % 00840 % DestroyEdge() destroys the specified polygon edge. 00841 % 00842 % The format of the DestroyEdge method is: 00843 % 00844 % long DestroyEdge(PolygonInfo *polygon_info,const int edge) 00845 % 00846 % A description of each parameter follows: 00847 % 00848 % o polygon_info: Specifies a pointer to an PolygonInfo structure. 00849 % 00850 % o edge: the polygon edge number to destroy. 00851 % 00852 % 00853 */ 00854 static unsigned long DestroyEdge(PolygonInfo *polygon_info, 00855 const unsigned long edge) 00856 { 00857 assert(edge < polygon_info->number_edges); 00858 polygon_info->edges[edge].points=(PointInfo *) 00859 RelinquishMagickMemory(polygon_info->edges[edge].points); 00860 polygon_info->number_edges--; 00861 if (edge < polygon_info->number_edges) 00862 (void) CopyMagickMemory(polygon_info->edges+edge,polygon_info->edges+edge+1, 00863 (size_t) (polygon_info->number_edges-edge)*sizeof(*polygon_info->edges)); 00864 return(polygon_info->number_edges); 00865 } 00866 00867 #if defined(MagickFuture) 00868 /* 00869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00870 % % 00871 % % 00872 % % 00873 + D e s t r o y G r a d i e n t I n f o % 00874 % % 00875 % % 00876 % % 00877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00878 % 00879 % DestroyGradientInfo() deallocates memory associated with the GradientInfo 00880 % list. 00881 % 00882 % The format of the DestroyGradientInfo method is: 00883 % 00884 % DestroyGradientInfo(GradientInfo *gradient_info) 00885 % 00886 % A description of each parameter follows: 00887 % 00888 % o gradient_info: The gradient info. 00889 % 00890 % 00891 */ 00892 static void DestroyGradientInfo(GradientInfo *gradient_info) 00893 { 00894 register GradientInfo 00895 *p; 00896 00897 if (gradient_info->debug != MagickFalse) 00898 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00899 if (gradient_info == (GradientInfo *) NULL) 00900 return; 00901 assert(gradient_info->signature == MagickSignature); 00902 for (p=gradient_info; p->previous != (GradientInfo *) NULL; p=p->previous); 00903 for (gradient_info=p; p != (GradientInfo *) NULL; gradient_info=p) 00904 { 00905 p=p->next; 00906 gradient_info=(GradientInfo *) RelinquishMagickMemory(gradient_info); 00907 } 00908 } 00909 #endif 00910 00911 /* 00912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00913 % % 00914 % % 00915 % % 00916 + D e s t r o y P o l y g o n I n f o % 00917 % % 00918 % % 00919 % % 00920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00921 % 00922 % DestroyPolygonInfo() destroys the PolygonInfo data structure. 00923 % 00924 % The format of the DestroyPolygonInfo method is: 00925 % 00926 % void DestroyPolygonInfo(PolygonInfo *polygon_info) 00927 % 00928 % A description of each parameter follows: 00929 % 00930 % o polygon_info: Specifies a pointer to an PolygonInfo structure. 00931 % 00932 % 00933 */ 00934 static void DestroyPolygonInfo(PolygonInfo *polygon_info) 00935 { 00936 register long 00937 i; 00938 00939 for (i=0; i < (long) polygon_info->number_edges; i++) 00940 polygon_info->edges[i].points=(PointInfo *) 00941 RelinquishMagickMemory(polygon_info->edges[i].points); 00942 polygon_info->edges=(EdgeInfo *) RelinquishMagickMemory(polygon_info->edges); 00943 polygon_info=(PolygonInfo *) RelinquishMagickMemory(polygon_info); 00944 } 00945 00946 /* 00947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00948 % % 00949 % % 00950 % D r a w A f f i n e I m a g e % 00951 % % 00952 % % 00953 % % 00954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00955 % 00956 % DrawAffineImage() composites the source over the destination image as 00957 % dictated by the affine transform. 00958 % 00959 % The format of the DrawAffineImage method is: 00960 % 00961 % MagickBooleanType DrawAffineImage(Image *image,const Image *composite, 00962 % const AffineMatrix *affine) 00963 % 00964 % A description of each parameter follows: 00965 % 00966 % o image: The image. 00967 % 00968 % o image: The composite image. 00969 % 00970 % o affine: The affine transform. 00971 % 00972 % 00973 */ 00974 00975 static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine, 00976 const long y,const SegmentInfo *edge) 00977 { 00978 MagickRealType 00979 intercept, 00980 z; 00981 00982 register long 00983 x; 00984 00985 SegmentInfo 00986 inverse_edge; 00987 00988 /* 00989 Determine left and right edges. 00990 */ 00991 inverse_edge.x1=edge->x1; 00992 inverse_edge.x2=edge->x2; 00993 z=affine->ry*(y+0.5)+affine->tx; 00994 if (affine->sx > MagickEpsilon) 00995 { 00996 intercept=(-z/affine->sx); 00997 x=(long) (intercept+MagickEpsilon+0.5); 00998 if ((MagickRealType) x > inverse_edge.x1) 00999 inverse_edge.x1=(MagickRealType) x; 01000 intercept=(-z+(MagickRealType) image->columns)/affine->sx; 01001 x=(long) (intercept-MagickEpsilon+0.5); 01002 if ((MagickRealType) x < inverse_edge.x2) 01003 inverse_edge.x2=(MagickRealType) x; 01004 } 01005 else 01006 if (affine->sx < -MagickEpsilon) 01007 { 01008 intercept=(-z+(MagickRealType) image->columns)/affine->sx; 01009 x=(long) (intercept+MagickEpsilon+0.5); 01010 if ((MagickRealType) x > inverse_edge.x1) 01011 inverse_edge.x1=(MagickRealType) x; 01012 intercept=(-z/affine->sx); 01013 x=(long) (intercept-MagickEpsilon+0.5); 01014 if ((MagickRealType) x < inverse_edge.x2) 01015 inverse_edge.x2=(MagickRealType) x; 01016 } 01017 else 01018 if ((z < 0.0) || (z >= (MagickRealType) image->columns)) 01019 { 01020 inverse_edge.x2=edge->x1; 01021 return(inverse_edge); 01022 } 01023 /* 01024 Determine top and bottom edges. 01025 */ 01026 z=affine->sy*(y+0.5)+affine->ty; 01027 if (affine->rx > MagickEpsilon) 01028 { 01029 intercept=(-z /affine->rx); 01030 x=(long) (intercept+MagickEpsilon+0.5); 01031 if ((MagickRealType) x > inverse_edge.x1) 01032 inverse_edge.x1=(MagickRealType) x; 01033 intercept=(-z+(MagickRealType) image->rows)/affine->rx; 01034 x=(long) (intercept-MagickEpsilon+0.5); 01035 if ((MagickRealType) x < inverse_edge.x2) 01036 inverse_edge.x2=(MagickRealType) x; 01037 } 01038 else 01039 if (affine->rx < -MagickEpsilon) 01040 { 01041 intercept=(-z+(MagickRealType) image->rows)/affine->rx; 01042 x=(long) (intercept+MagickEpsilon+0.5); 01043 if ((MagickRealType) x > inverse_edge.x1) 01044 inverse_edge.x1=(MagickRealType) x; 01045 intercept=(-z/affine->rx); 01046 x=(long) (intercept-MagickEpsilon+0.5); 01047 if ((MagickRealType) x < inverse_edge.x2) 01048 inverse_edge.x2=(MagickRealType) x; 01049 } 01050 else 01051 if ((z < 0.0) || (z >= (MagickRealType) image->rows)) 01052 { 01053 inverse_edge.x2=edge->x1; 01054 return(inverse_edge); 01055 } 01056 return(inverse_edge); 01057 } 01058 01059 static AffineMatrix InverseAffineMatrix(const AffineMatrix *affine) 01060 { 01061 AffineMatrix 01062 inverse_affine; 01063 01064 MagickRealType 01065 determinant; 01066 01067 determinant=1.0/(affine->sx*affine->sy-affine->rx*affine->ry); 01068 inverse_affine.sx=determinant*affine->sy; 01069 inverse_affine.rx=determinant*(-affine->rx); 01070 inverse_affine.ry=determinant*(-affine->ry); 01071 inverse_affine.sy=determinant*affine->sx; 01072 inverse_affine.tx= 01073 (-affine->tx)*inverse_affine.sx-affine->ty*inverse_affine.ry; 01074 inverse_affine.ty= 01075 (-affine->tx)*inverse_affine.rx-affine->ty*inverse_affine.sy; 01076 return(inverse_affine); 01077 } 01078 01079 MagickExport MagickBooleanType DrawAffineImage(Image *image, 01080 const Image *composite,const AffineMatrix *affine) 01081 { 01082 AffineMatrix 01083 inverse_affine; 01084 01085 long 01086 start, 01087 stop, 01088 y; 01089 01090 PixelPacket 01091 pixel; 01092 01093 PointInfo 01094 extent[4], 01095 min, 01096 max, 01097 point; 01098 01099 register long 01100 i, 01101 x; 01102 01103 register PixelPacket 01104 *q; 01105 01106 SegmentInfo 01107 edge, 01108 inverse_edge; 01109 01110 /* 01111 Determine bounding box. 01112 */ 01113 assert(image != (Image *) NULL); 01114 assert(image->signature == MagickSignature); 01115 if (image->debug != MagickFalse) 01116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 01117 assert(composite != (const Image *) NULL); 01118 assert(composite->signature == MagickSignature); 01119 assert(affine != (AffineMatrix *) NULL); 01120 extent[0].x=0; 01121 extent[0].y=0; 01122 extent[1].x=(MagickRealType) composite->columns; 01123 extent[1].y=0; 01124 extent[2].x=(MagickRealType) composite->columns; 01125 extent[2].y=(MagickRealType) composite->rows; 01126 extent[3].x=0; 01127 extent[3].y=(MagickRealType) composite->rows; 01128 for (i=0; i < 4; i++) 01129 { 01130 x=(long) extent[i].x; 01131 y=(long) extent[i].y; 01132 extent[i].x=(MagickRealType) (x*affine->sx+y*affine->ry+affine->tx); 01133 extent[i].y=(MagickRealType) (x*affine->rx+y*affine->sy+affine->ty); 01134 } 01135 min=extent[0]; 01136 max=extent[0]; 01137 for (i=1; i < 4; i++) 01138 { 01139 if (min.x > extent[i].x) 01140 min.x=extent[i].x; 01141 if (min.y > extent[i].y) 01142 min.y=extent[i].y; 01143 if (max.x < extent[i].x) 01144 max.x=extent[i].x; 01145 if (max.y < extent[i].y) 01146 max.y=extent[i].y; 01147 } 01148 /* 01149 Affine transform image. 01150 */ 01151 image->storage_class=DirectClass; 01152 edge.x1=min.x; 01153 edge.y1=min.y; 01154 edge.x2=max.x; 01155 edge.y2=max.y; 01156 inverse_affine=InverseAffineMatrix(affine); 01157 if (edge.y1 < 0) 01158 edge.y1=0.0; 01159 if (edge.y2 >= (MagickRealType) image->rows) 01160 edge.y2=(MagickRealType) image->rows-1; 01161 for (y=(long) (edge.y1+0.5); y <= (long) (edge.y2+0.5); y++) 01162 { 01163 inverse_edge=AffineEdge(composite,&inverse_affine,y,&edge); 01164 if (inverse_edge.x2 < inverse_edge.x1) 01165 continue; 01166 if (inverse_edge.x1 < 0) 01167 inverse_edge.x1=0.0; 01168 if (inverse_edge.x2 >= (MagickRealType) image->columns) 01169 inverse_edge.x2=(MagickRealType) image->columns-1; 01170 start=(long) (inverse_edge.x1+0.5); 01171 stop=(long) (inverse_edge.x2+0.5); 01172 x=start; 01173 q=GetImagePixels(image,x,y,(unsigned long) (stop-x+1),1); 01174 if (q == (PixelPacket *) NULL) 01175 break; 01176 for ( ; x <= stop; x++) 01177 { 01178 point.x=(MagickRealType) (x*inverse_affine.sx+y*inverse_affine.ry+ 01179 inverse_affine.tx); 01180 point.y=(MagickRealType) (x*inverse_affine.rx+y*inverse_affine.sy+ 01181 inverse_affine.ty); 01182 pixel=AcquireOnePixel(composite,(long) point.x,(long) point.y, 01183 &image->exception); 01184 MagickCompositeOver(&pixel,(MagickRealType) pixel.opacity,q, 01185 (MagickRealType) q->opacity,q); 01186 q++; 01187 } 01188 if (SyncImagePixels(image) == MagickFalse) 01189 break; 01190 } 01191 return(MagickTrue); 01192 } 01193 01194 /* 01195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01196 % % 01197 % % 01198 % % 01199 + D r a w B o u n d i n g R e c t a n g l e s % 01200 % % 01201 % % 01202 % % 01203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01204 % 01205 % DrawBoundingRectangles() draws the bounding rectangles on the image. This 01206 % is only useful for developers debugging the rendering algorithm. 01207 % 01208 % The format of the DrawBoundingRectangles method is: 01209 % 01210 % void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info, 01211 % PolygonInfo *polygon_info) 01212 % 01213 % A description of each parameter follows: 01214 % 01215 % o image: The image. 01216 % 01217 % o draw_info: The draw info. 01218 % 01219 % o polygon_info: Specifies a pointer to a PolygonInfo structure. 01220 % 01221 % 01222 */ 01223 static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info, 01224 const PolygonInfo *polygon_info) 01225 { 01226 DrawInfo 01227 *clone_info; 01228 01229 long 01230 coordinates; 01231 01232 MagickRealType 01233 mid; 01234 01235 PointInfo 01236 end, 01237 resolution, 01238 start; 01239 01240 PrimitiveInfo 01241 primitive_info[6]; 01242 01243 register long 01244 i; 01245 01246 SegmentInfo 01247 bounds; 01248 01249 clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info); 01250 (void) QueryColorDatabase("#000000ff",&clone_info->fill,&image->exception); 01251 resolution.x=72.0; 01252 resolution.y=