]> granicus.if.org Git - imagemagick/blob - magick/annotate.c
(no commit message)
[imagemagick] / magick / annotate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %           AAA   N   N  N   N   OOO   TTTTT   AAA   TTTTT  EEEEE             %
7 %          A   A  NN  N  NN  N  O   O    T    A   A    T    E                 %
8 %          AAAAA  N N N  N N N  O   O    T    AAAAA    T    EEE               %
9 %          A   A  N  NN  N  NN  O   O    T    A   A    T    E                 %
10 %          A   A  N   N  N   N   OOO     T    A   A    T    EEEEE             %
11 %                                                                             %
12 %                                                                             %
13 %                   MagickCore Image Annotation Methods                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % Digital Applications (www.digapp.com) contributed the stroked text algorithm.
37 % It was written by Leonard Rosenthol.
38 %
39 %
40 */
41 \f
42 /*
43   Include declarations.
44 */
45 #include "magick/studio.h"
46 #include "magick/annotate.h"
47 #include "magick/attribute.h"
48 #include "magick/cache-view.h"
49 #include "magick/client.h"
50 #include "magick/color.h"
51 #include "magick/color-private.h"
52 #include "magick/composite.h"
53 #include "magick/composite-private.h"
54 #include "magick/constitute.h"
55 #include "magick/draw.h"
56 #include "magick/draw-private.h"
57 #include "magick/exception.h"
58 #include "magick/exception-private.h"
59 #include "magick/gem.h"
60 #include "magick/geometry.h"
61 #include "magick/image-private.h"
62 #include "magick/log.h"
63 #include "magick/quantum.h"
64 #include "magick/quantum-private.h"
65 #include "magick/property.h"
66 #include "magick/resource_.h"
67 #include "magick/statistic.h"
68 #include "magick/string_.h"
69 #include "magick/token-private.h"
70 #include "magick/transform.h"
71 #include "magick/type.h"
72 #include "magick/utility.h"
73 #include "magick/xwindow-private.h"
74 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
75 #if defined(__MINGW32__)
76 #  undef interface
77 #endif
78 #if defined(MAGICKCORE_HAVE_FT2BUILD_H)
79 #  include <ft2build.h>
80 #endif
81 #if defined(FT_FREETYPE_H)
82 #  include FT_FREETYPE_H
83 #else
84 #  include <freetype/freetype.h>
85 #endif
86 #if defined(FT_GLYPH_H)
87 #  include FT_GLYPH_H
88 #else
89 #  include <freetype/ftglyph.h>
90 #endif
91 #if defined(FT_OUTLINE_H)
92 #  include FT_OUTLINE_H
93 #else
94 #  include <freetype/ftoutln.h>
95 #endif
96 #if defined(FT_BBOX_H)
97 #  include FT_BBOX_H
98 #else
99 #  include <freetype/ftbbox.h>
100 #endif /* defined(FT_BBOX_H) */
101 #endif
102 \f
103 /*
104   Forward declarations.
105 */
106 static MagickBooleanType
107   RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
108   RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
109   RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
110     TypeMetric *),
111   RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *);
112 \f
113 /*
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %                                                                             %
116 %                                                                             %
117 %                                                                             %
118 %   A n n o t a t e I m a g e                                                 %
119 %                                                                             %
120 %                                                                             %
121 %                                                                             %
122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123 %
124 %  AnnotateImage() annotates an image with text.  Optionally you can include
125 %  any of the following bits of information about the image by embedding
126 %  the appropriate special characters:
127 %
128 %    %b   file size in bytes.
129 %    %c   comment.
130 %    %d   directory in which the image resides.
131 %    %e   extension of the image file.
132 %    %f   original filename of the image.
133 %    %h   height of image.
134 %    %i   filename of the image.
135 %    %k   number of unique colors.
136 %    %l   image label.
137 %    %m   image file format.
138 %    %n   number of images in a image sequence.
139 %    %o   output image filename.
140 %    %p   page number of the image.
141 %    %q   image depth (8 or 16).
142 %    %q   image depth (8 or 16).
143 %    %s   image scene number.
144 %    %t   image filename without any extension.
145 %    %u   a unique temporary filename.
146 %    %w   image width.
147 %    %x   x resolution of the image.
148 %    %y   y resolution of the image.
149 %
150 %  The format of the AnnotateImage method is:
151 %
152 %      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info)
153 %
154 %  A description of each parameter follows:
155 %
156 %    o image: the image.
157 %
158 %    o draw_info: the draw info.
159 %
160 */
161 MagickExport MagickBooleanType AnnotateImage(Image *image,
162   const DrawInfo *draw_info)
163 {
164   char
165     primitive[MaxTextExtent],
166     **textlist;
167
168   DrawInfo
169     *annotate,
170     *annotate_info;
171
172   GeometryInfo
173     geometry_info;
174
175   MagickBooleanType
176     status;
177
178   PointInfo
179     offset;
180
181   RectangleInfo
182     geometry;
183
184   register long
185     i;
186
187   size_t
188     length;
189
190   TypeMetric
191     metrics;
192
193   unsigned long
194     height,
195     number_lines;
196
197   assert(image != (Image *) NULL);
198   assert(image->signature == MagickSignature);
199   if (image->debug != MagickFalse)
200     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
201   assert(draw_info != (DrawInfo *) NULL);
202   assert(draw_info->signature == MagickSignature);
203   if (draw_info->text == (char *) NULL)
204     return(MagickFalse);
205   if (*draw_info->text == '\0')
206     return(MagickTrue);
207   textlist=StringToList(draw_info->text);
208   if (textlist == (char **) NULL)
209     return(MagickFalse);
210   length=strlen(textlist[0]);
211   for (i=1; textlist[i] != (char *) NULL; i++)
212     if (strlen(textlist[i]) > length)
213       length=strlen(textlist[i]);
214   number_lines=(unsigned long) i;
215   annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
216   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
217   SetGeometry(image,&geometry);
218   SetGeometryInfo(&geometry_info);
219   if (annotate_info->geometry != (char *) NULL)
220     {
221       (void) ParsePageGeometry(image,annotate_info->geometry,&geometry,
222         &image->exception);
223       (void) ParseGeometry(annotate_info->geometry,&geometry_info);
224     }
225   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
226     return(MagickFalse);
227   status=MagickTrue;
228   for (i=0; textlist[i] != (char *) NULL; i++)
229   {
230     /*
231       Position text relative to image.
232     */
233     annotate_info->affine.tx=geometry_info.xi-image->page.x;
234     annotate_info->affine.ty=geometry_info.psi-image->page.y;
235     (void) CloneString(&annotate->text,textlist[i]);
236     (void) GetTypeMetrics(image,annotate,&metrics);
237     height=(long) (metrics.ascent-metrics.descent+
238       draw_info->interline_spacing+0.5);
239     switch (annotate->gravity)
240     {
241       case UndefinedGravity:
242       default:
243       {
244         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
245         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
246         break;
247       }
248       case NorthWestGravity:
249       {
250         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
251           annotate_info->affine.ry*height+annotate_info->affine.ry*
252           (metrics.ascent+metrics.descent);
253         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
254           annotate_info->affine.sy*height+annotate_info->affine.sy*
255           metrics.ascent;
256         break;
257       }
258       case NorthGravity:
259       {
260         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
261           geometry.width/2.0+i*annotate_info->affine.ry*height-
262           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
263           annotate_info->affine.ry*(metrics.ascent+metrics.descent);
264         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
265           annotate_info->affine.sy*height+annotate_info->affine.sy*
266           metrics.ascent-annotate_info->affine.rx*(metrics.width-
267           metrics.bounds.x1)/2.0;
268         break;
269       }
270       case NorthEastGravity:
271       {
272         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
273           geometry.width+i*annotate_info->affine.ry*height-
274           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
275           annotate_info->affine.ry*(metrics.ascent+metrics.descent)-1.0;
276         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
277           annotate_info->affine.sy*height+annotate_info->affine.sy*
278           metrics.ascent-annotate_info->affine.rx*(metrics.width-
279           metrics.bounds.x1);
280         break;
281       }
282       case WestGravity:
283       {
284         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
285           annotate_info->affine.ry*height+annotate_info->affine.ry*
286           (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
287         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
288           geometry.height/2.0+i*annotate_info->affine.sy*height+
289           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
290           (number_lines-1.0)*height)/2.0;
291         break;
292       }
293       case StaticGravity:
294       case CenterGravity:
295       {
296         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
297           geometry.width/2.0+i*annotate_info->affine.ry*height-
298           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
299           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
300           (number_lines-1)*height)/2.0;
301         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
302           geometry.height/2.0+i*annotate_info->affine.sy*height-
303           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
304           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
305           (number_lines-1.0)*height)/2.0;
306         break;
307       }
308       case EastGravity:
309       {
310         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
311           geometry.width+i*annotate_info->affine.ry*height-
312           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
313           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
314           (number_lines-1.0)*height)/2.0-1.0;
315         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
316           geometry.height/2.0+i*annotate_info->affine.sy*height-
317           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
318           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
319           (number_lines-1.0)*height)/2.0;
320         break;
321       }
322       case SouthWestGravity:
323       {
324         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
325           annotate_info->affine.ry*height-annotate_info->affine.ry*
326           (number_lines-1.0)*height;
327         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
328           geometry.height+i*annotate_info->affine.sy*height-
329           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
330         break;
331       }
332       case SouthGravity:
333       {
334         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
335           geometry.width/2.0+i*annotate_info->affine.ry*height-
336           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
337           annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
338         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
339           geometry.height+i*annotate_info->affine.sy*height-
340           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
341           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
342         break;
343       }
344       case SouthEastGravity:
345       {
346         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
347           geometry.width+i*annotate_info->affine.ry*height-
348           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
349           annotate_info->affine.ry*(number_lines-1.0)*height-1.0;
350         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
351           geometry.height+i*annotate_info->affine.sy*height-
352           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
353           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
354         break;
355       }
356     }
357     switch (annotate->align)
358     {
359       case LeftAlign:
360       {
361         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
362         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
363         break;
364       }
365       case CenterAlign:
366       {
367         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
368           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
369         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
370           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
371         break;
372       }
373       case RightAlign:
374       {
375         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
376           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
377         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
378           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
379         break;
380       }
381       default:
382         break;
383     }
384     if (draw_info->undercolor.opacity != TransparentOpacity)
385       {
386         DrawInfo
387           *undercolor_info;
388
389         /*
390           Text box.
391         */
392         undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
393         undercolor_info->fill=draw_info->undercolor;
394         undercolor_info->affine=draw_info->affine;
395         undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
396         undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
397         (void) FormatMagickString(primitive,MaxTextExtent,
398           "rectangle 0,0 %g,%lu",metrics.origin.x,height);
399         (void) CloneString(&undercolor_info->primitive,primitive);
400         (void) DrawImage(image,undercolor_info);
401         (void) DestroyDrawInfo(undercolor_info);
402       }
403     annotate_info->affine.tx=offset.x;
404     annotate_info->affine.ty=offset.y;
405     (void) FormatMagickString(primitive,MaxTextExtent,"stroke-width %g "
406       "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
407     if (annotate->decorate == OverlineDecoration)
408       {
409         annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
410           metrics.descent-metrics.underline_position));
411         (void) CloneString(&annotate_info->primitive,primitive);
412         (void) DrawImage(image,annotate_info);
413       }
414     else
415       if (annotate->decorate == UnderlineDecoration)
416         {
417           annotate_info->affine.ty-=(draw_info->affine.sy*
418             metrics.underline_position);
419           (void) CloneString(&annotate_info->primitive,primitive);
420           (void) DrawImage(image,annotate_info);
421         }
422     /*
423       Annotate image with text.
424     */
425     status=RenderType(image,annotate,&offset,&metrics);
426     if (status == MagickFalse)
427       break;
428     if (annotate->decorate == LineThroughDecoration)
429       {
430         annotate_info->affine.ty-=(draw_info->affine.sy*(height+
431           metrics.underline_position+metrics.descent)/2.0);
432         (void) CloneString(&annotate_info->primitive,primitive);
433         (void) DrawImage(image,annotate_info);
434       }
435   }
436   /*
437     Relinquish resources.
438   */
439   annotate_info=DestroyDrawInfo(annotate_info);
440   annotate=DestroyDrawInfo(annotate);
441   for (i=0; textlist[i] != (char *) NULL; i++)
442     textlist[i]=DestroyString(textlist[i]);
443   textlist=(char **) RelinquishMagickMemory(textlist);
444   return(status);
445 }
446 \f
447 /*
448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449 %                                                                             %
450 %                                                                             %
451 %                                                                             %
452 %  F o r m a t M a g i c k C a p t i o n                                      %
453 %                                                                             %
454 %                                                                             %
455 %                                                                             %
456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
457 %
458 %  FormatMagickCaption() formats a caption so that it fits within the image
459 %  width.  It returns the number of lines in the formatted caption.
460 %
461 %  The format of the FormatMagickCaption method is:
462 %
463 %      long FormatMagickCaption(Image *image,DrawInfo *draw_info,
464 %        TypeMetric *metrics,char **caption)
465 %
466 %  A description of each parameter follows.
467 %
468 %    o image:  The image.
469 %
470 %    o caption: the caption.
471 %
472 %    o draw_info: the draw info.
473 %
474 %    o metrics: Return the font metrics in this structure.
475 %
476 */
477 MagickExport long FormatMagickCaption(Image *image,DrawInfo *draw_info,
478   TypeMetric *metrics,char **caption)
479 {
480   MagickBooleanType
481     status;
482
483   register char
484     *p,
485     *q,
486     *s;
487
488   register long
489     i;
490
491   unsigned long
492     width;
493
494   q=draw_info->text;
495   s=(char *) NULL;
496   for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
497   {
498     if (IsUTFSpace(GetUTFCode(p)) != MagickFalse)
499       s=p;
500     for (i=0; i < (long) GetUTFOctets(p); i++)
501       *q++=(*(p+i));
502     *q='\0';
503     status=GetTypeMetrics(image,draw_info,metrics);
504     if (status == MagickFalse)
505       break;
506     width=(unsigned long) (metrics->width+0.5);
507     if (GetUTFCode(p) != '\n')
508       if (width <= image->columns)
509         continue;
510     if (s == (char *) NULL)
511       {
512         s=p;
513         while ((IsUTFSpace(GetUTFCode(s)) == MagickFalse) &&
514                (GetUTFCode(s) != 0))
515           s+=GetUTFOctets(s);
516       }
517     if (GetUTFCode(s) != 0)
518       {
519         *s='\n';
520         p=s;
521       }
522     else
523       {
524         char
525           *target;
526
527         long
528           n;
529
530         /*
531           No convenient line breaks-- insert newline.
532         */
533         target=AcquireString(*caption);
534         n=p-(*caption);
535         CopyMagickString(target,*caption,n+1);
536         ConcatenateMagickString(target,"\n",strlen(*caption)+1);
537         ConcatenateMagickString(target,p,strlen(*caption)+2);
538         (void) DestroyString(*caption);
539         *caption=target;
540         p=(*caption)+n;
541       }
542     s=(char *) NULL;
543     q=draw_info->text;
544   }
545   i=0;
546   for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
547     if (GetUTFCode(p) == '\n')
548       i++;
549   return(i);
550 }
551 \f
552 /*
553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 %                                                                             %
555 %                                                                             %
556 %                                                                             %
557 %   G e t M u l t i l i n e T y p e M e t r i c s                             %
558 %                                                                             %
559 %                                                                             %
560 %                                                                             %
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 %
563 %  GetMultilineTypeMetrics() returns the following information for the
564 %  specified font and text:
565 %
566 %    character width
567 %    character height
568 %    ascender
569 %    descender
570 %    text width
571 %    text height
572 %    maximum horizontal advance
573 %    bounds: x1
574 %    bounds: y1
575 %    bounds: x2
576 %    bounds: y2
577 %    origin: x
578 %    origin: y
579 %    underline position
580 %    underline thickness
581 %
582 %  This method is like GetTypeMetrics() but it returns the maximum text width
583 %  and height for multiple lines of text.
584 %
585 %  The format of the GetMultilineTypeMetrics method is:
586 %
587 %      MagickBooleanType GetMultilineTypeMetrics(Image *image,
588 %        const DrawInfo *draw_info,TypeMetric *metrics)
589 %
590 %  A description of each parameter follows:
591 %
592 %    o image: the image.
593 %
594 %    o draw_info: the draw info.
595 %
596 %    o metrics: Return the font metrics in this structure.
597 %
598 */
599 MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
600   const DrawInfo *draw_info,TypeMetric *metrics)
601 {
602   char
603     **textlist;
604
605   DrawInfo
606     *annotate_info;
607
608   MagickBooleanType
609     status;
610
611   register long
612     i;
613
614   TypeMetric
615     extent;
616
617   assert(image != (Image *) NULL);
618   assert(image->signature == MagickSignature);
619   if (image->debug != MagickFalse)
620     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
621   assert(draw_info != (DrawInfo *) NULL);
622   assert(draw_info->text != (char *) NULL);
623   assert(draw_info->signature == MagickSignature);
624   if (*draw_info->text == '\0')
625     return(MagickFalse);
626   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
627   annotate_info->text=DestroyString(annotate_info->text);
628   /*
629     Convert newlines to multiple lines of text.
630   */
631   textlist=StringToList(draw_info->text);
632   if (textlist == (char **) NULL)
633     return(MagickFalse);
634   annotate_info->render=MagickFalse;
635   (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
636   (void) ResetMagickMemory(&extent,0,sizeof(extent));
637   /*
638     Find the widest of the text lines.
639   */
640   annotate_info->text=textlist[0];
641   status=GetTypeMetrics(image,annotate_info,&extent);
642   *metrics=extent;
643   for (i=1; textlist[i] != (char *) NULL; i++)
644   {
645     annotate_info->text=textlist[i];
646     status=GetTypeMetrics(image,annotate_info,&extent);
647     if (extent.width > metrics->width)
648       *metrics=extent;
649   }
650   metrics->height=(double) (i*(unsigned long) (metrics->ascent-
651     metrics->descent+0.5)+(i-1)*draw_info->interline_spacing);
652   /*
653     Relinquish resources.
654   */
655   annotate_info->text=(char *) NULL;
656   annotate_info=DestroyDrawInfo(annotate_info);
657   for (i=0; textlist[i] != (char *) NULL; i++)
658     textlist[i]=DestroyString(textlist[i]);
659   textlist=(char **) RelinquishMagickMemory(textlist);
660   return(status);
661 }
662 \f
663 /*
664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 %                                                                             %
666 %                                                                             %
667 %                                                                             %
668 %   G e t T y p e M e t r i c s                                               %
669 %                                                                             %
670 %                                                                             %
671 %                                                                             %
672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673 %
674 %  GetTypeMetrics() returns the following information for the specified font
675 %  and text:
676 %
677 %    character width
678 %    character height
679 %    ascender
680 %    descender
681 %    text width
682 %    text height
683 %    maximum horizontal advance
684 %    bounds: x1
685 %    bounds: y1
686 %    bounds: x2
687 %    bounds: y2
688 %    origin: x
689 %    origin: y
690 %    underline position
691 %    underline thickness
692 %
693 %  The format of the GetTypeMetrics method is:
694 %
695 %      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
696 %        TypeMetric *metrics)
697 %
698 %  A description of each parameter follows:
699 %
700 %    o image: the image.
701 %
702 %    o draw_info: the draw info.
703 %
704 %    o metrics: Return the font metrics in this structure.
705 %
706 */
707 MagickExport MagickBooleanType GetTypeMetrics(Image *image,
708   const DrawInfo *draw_info,TypeMetric *metrics)
709 {
710   DrawInfo
711     *annotate_info;
712
713   MagickBooleanType
714     status;
715
716   PointInfo
717     offset;
718
719   assert(image != (Image *) NULL);
720   assert(image->signature == MagickSignature);
721   if (image->debug != MagickFalse)
722     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
723   assert(draw_info != (DrawInfo *) NULL);
724   assert(draw_info->text != (char *) NULL);
725   assert(draw_info->signature == MagickSignature);
726   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
727   annotate_info->render=MagickFalse;
728   (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
729   offset.x=0.0;
730   offset.y=0.0;
731   status=RenderType(image,annotate_info,&offset,metrics);
732   if (image->debug != MagickFalse)
733     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
734       "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
735       "bounds: %g,%g  %g,%g; origin: %g,%g; pixels per em: %g,%g; "
736       "underline position: %g; underline thickness: %g",annotate_info->text,
737       metrics->width,metrics->height,metrics->ascent,metrics->descent,
738       metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
739       metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
740       metrics->pixels_per_em.x,metrics->pixels_per_em.y,
741       metrics->underline_position,metrics->underline_thickness);
742   annotate_info=DestroyDrawInfo(annotate_info);
743   return(status);
744 }
745 \f
746 /*
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 %                                                                             %
749 %                                                                             %
750 %                                                                             %
751 +   R e n d e r T y p e                                                       %
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %
757 %  RenderType() renders text on the image.  It also returns the bounding box of
758 %  the text relative to the image.
759 %
760 %  The format of the RenderType method is:
761 %
762 %      MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
763 %        const PointInfo *offset,TypeMetric *metrics)
764 %
765 %  A description of each parameter follows:
766 %
767 %    o image: the image.
768 %
769 %    o draw_info: the draw info.
770 %
771 %    o offset: (x,y) location of text relative to image.
772 %
773 %    o metrics: bounding box of text.
774 %
775 */
776 static MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
777   const PointInfo *offset,TypeMetric *metrics)
778 {
779   const TypeInfo
780     *type_info;
781
782   DrawInfo
783     *annotate_info;
784
785   MagickBooleanType
786     status;
787
788   type_info=(const TypeInfo *) NULL;
789   if (draw_info->font != (char *) NULL)
790     {
791       if (*draw_info->font == '@')
792         {
793           status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
794             metrics);
795           return(status);
796         }
797       if (*draw_info->font == '-')
798         return(RenderX11(image,draw_info,offset,metrics));
799       if (IsPathAccessible(draw_info->font) != MagickFalse)
800         {
801           status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
802             metrics);
803           return(status);
804         }
805       type_info=GetTypeInfo(draw_info->font,&image->exception);
806       if (type_info == (const TypeInfo *) NULL)
807         (void) ThrowMagickException(&image->exception,GetMagickModule(),
808           TypeWarning,"UnableToReadFont","`%s'",draw_info->font);
809     }
810   if ((type_info == (const TypeInfo *) NULL) &&
811       (draw_info->family != (const char *) NULL))
812     {
813       type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
814         draw_info->stretch,draw_info->weight,&image->exception);
815       if (type_info == (const TypeInfo *) NULL)
816         (void) ThrowMagickException(&image->exception,GetMagickModule(),
817           TypeWarning,"UnableToReadFont","`%s'",draw_info->family);
818     }
819   if (type_info == (const TypeInfo *) NULL)
820     type_info=GetTypeInfoByFamily("arial",draw_info->style,
821       draw_info->stretch,draw_info->weight,&image->exception);
822   if (type_info == (const TypeInfo *) NULL)
823     type_info=GetTypeInfoByFamily("helvetica",draw_info->style,
824       draw_info->stretch,draw_info->weight,&image->exception);
825   if (type_info == (const TypeInfo *) NULL)
826     type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
827       draw_info->stretch,draw_info->weight,&image->exception);
828   if (type_info == (const TypeInfo *) NULL)
829     {
830       status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics);
831       return(status);
832     }
833   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
834   annotate_info->face=type_info->face;
835   if (type_info->metrics != (char *) NULL)
836     (void) CloneString(&annotate_info->metrics,type_info->metrics);
837   if (type_info->glyphs != (char *) NULL)
838     (void) CloneString(&annotate_info->font,type_info->glyphs);
839   status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics);
840   annotate_info=DestroyDrawInfo(annotate_info);
841   return(status);
842 }
843 \f
844 /*
845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
846 %                                                                             %
847 %                                                                             %
848 %                                                                             %
849 +   R e n d e r F r e e t y p e                                               %
850 %                                                                             %
851 %                                                                             %
852 %                                                                             %
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
854 %
855 %  RenderFreetype() renders text on the image with a Truetype font.  It also
856 %  returns the bounding box of the text relative to the image.
857 %
858 %  The format of the RenderFreetype method is:
859 %
860 %      MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
861 %        const char *encoding,const PointInfo *offset,TypeMetric *metrics)
862 %
863 %  A description of each parameter follows:
864 %
865 %    o image: the image.
866 %
867 %    o draw_info: the draw info.
868 %
869 %    o encoding: the font encoding.
870 %
871 %    o offset: (x,y) location of text relative to image.
872 %
873 %    o metrics: bounding box of text.
874 %
875 */
876
877 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
878 static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
879   DrawInfo *draw_info)
880 {
881   AffineMatrix
882     affine;
883
884   char
885     path[MaxTextExtent];
886
887   affine=draw_info->affine;
888   (void) FormatMagickString(path,MaxTextExtent,"C%g,%g %g,%g %g,%g",
889     affine.tx+p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,
890     affine.ty-q->y/64.0,affine.tx+to->x/64.0,affine.ty-to->y/64.0);
891   (void) ConcatenateString(&draw_info->primitive,path);
892   return(0);
893 }
894
895 static int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
896 {
897   AffineMatrix
898     affine;
899
900   char
901     path[MaxTextExtent];
902
903   affine=draw_info->affine;
904   (void) FormatMagickString(path,MaxTextExtent,"L%g,%g",affine.tx+to->x/64.0,
905     affine.ty-to->y/64.0);
906   (void) ConcatenateString(&draw_info->primitive,path);
907   return(0);
908 }
909
910 static int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
911 {
912   AffineMatrix
913     affine;
914
915   char
916     path[MaxTextExtent];
917
918   affine=draw_info->affine;
919   (void) FormatMagickString(path,MaxTextExtent,"M%g,%g",affine.tx+to->x/64.0,
920     affine.ty-to->y/64.0);
921   (void) ConcatenateString(&draw_info->primitive,path);
922   return(0);
923 }
924
925 static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
926   DrawInfo *draw_info)
927 {
928   AffineMatrix
929     affine;
930
931   char
932     path[MaxTextExtent];
933
934   affine=draw_info->affine;
935   (void) FormatMagickString(path,MaxTextExtent,"Q%g,%g %g,%g",
936     affine.tx+control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,
937     affine.ty-to->y/64.0);
938   (void) ConcatenateString(&draw_info->primitive,path);
939   return(0);
940 }
941
942 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
943   const char *encoding,const PointInfo *offset,TypeMetric *metrics)
944 {
945 #if !defined(FT_OPEN_PATHNAME)
946 #define FT_OPEN_PATHNAME  ft_open_pathname
947 #endif
948
949   typedef struct _GlyphInfo
950   {
951     FT_UInt
952       id;
953
954     FT_Vector
955       origin;
956
957     FT_Glyph
958       image;
959   } GlyphInfo;
960
961   const char
962     *value;
963
964   DrawInfo
965     *annotate_info;
966
967   FT_BBox
968     bounds;
969
970   FT_BitmapGlyph
971     bitmap;
972
973   FT_Encoding
974     encoding_type;
975
976   FT_Error
977     status;
978
979   FT_Face
980     face;
981
982   FT_Int32
983     flags;
984
985   FT_Library
986     library;
987
988   FT_Matrix
989     affine;
990
991   FT_Open_Args
992     args;
993
994   FT_Vector
995     origin;
996
997   GlyphInfo
998     glyph,
999     last_glyph;
1000
1001   long
1002     code,
1003     y;
1004
1005   PointInfo
1006     point,
1007     resolution;
1008
1009   register char
1010     *p;
1011
1012   static FT_Outline_Funcs
1013     OutlineMethods =
1014     {
1015       (FT_Outline_MoveTo_Func) TraceMoveTo,
1016       (FT_Outline_LineTo_Func) TraceLineTo,
1017       (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
1018       (FT_Outline_CubicTo_Func) TraceCubicBezier,
1019       0, 0
1020     };
1021
1022   /*
1023     Initialize Truetype library.
1024   */
1025   status=FT_Init_FreeType(&library);
1026   if (status != 0)
1027     ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
1028       image->filename);
1029   args.flags=FT_OPEN_PATHNAME;
1030   if (draw_info->font == (char *) NULL)
1031     args.pathname=ConstantString("helvetica");
1032   else
1033     if (*draw_info->font != '@')
1034       args.pathname=ConstantString(draw_info->font);
1035     else
1036       args.pathname=ConstantString(draw_info->font+1);
1037   face=(FT_Face) NULL;
1038   status=FT_Open_Face(library,&args,draw_info->face,&face);
1039   args.pathname=DestroyString(args.pathname);
1040   if (status != 0)
1041     {
1042       (void) FT_Done_FreeType(library);
1043       (void) ThrowMagickException(&image->exception,GetMagickModule(),
1044         TypeError,"UnableToReadFont","`%s'",draw_info->font);
1045       return(RenderPostscript(image,draw_info,offset,metrics));
1046     }
1047   if ((draw_info->metrics != (char *) NULL) &&
1048       (IsPathAccessible(draw_info->metrics) != MagickFalse))
1049     (void) FT_Attach_File(face,draw_info->metrics);
1050   encoding_type=ft_encoding_unicode;
1051   status=FT_Select_Charmap(face,encoding_type);
1052   if ((status != 0) && (face->num_charmaps != 0))
1053     status=FT_Set_Charmap(face,face->charmaps[0]);
1054   if (encoding != (const char *) NULL)
1055     {
1056       if (LocaleCompare(encoding,"AdobeCustom") == 0)
1057         encoding_type=ft_encoding_adobe_custom;
1058       if (LocaleCompare(encoding,"AdobeExpert") == 0)
1059         encoding_type=ft_encoding_adobe_expert;
1060       if (LocaleCompare(encoding,"AdobeStandard") == 0)
1061         encoding_type=ft_encoding_adobe_standard;
1062       if (LocaleCompare(encoding,"AppleRoman") == 0)
1063         encoding_type=ft_encoding_apple_roman;
1064       if (LocaleCompare(encoding,"BIG5") == 0)
1065         encoding_type=ft_encoding_big5;
1066       if (LocaleCompare(encoding,"GB2312") == 0)
1067         encoding_type=ft_encoding_gb2312;
1068       if (LocaleCompare(encoding,"Johab") == 0)
1069         encoding_type=ft_encoding_johab;
1070 #if defined(ft_encoding_latin_1)
1071       if (LocaleCompare(encoding,"Latin-1") == 0)
1072         encoding_type=ft_encoding_latin_1;
1073 #endif
1074       if (LocaleCompare(encoding,"Latin-2") == 0)
1075         encoding_type=ft_encoding_latin_2;
1076       if (LocaleCompare(encoding,"None") == 0)
1077         encoding_type=ft_encoding_none;
1078       if (LocaleCompare(encoding,"SJIScode") == 0)
1079         encoding_type=ft_encoding_sjis;
1080       if (LocaleCompare(encoding,"Symbol") == 0)
1081         encoding_type=ft_encoding_symbol;
1082       if (LocaleCompare(encoding,"Unicode") == 0)
1083         encoding_type=ft_encoding_unicode;
1084       if (LocaleCompare(encoding,"Wansung") == 0)
1085         encoding_type=ft_encoding_wansung;
1086       status=FT_Select_Charmap(face,encoding_type);
1087       if (status != 0)
1088         ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
1089     }
1090   /*
1091     Set text size.
1092   */
1093   resolution.x=DefaultResolution;
1094   resolution.y=DefaultResolution;
1095   if (draw_info->density != (char *) NULL)
1096     {
1097       GeometryInfo
1098         geometry_info;
1099
1100       MagickStatusType
1101         flags;
1102
1103       flags=ParseGeometry(draw_info->density,&geometry_info);
1104       resolution.x=geometry_info.rho;
1105       resolution.y=geometry_info.sigma;
1106       if ((flags & SigmaValue) == 0)
1107         resolution.y=resolution.x;
1108     }
1109   status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
1110     (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
1111     (FT_UInt) resolution.y);
1112   metrics->pixels_per_em.x=face->size->metrics.x_ppem;
1113   metrics->pixels_per_em.y=face->size->metrics.y_ppem;
1114   metrics->ascent=(double) face->size->metrics.ascender/64.0;
1115   metrics->descent=(double) face->size->metrics.descender/64.0;
1116   metrics->width=0;
1117   metrics->origin.x=0;
1118   metrics->origin.y=0;
1119   metrics->height=(double) face->size->metrics.height/64.0;
1120   metrics->max_advance=0.0;
1121   if (face->size->metrics.max_advance > MagickEpsilon)
1122     metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
1123   metrics->bounds.x1=0.0;
1124   metrics->bounds.y1=metrics->descent;
1125   metrics->bounds.x2=metrics->ascent+metrics->descent;
1126   metrics->bounds.y2=metrics->ascent+metrics->descent;
1127   metrics->underline_position=face->underline_position/64.0;
1128   metrics->underline_thickness=face->underline_thickness/64.0;
1129   if (*draw_info->text == '\0')
1130     {
1131       (void) FT_Done_Face(face);
1132       (void) FT_Done_FreeType(library);
1133       return(MagickTrue);
1134     }
1135   /*
1136     Compute bounding box.
1137   */
1138   if (image->debug != MagickFalse)
1139     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
1140       "font-encoding %s; text-encoding %s; pointsize %g",
1141       draw_info->font != (char *) NULL ? draw_info->font : "none",
1142       encoding != (char *) NULL ? encoding : "none",
1143       draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
1144       draw_info->pointsize);
1145   flags=FT_LOAD_NO_BITMAP;
1146   value=GetImageProperty(image,"type:hinting");
1147   if (LocaleCompare(value,"off") == 0)
1148     flags|=FT_LOAD_NO_HINTING;
1149   glyph.id=0;
1150   glyph.image=NULL;
1151   last_glyph.id=0;
1152   last_glyph.image=NULL;
1153   origin.x=0;
1154   origin.y=0;
1155   affine.xx=65536L;
1156   affine.yx=0L;
1157   affine.xy=0L;
1158   affine.yy=65536L;
1159   if (draw_info->render != MagickFalse)
1160     {
1161       affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
1162       affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
1163       affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
1164       affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
1165     }
1166   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1167   (void) CloneString(&annotate_info->primitive,"path '");
1168   if (draw_info->render != MagickFalse)
1169     {
1170       if (image->storage_class != DirectClass)
1171         (void) SetImageStorageClass(image,DirectClass);
1172       if (image->matte == MagickFalse)
1173         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
1174     }
1175   point.x=0.0;
1176   point.y=0.0;
1177   code=0;
1178   for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
1179   {
1180     glyph.id=FT_Get_Char_Index(face,GetUTFCode(p));
1181     if (glyph.id == 0)
1182       glyph.id=FT_Get_Char_Index(face,'?');
1183     if ((glyph.id != 0) && (last_glyph.id != 0))
1184       {
1185         if (draw_info->kerning != 0.0)
1186           origin.x+=64.0*draw_info->kerning;
1187         else
1188           if (FT_HAS_KERNING(face))
1189             {
1190               FT_Vector
1191                 kerning;
1192
1193               status=FT_Get_Kerning(face,last_glyph.id,glyph.id,
1194                 ft_kerning_default,&kerning);
1195               if (status == 0)
1196                 origin.x+=kerning.x;
1197             }
1198         }
1199     glyph.origin=origin;
1200     status=FT_Load_Glyph(face,glyph.id,flags);
1201     if (status != 0)
1202       continue;
1203     status=FT_Get_Glyph(face->glyph,&glyph.image);
1204     if (status != 0)
1205       continue;
1206     status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->outline,
1207       &bounds);
1208     if (status != 0)
1209       continue;
1210     if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
1211       metrics->bounds.x1=bounds.xMin;
1212     if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
1213       metrics->bounds.y1=bounds.yMin;
1214     if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
1215       metrics->bounds.x2=bounds.xMax;
1216     if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
1217       metrics->bounds.y2=bounds.yMax;
1218     if (draw_info->render != MagickFalse)
1219       if ((draw_info->stroke.opacity != TransparentOpacity) ||
1220           (draw_info->stroke_pattern != (Image *) NULL))
1221         {
1222           /*
1223             Trace the glyph.
1224           */
1225           annotate_info->affine.tx=glyph.origin.x/64.0;
1226           annotate_info->affine.ty=glyph.origin.y/64.0;
1227           (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->outline,
1228             &OutlineMethods,annotate_info);
1229         }
1230     FT_Vector_Transform(&glyph.origin,&affine);
1231     (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1232     status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
1233       (FT_Vector *) NULL,MagickTrue);
1234     if (status != 0)
1235       continue;
1236     bitmap=(FT_BitmapGlyph) glyph.image;
1237     point.x=offset->x+bitmap->left;
1238     point.y=offset->y-bitmap->top;
1239     if (draw_info->render != MagickFalse)
1240       {
1241         CacheView
1242           *image_view;
1243
1244         ExceptionInfo
1245           *exception;
1246
1247         MagickBooleanType
1248           status;
1249
1250         /*
1251           Rasterize the glyph.
1252         */
1253         status=MagickTrue;
1254         exception=(&image->exception);
1255         image_view=AcquireCacheView(image);
1256         for (y=0; y < (long) bitmap->bitmap.rows; y++)
1257         {
1258           long
1259             x_offset,
1260             y_offset;
1261
1262           MagickBooleanType
1263             active,
1264             sync;
1265
1266           MagickRealType
1267             fill_opacity;
1268
1269           PixelPacket
1270             fill_color;
1271
1272           register long
1273             x;
1274
1275           register PixelPacket
1276             *__restrict q;
1277
1278           register unsigned char
1279             *p;
1280
1281           if (status == MagickFalse)
1282             continue;
1283           x_offset=(long) (point.x+0.5);
1284           y_offset=(long) (point.y+y+0.5);
1285           if ((y_offset < 0) || (y_offset >= (long) image->rows))
1286             continue;
1287           q=(PixelPacket *) NULL;
1288           if ((x_offset < 0) || (x_offset >= (long) image->columns))
1289             active=MagickFalse;
1290           else
1291             {
1292               q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
1293                 bitmap->bitmap.width,1,exception);
1294               active=q != (PixelPacket *) NULL ? MagickTrue : MagickFalse;
1295             }
1296           p=bitmap->bitmap.buffer+y*bitmap->bitmap.width;
1297           for (x=0; x < (long) bitmap->bitmap.width; x++)
1298           {
1299             x_offset++;
1300             if ((*p == 0) || (x_offset < 0) ||
1301                 (x_offset >= (long) image->columns))
1302               {
1303                 p++;
1304                 q++;
1305                 continue;
1306               }
1307             fill_opacity=(MagickRealType) (*p)/(bitmap->bitmap.num_grays-1);
1308             if (draw_info->text_antialias == MagickFalse)
1309               fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
1310             if (active == MagickFalse)
1311               q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
1312                 exception);
1313             if (q == (PixelPacket *) NULL)
1314               {
1315                 p++;
1316                 q++;
1317                 continue;
1318               }
1319             (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color);
1320             fill_opacity=QuantumRange-fill_opacity*(QuantumRange-
1321               fill_color.opacity);
1322             MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q);
1323             if (active == MagickFalse)
1324               {
1325                 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1326                 if (sync == MagickFalse)
1327                   status=MagickFalse;
1328               }
1329             p++;
1330             q++;
1331           }
1332           sync=SyncCacheViewAuthenticPixels(image_view,exception);
1333           if (sync == MagickFalse)
1334             status=MagickFalse;
1335         }
1336         image_view=DestroyCacheView(image_view);
1337       }
1338     if ((bitmap->left+bitmap->bitmap.width) > metrics->width)
1339       metrics->width=bitmap->left+bitmap->bitmap.width;
1340     if ((draw_info->interword_spacing != 0.0) &&
1341         (IsUTFSpace(GetUTFCode(p)) != MagickFalse) &&
1342         (IsUTFSpace(code) == MagickFalse))
1343       origin.x+=64.0*draw_info->interword_spacing;
1344     else
1345       origin.x+=face->glyph->advance.x;
1346     metrics->origin.x=origin.x;
1347     metrics->origin.y=origin.y;
1348     if (last_glyph.id != 0)
1349       FT_Done_Glyph(last_glyph.image);
1350     last_glyph=glyph;
1351     code=GetUTFCode(p);
1352   }
1353   if (last_glyph.id != 0)
1354     FT_Done_Glyph(last_glyph.image);
1355   if ((draw_info->stroke.opacity != TransparentOpacity) ||
1356       (draw_info->stroke_pattern != (Image *) NULL))
1357     {
1358       if (draw_info->render != MagickFalse)
1359         {
1360           /*
1361             Draw text stroke.
1362           */
1363           annotate_info->linejoin=RoundJoin;
1364           annotate_info->affine.tx=offset->x;
1365           annotate_info->affine.ty=offset->y;
1366           (void) ConcatenateString(&annotate_info->primitive,"'");
1367           (void) DrawImage(image,annotate_info);
1368         }
1369       }
1370   /*
1371     Determine font metrics.
1372   */
1373   glyph.id=FT_Get_Char_Index(face,'_');
1374   glyph.origin=origin;
1375   status=FT_Load_Glyph(face,glyph.id,flags);
1376   if (status == 0)
1377     {
1378       status=FT_Get_Glyph(face->glyph,&glyph.image);
1379       if (status == 0)
1380         {
1381           status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->
1382             outline,&bounds);
1383           if (status == 0)
1384             {
1385               FT_Vector_Transform(&glyph.origin,&affine);
1386               (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1387               status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
1388                 (FT_Vector *) NULL,MagickTrue);
1389               bitmap=(FT_BitmapGlyph) glyph.image;
1390               if (bitmap->left > metrics->width)
1391                 metrics->width=bitmap->left;
1392             }
1393         }
1394       if (glyph.id != 0)
1395         FT_Done_Glyph(glyph.image);
1396     }
1397   metrics->width-=metrics->bounds.x1/64.0;
1398   metrics->bounds.x1/=64.0;
1399   metrics->bounds.y1/=64.0;
1400   metrics->bounds.x2/=64.0;
1401   metrics->bounds.y2/=64.0;
1402   metrics->origin.x/=64.0;
1403   metrics->origin.y/=64.0;
1404   /*
1405     Relinquish resources.
1406   */
1407   annotate_info=DestroyDrawInfo(annotate_info);
1408   (void) FT_Done_Face(face);
1409   (void) FT_Done_FreeType(library);
1410   return(MagickTrue);
1411 }
1412 #else
1413 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
1414   const char *magick_unused(encoding),const PointInfo *offset,
1415   TypeMetric *metrics)
1416 {
1417   (void) ThrowMagickException(&image->exception,GetMagickModule(),
1418     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (Freetype)",
1419     draw_info->font);
1420   return(RenderPostscript(image,draw_info,offset,metrics));
1421 }
1422 #endif
1423 \f
1424 /*
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 %                                                                             %
1427 %                                                                             %
1428 %                                                                             %
1429 +   R e n d e r P o s t s c r i p t                                           %
1430 %                                                                             %
1431 %                                                                             %
1432 %                                                                             %
1433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 %
1435 %  RenderPostscript() renders text on the image with a Postscript font.  It
1436 %  also returns the bounding box of the text relative to the image.
1437 %
1438 %  The format of the RenderPostscript method is:
1439 %
1440 %      MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
1441 %        const PointInfo *offset,TypeMetric *metrics)
1442 %
1443 %  A description of each parameter follows:
1444 %
1445 %    o image: the image.
1446 %
1447 %    o draw_info: the draw info.
1448 %
1449 %    o offset: (x,y) location of text relative to image.
1450 %
1451 %    o metrics: bounding box of text.
1452 %
1453 */
1454
1455 static inline size_t MagickMin(const size_t x,const size_t y)
1456 {
1457   if (x < y)
1458     return(x);
1459   return(y);
1460 }
1461
1462 static char *EscapeParenthesis(const char *text)
1463 {
1464   char
1465     *buffer;
1466
1467   register char
1468     *p;
1469
1470   register long
1471     i;
1472
1473   size_t
1474     escapes;
1475
1476   escapes=0;
1477   buffer=AcquireString(text);
1478   p=buffer;
1479   for (i=0; i < (long) MagickMin(strlen(text),MaxTextExtent-escapes-1); i++)
1480   {
1481     if ((text[i] == '(') || (text[i] == ')'))
1482       {
1483         *p++='\\';
1484         escapes++;
1485       }
1486     *p++=text[i];
1487   }
1488   *p='\0';
1489   return(buffer);
1490 }
1491
1492 static MagickBooleanType RenderPostscript(Image *image,
1493   const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics)
1494 {
1495   char
1496     filename[MaxTextExtent],
1497     geometry[MaxTextExtent],
1498     *text;
1499
1500   FILE
1501     *file;
1502
1503   Image
1504     *annotate_image;
1505
1506   ImageInfo
1507     *annotate_info;
1508
1509   int
1510     unique_file;
1511
1512   long
1513     y;
1514
1515   MagickBooleanType
1516     identity;
1517
1518   PointInfo
1519     extent,
1520     point,
1521     resolution;
1522
1523   register long
1524     i;
1525
1526   /*
1527     Render label with a Postscript font.
1528   */
1529   if (image->debug != MagickFalse)
1530     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
1531       "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
1532       draw_info->font : "none",draw_info->pointsize);
1533   file=(FILE *) NULL;
1534   unique_file=AcquireUniqueFileResource(filename);
1535   if (unique_file != -1)
1536     file=fdopen(unique_file,"wb");
1537   if ((unique_file == -1) || (file == (FILE *) NULL))
1538     {
1539       ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
1540         filename);
1541       return(MagickFalse);
1542     }
1543   (void) fprintf(file,"%%!PS-Adobe-3.0\n");
1544   (void) fprintf(file,"/ReencodeType\n");
1545   (void) fprintf(file,"{\n");
1546   (void) fprintf(file,"  findfont dup length\n");
1547   (void) fprintf(file,
1548     "  dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
1549   (void) fprintf(file,
1550     "  /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
1551   (void) fprintf(file,"} bind def\n");
1552   /*
1553     Sample to compute bounding box.
1554   */
1555   identity=(draw_info->affine.sx == draw_info->affine.sy) &&
1556     (draw_info->affine.rx == 0.0) && (draw_info->affine.ry == 0.0) ?
1557     MagickTrue : MagickFalse;
1558   extent.x=0.0;
1559   extent.y=0.0;
1560   for (i=0; i <= (long) (strlen(draw_info->text)+2); i++)
1561   {
1562     point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
1563       draw_info->affine.ry*2.0*draw_info->pointsize);
1564     point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
1565       draw_info->affine.sy*2.0*draw_info->pointsize);
1566     if (point.x > extent.x)
1567       extent.x=point.x;
1568     if (point.y > extent.y)
1569       extent.y=point.y;
1570   }
1571   (void) fprintf(file,"%g %g moveto\n",identity  != MagickFalse ? 0.0 :
1572     extent.x/2.0,extent.y/2.0);
1573   (void) fprintf(file,"%g %g scale\n",draw_info->pointsize,
1574     draw_info->pointsize);
1575   if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
1576       (strchr(draw_info->font,'/') != (char *) NULL))
1577     (void) fprintf(file,
1578       "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
1579   else
1580     (void) fprintf(file,"/%s-ISO dup /%s ReencodeType findfont setfont\n",
1581       draw_info->font,draw_info->font);
1582   (void) fprintf(file,"[%g %g %g %g 0 0] concat\n",draw_info->affine.sx,
1583     -draw_info->affine.rx,-draw_info->affine.ry,draw_info->affine.sy);
1584   text=EscapeParenthesis(draw_info->text);
1585   if (identity == MagickFalse)
1586     (void) fprintf(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",text);
1587   (void) fprintf(file,"(%s) show\n",text);
1588   text=DestroyString(text);
1589   (void) fprintf(file,"showpage\n");
1590   (void) fclose(file);
1591   (void) FormatMagickString(geometry,MaxTextExtent,"%ldx%ld+0+0!",(long)
1592     (extent.x+0.5),(long) (extent.y+0.5));
1593   annotate_info=AcquireImageInfo();
1594   (void) FormatMagickString(annotate_info->filename,MaxTextExtent,"ps:%s",
1595     filename);
1596   (void) CloneString(&annotate_info->page,geometry);
1597   if (draw_info->density != (char *) NULL)
1598     (void) CloneString(&annotate_info->density,draw_info->density);
1599   annotate_info->antialias=draw_info->text_antialias;
1600   annotate_image=ReadImage(annotate_info,&image->exception);
1601   CatchException(&image->exception);
1602   annotate_info=DestroyImageInfo(annotate_info);
1603   (void) RelinquishUniqueFileResource(filename);
1604   if (annotate_image == (Image *) NULL)
1605     return(MagickFalse);
1606   resolution.x=DefaultResolution;
1607   resolution.y=DefaultResolution;
1608   if (draw_info->density != (char *) NULL)
1609     {
1610       GeometryInfo
1611         geometry_info;
1612
1613       MagickStatusType
1614         flags;
1615
1616       flags=ParseGeometry(draw_info->density,&geometry_info);
1617       resolution.x=geometry_info.rho;
1618       resolution.y=geometry_info.sigma;
1619       if ((flags & SigmaValue) == 0)
1620         resolution.y=resolution.x;
1621     }
1622   if (identity == MagickFalse)
1623     (void) TransformImage(&annotate_image,"0x0",(char *) NULL);
1624   else
1625     {
1626       RectangleInfo
1627         crop_info;
1628
1629       crop_info=GetImageBoundingBox(annotate_image,&annotate_image->exception);
1630       crop_info.height=(unsigned long) ((resolution.y/DefaultResolution)*
1631         ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
1632       crop_info.y=(long) ((resolution.y/DefaultResolution)*extent.y/8.0+0.5);
1633       (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
1634         crop_info.width,crop_info.height,crop_info.x,crop_info.y);
1635       (void) TransformImage(&annotate_image,geometry,(char *) NULL);
1636     }
1637   metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
1638     ExpandAffine(&draw_info->affine)*draw_info->pointsize;
1639   metrics->pixels_per_em.y=metrics->pixels_per_em.x;
1640   metrics->ascent=metrics->pixels_per_em.x;
1641   metrics->descent=metrics->pixels_per_em.y/-5.0;
1642   metrics->width=(double) annotate_image->columns/
1643     ExpandAffine(&draw_info->affine);
1644   metrics->height=1.152*metrics->pixels_per_em.x;
1645   metrics->max_advance=metrics->pixels_per_em.x;
1646   metrics->bounds.x1=0.0;
1647   metrics->bounds.y1=metrics->descent;
1648   metrics->bounds.x2=metrics->ascent+metrics->descent;
1649   metrics->bounds.y2=metrics->ascent+metrics->descent;
1650   metrics->underline_position=(-2.0);
1651   metrics->underline_thickness=1.0;
1652   if (draw_info->render == MagickFalse)
1653     {
1654       annotate_image=DestroyImage(annotate_image);
1655       return(MagickTrue);
1656     }
1657   if (draw_info->fill.opacity != TransparentOpacity)
1658     {
1659       ExceptionInfo
1660         *exception;
1661
1662       MagickBooleanType
1663         sync;
1664
1665       PixelPacket
1666         fill_color;
1667
1668       CacheView
1669         *annotate_view;
1670
1671       /*
1672         Render fill color.
1673       */
1674       if (image->matte == MagickFalse)
1675         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
1676       if (annotate_image->matte == MagickFalse)
1677         (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel);
1678       fill_color=draw_info->fill;
1679       exception=(&image->exception);
1680       annotate_view=AcquireCacheView(annotate_image);
1681       for (y=0; y < (long) annotate_image->rows; y++)
1682       {
1683         register long
1684           x;
1685
1686         register PixelPacket
1687           *__restrict q;
1688
1689         q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
1690           1,exception);
1691         if (q == (PixelPacket *) NULL)
1692           break;
1693         for (x=0; x < (long) annotate_image->columns; x++)
1694         {
1695           (void) GetFillColor(draw_info,x,y,&fill_color);
1696           q->opacity=RoundToQuantum(QuantumRange-(((QuantumRange-
1697             (MagickRealType) PixelIntensityToQuantum(q))*(QuantumRange-
1698             fill_color.opacity))/QuantumRange));
1699           q->red=fill_color.red;
1700           q->green=fill_color.green;
1701           q->blue=fill_color.blue;
1702           q++;
1703         }
1704         sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
1705         if (sync == MagickFalse)
1706           break;
1707       }
1708       annotate_view=DestroyCacheView(annotate_view);
1709       (void) CompositeImage(image,OverCompositeOp,annotate_image,
1710         (long) (offset->x+0.5),(long) (offset->y-(metrics->ascent+
1711         metrics->descent)+0.5));
1712     }
1713   annotate_image=DestroyImage(annotate_image);
1714   return(MagickTrue);
1715 }
1716 \f
1717 /*
1718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 %                                                                             %
1720 %                                                                             %
1721 %                                                                             %
1722 +   R e n d e r X 1 1                                                         %
1723 %                                                                             %
1724 %                                                                             %
1725 %                                                                             %
1726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 %
1728 %  RenderX11() renders text on the image with an X11 font.  It also returns the
1729 %  bounding box of the text relative to the image.
1730 %
1731 %  The format of the RenderX11 method is:
1732 %
1733 %      MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
1734 %        const PointInfo *offset,TypeMetric *metrics)
1735 %
1736 %  A description of each parameter follows:
1737 %
1738 %    o image: the image.
1739 %
1740 %    o draw_info: the draw info.
1741 %
1742 %    o offset: (x,y) location of text relative to image.
1743 %
1744 %    o metrics: bounding box of text.
1745 %
1746 */
1747 #if defined(MAGICKCORE_X11_DELEGATE)
1748 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
1749   const PointInfo *offset,TypeMetric *metrics)
1750 {
1751   MagickBooleanType
1752     status;
1753
1754   static DrawInfo
1755     cache_info;
1756
1757   static Display
1758     *display = (Display *) NULL;
1759
1760   static XAnnotateInfo
1761     annotate_info;
1762
1763   static XFontStruct
1764     *font_info;
1765
1766   static XPixelInfo
1767     pixel;
1768
1769   static XResourceInfo
1770     resource_info;
1771
1772   static XrmDatabase
1773     resource_database;
1774
1775   static XStandardColormap
1776     *map_info;
1777
1778   static XVisualInfo
1779     *visual_info;
1780
1781   unsigned long
1782     height,
1783     width;
1784
1785   if (display == (Display *) NULL)
1786     {
1787       const char
1788         *client_name;
1789
1790       ImageInfo
1791         *image_info;
1792
1793       /*
1794         Open X server connection.
1795       */
1796       display=XOpenDisplay(draw_info->server_name);
1797       if (display == (Display *) NULL)
1798         {
1799           ThrowXWindowException(XServerError,"UnableToOpenXServer",
1800             draw_info->server_name);
1801           return(MagickFalse);
1802         }
1803       /*
1804         Get user defaults from X resource database.
1805       */
1806       (void) XSetErrorHandler(XError);
1807       image_info=AcquireImageInfo();
1808       client_name=GetClientName();
1809       resource_database=XGetResourceDatabase(display,client_name);
1810       XGetResourceInfo(image_info,resource_database,client_name,&resource_info);
1811       resource_info.close_server=MagickFalse;
1812       resource_info.colormap=PrivateColormap;
1813       resource_info.font=AcquireString(draw_info->font);
1814       resource_info.background_color=AcquireString("#ffffffffffff");
1815       resource_info.foreground_color=AcquireString("#000000000000");
1816       map_info=XAllocStandardColormap();
1817       if (map_info == (XStandardColormap *) NULL)
1818         {
1819           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
1820             image->filename);
1821           return(MagickFalse);
1822         }
1823       /*
1824         Initialize visual info.
1825       */
1826       visual_info=XBestVisualInfo(display,map_info,&resource_info);
1827       if (visual_info == (XVisualInfo *) NULL)
1828         {
1829           ThrowXWindowException(XServerError,"UnableToGetVisual",
1830             image->filename);
1831           return(MagickFalse);
1832         }
1833       map_info->colormap=(Colormap) NULL;
1834       pixel.pixels=(unsigned long *) NULL;
1835       /*
1836         Initialize Standard Colormap info.
1837       */
1838       XGetMapInfo(visual_info,XDefaultColormap(display,visual_info->screen),
1839         map_info);
1840       XGetPixelPacket(display,visual_info,map_info,&resource_info,
1841         (Image *) NULL,&pixel);
1842       pixel.annotate_context=XDefaultGC(display,visual_info->screen);
1843       /*
1844         Initialize font info.
1845       */
1846       font_info=XBestFont(display,&resource_info,MagickFalse);
1847       if (font_info == (XFontStruct *) NULL)
1848         {
1849           ThrowXWindowException(XServerError,"UnableToLoadFont",
1850             draw_info->font);
1851           return(MagickFalse);
1852         }
1853       if ((map_info == (XStandardColormap *) NULL) ||
1854           (visual_info == (XVisualInfo *) NULL) ||
1855           (font_info == (XFontStruct *) NULL))
1856         {
1857           XFreeResources(display,visual_info,map_info,&pixel,font_info,
1858             &resource_info,(XWindowInfo *) NULL);
1859           ThrowXWindowException(XServerError,"UnableToLoadFont",
1860             image->filename);
1861           return(MagickFalse);
1862         }
1863       cache_info=(*draw_info);
1864     }
1865   /*
1866     Initialize annotate info.
1867   */
1868   XGetAnnotateInfo(&annotate_info);
1869   annotate_info.stencil=ForegroundStencil;
1870   if (cache_info.font != draw_info->font)
1871     {
1872       /*
1873         Type name has changed.
1874       */
1875       (void) XFreeFont(display,font_info);
1876       (void) CloneString(&resource_info.font,draw_info->font);
1877       font_info=XBestFont(display,&resource_info,MagickFalse);
1878       if (font_info == (XFontStruct *) NULL)
1879         {
1880           ThrowXWindowException(XServerError,"UnableToLoadFont",
1881             draw_info->font);
1882           return(MagickFalse);
1883         }
1884     }
1885   if (image->debug != MagickFalse)
1886     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
1887       "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
1888       draw_info->font : "none",draw_info->pointsize);
1889   cache_info=(*draw_info);
1890   annotate_info.font_info=font_info;
1891   annotate_info.text=(char *) draw_info->text;
1892   annotate_info.width=(unsigned int) XTextWidth(font_info,draw_info->text,
1893     (int) strlen(draw_info->text));
1894   annotate_info.height=(unsigned int) font_info->ascent+font_info->descent;
1895   metrics->pixels_per_em.x=(double) font_info->max_bounds.width;
1896   metrics->pixels_per_em.y=(double) font_info->ascent+font_info->descent;
1897   metrics->ascent=(double) font_info->ascent+4;
1898   metrics->descent=(double) (-font_info->descent);
1899   metrics->width=annotate_info.width/ExpandAffine(&draw_info->affine);
1900   metrics->height=font_info->ascent+font_info->descent;
1901   metrics->max_advance=(double) font_info->max_bounds.width;
1902   metrics->bounds.x1=0.0;
1903   metrics->bounds.y1=metrics->descent;
1904   metrics->bounds.x2=metrics->ascent+metrics->descent;
1905   metrics->bounds.y2=metrics->ascent+metrics->descent;
1906   metrics->underline_position=(-2.0);
1907   metrics->underline_thickness=1.0;
1908   if (draw_info->render == MagickFalse)
1909     return(MagickTrue);
1910   if (draw_info->fill.opacity == TransparentOpacity)
1911     return(MagickTrue);
1912   /*
1913     Render fill color.
1914   */
1915   width=annotate_info.width;
1916   height=annotate_info.height;
1917   if ((draw_info->affine.rx != 0.0) || (draw_info->affine.ry != 0.0))
1918     {
1919       if (((draw_info->affine.sx-draw_info->affine.sy) == 0.0) &&
1920           ((draw_info->affine.rx+draw_info->affine.ry) == 0.0))
1921         annotate_info.degrees=(180.0/MagickPI)*
1922           atan2(draw_info->affine.rx,draw_info->affine.sx);
1923     }
1924   (void) FormatMagickString(annotate_info.geometry,MaxTextExtent,
1925     "%lux%lu+%ld+%ld",width,height,(long) (offset->x+0.5),
1926     (long) (offset->y-metrics->ascent-metrics->descent+
1927     draw_info->interline_spacing+0.5));
1928   pixel.pen_color.red=ScaleQuantumToShort(draw_info->fill.red);
1929   pixel.pen_color.green=ScaleQuantumToShort(draw_info->fill.green);
1930   pixel.pen_color.blue=ScaleQuantumToShort(draw_info->fill.blue);
1931   status=XAnnotateImage(display,&pixel,&annotate_info,image);
1932   if (status == 0)
1933     {
1934       ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
1935         image->filename);
1936       return(MagickFalse);
1937     }
1938   return(MagickTrue);
1939 }
1940 #else
1941 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
1942   const PointInfo *offset,TypeMetric *metrics)
1943 {
1944   (void) draw_info;
1945   (void) offset;
1946   (void) metrics;
1947   (void) ThrowMagickException(&image->exception,GetMagickModule(),
1948     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
1949     image->filename);
1950   return(MagickFalse);
1951 }
1952 #endif