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