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