13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           AAA   N   N  N   N   OOO   TTTTT   AAA   TTTTT  EEEEE             %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          A   A  NN  N  NN  N  O   O    T    A   A    T    E                 %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          AAAAA  N N N  N N N  O   O    T    AAAAA    T    EEE               %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          A   A  N  NN  N  NN  O   O    T    A   A    T    E                 %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          A   A  N   N  N   N   OOO     T    A   A    T    EEEEE             %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                   MagickCore Image Annotation Methods                       %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                 July 1992                                   %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
207ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Digital Applications (www.digapp.com) contributed the stroked text algorithm.
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% It was written by Leonard Rosenthol.
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/annotate.h"
475ff4eaf57b3cd47d0371f204f865cbba614674a0cristy#include "MagickCore/annotate-private.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/attribute.h"
49ba4ad2dfd3d5b883e8aa7d6e8b4e6f9613dc3c45Cristy#include "MagickCore/cache-private.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h"
51c9afe1687cd4da5d2382a9ca3ca12f30d8baa96fcristy#include "MagickCore/channel.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/client.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h"
5554b92627b2e9657853beee431546d08234276477cristy#include "MagickCore/colorspace-private.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite-private.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/constitute.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw-private.h"
613644bdf56f0081bcae1f4dbc69c2d06713f6203bcristy#include "MagickCore/enhance.h"
624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h"
654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/geometry.h"
664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/log.h"
684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum.h"
694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/property.h"
724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resource_.h"
734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h"
744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h"
754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
7617f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy#include "MagickCore/token.h"
774c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token-private.h"
7806f590165f0505d42005264893fe14a9e8a79986dirk#include "MagickCore/transform-private.h"
794c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/type.h"
804c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h"
81d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h"
82bcbda3fd7d9f3084869f5cebabceb0324c3b2cd7cristy#include "MagickCore/xwindow.h"
834c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/xwindow-private.h"
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FREETYPE_DELEGATE)
8507a3cca00593c795eb8e0427f5bc4c2bcad3f0fbcristy#if defined(__MINGW32__) || defined(__MINGW64__)
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  undef interface
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
8803f187ee83f1927717c93c57af06d5e030a194becristy#include <ft2build.h>
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(FT_FREETYPE_H)
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include FT_FREETYPE_H
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include <freetype/freetype.h>
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(FT_GLYPH_H)
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include FT_GLYPH_H
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include <freetype/ftglyph.h>
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(FT_OUTLINE_H)
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include FT_OUTLINE_H
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include <freetype/ftoutln.h>
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(FT_BBOX_H)
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include FT_BBOX_H
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#  include <freetype/ftbbox.h>
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif /* defined(FT_BBOX_H) */
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
11017f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy#if defined(MAGICKCORE_RAQM_DELEGATE)
11169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy#include <raqm.h>
112ea866ca14ef4019d49cf678d35b405512b210b85Cristy#endif
11317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristytypedef struct _GraphemeInfo
11469a0d3b5699c573f650e6b61f98ce4579d6f218cCristy{
11587dc5e4e6f9471304ba85f508de30e664b484d3aCristy  size_t
11669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    index,
11769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    x_offset,
11869a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    x_advance,
11969a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    y_offset;
12069a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
12187dc5e4e6f9471304ba85f508de30e664b484d3aCristy  size_t
12269a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    cluster;
12317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy} GraphemeInfo;
1245eb36084e86f5ab4a877c2b31c19880b0b0b02e3Cristy
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
126d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  Annotate semaphores.
127d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy*/
128d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristystatic SemaphoreInfo
129d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  *annotate_semaphore = (SemaphoreInfo *) NULL;
130d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy
131d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy/*
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Forward declarations.
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
1355cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
1365cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    ExceptionInfo *),
1375cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
1385cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    ExceptionInfo *),
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
1405cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    TypeMetric *,ExceptionInfo *),
1415cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
1425cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    ExceptionInfo *);
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
149d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy+   A n n o t a t e C o m p o n e n t G e n e s i s                           %
150d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
151d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
152d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
153d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
155d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%  AnnotateComponentGenesis() instantiates the annotate component.
156d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
157d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%  The format of the AnnotateComponentGenesis method is:
158d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
159d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%      MagickBooleanType AnnotateComponentGenesis(void)
160d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
161d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy*/
1625ff4eaf57b3cd47d0371f204f865cbba614674a0cristyMagickPrivate MagickBooleanType AnnotateComponentGenesis(void)
163d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy{
1647c9770650f31145e0fe8811d10b2e0ecd47697c8cristy  if (annotate_semaphore == (SemaphoreInfo *) NULL)
1657c9770650f31145e0fe8811d10b2e0ecd47697c8cristy    annotate_semaphore=AcquireSemaphoreInfo();
166d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  return(MagickTrue);
167d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy}
168d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy
169d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy/*
170d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
172d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
173d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
174d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy+   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                         %
175d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
176d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
177d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
178d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
180d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%  AnnotateComponentTerminus() destroys the annotate component.
181d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
182d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%  The format of the AnnotateComponentTerminus method is:
183d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
184d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%      AnnotateComponentTerminus(void)
185d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%
186d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy*/
1875ff4eaf57b3cd47d0371f204f865cbba614674a0cristyMagickPrivate void AnnotateComponentTerminus(void)
188d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy{
189d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  if (annotate_semaphore == (SemaphoreInfo *) NULL)
19004b11db5504ecdf205114ae7e9e68774a1ff0b9bcristy    ActivateSemaphoreInfo(&annotate_semaphore);
1913d162a93f537cb7cbb6d9fa3b8e73e8f992a527acristy  RelinquishSemaphoreInfo(&annotate_semaphore);
192d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy}
193d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy
194d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy/*
195d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
197d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
198d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy%                                                                             %
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A n n o t a t e I m a g e                                                 %
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AnnotateImage() annotates an image with text.  Optionally you can include
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  any of the following bits of information about the image by embedding
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the appropriate special characters:
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
209528127ac76bc2eda65c7e8407b11669b25513149cristy%    \n   newline
210528127ac76bc2eda65c7e8407b11669b25513149cristy%    \r   carriage return
211528127ac76bc2eda65c7e8407b11669b25513149cristy%    <    less-than character.
212528127ac76bc2eda65c7e8407b11669b25513149cristy%    >    greater-than character.
213528127ac76bc2eda65c7e8407b11669b25513149cristy%    &    ampersand character.
214528127ac76bc2eda65c7e8407b11669b25513149cristy%    %%   a percent sign
215528127ac76bc2eda65c7e8407b11669b25513149cristy%    %b   file size of image read in
216528127ac76bc2eda65c7e8407b11669b25513149cristy%    %c   comment meta-data property
217528127ac76bc2eda65c7e8407b11669b25513149cristy%    %d   directory component of path
218528127ac76bc2eda65c7e8407b11669b25513149cristy%    %e   filename extension or suffix
219528127ac76bc2eda65c7e8407b11669b25513149cristy%    %f   filename (including suffix)
220528127ac76bc2eda65c7e8407b11669b25513149cristy%    %g   layer canvas page geometry   (equivalent to "%Wx%H%X%Y")
221528127ac76bc2eda65c7e8407b11669b25513149cristy%    %h   current image height in pixels
222528127ac76bc2eda65c7e8407b11669b25513149cristy%    %i   image filename (note: becomes output filename for "info:")
223528127ac76bc2eda65c7e8407b11669b25513149cristy%    %k   CALCULATED: number of unique colors
224528127ac76bc2eda65c7e8407b11669b25513149cristy%    %l   label meta-data property
225528127ac76bc2eda65c7e8407b11669b25513149cristy%    %m   image file format (file magic)
226528127ac76bc2eda65c7e8407b11669b25513149cristy%    %n   number of images in current image sequence
227528127ac76bc2eda65c7e8407b11669b25513149cristy%    %o   output filename  (used for delegates)
228528127ac76bc2eda65c7e8407b11669b25513149cristy%    %p   index of image in current image list
229528127ac76bc2eda65c7e8407b11669b25513149cristy%    %q   quantum depth (compile-time constant)
230528127ac76bc2eda65c7e8407b11669b25513149cristy%    %r   image class and colorspace
231528127ac76bc2eda65c7e8407b11669b25513149cristy%    %s   scene number (from input unless re-assigned)
232528127ac76bc2eda65c7e8407b11669b25513149cristy%    %t   filename without directory or extension (suffix)
233528127ac76bc2eda65c7e8407b11669b25513149cristy%    %u   unique temporary filename (used for delegates)
234528127ac76bc2eda65c7e8407b11669b25513149cristy%    %w   current width in pixels
235528127ac76bc2eda65c7e8407b11669b25513149cristy%    %x   x resolution (density)
236528127ac76bc2eda65c7e8407b11669b25513149cristy%    %y   y resolution (density)
237528127ac76bc2eda65c7e8407b11669b25513149cristy%    %z   image depth (as read in unless modified, image save depth)
238528127ac76bc2eda65c7e8407b11669b25513149cristy%    %A   image transparency channel enabled (true/false)
239528127ac76bc2eda65c7e8407b11669b25513149cristy%    %C   image compression type
240528127ac76bc2eda65c7e8407b11669b25513149cristy%    %D   image GIF dispose method
241528127ac76bc2eda65c7e8407b11669b25513149cristy%    %G   original image size (%wx%h; before any resizes)
242528127ac76bc2eda65c7e8407b11669b25513149cristy%    %H   page (canvas) height
243528127ac76bc2eda65c7e8407b11669b25513149cristy%    %M   Magick filename (original file exactly as given,  including read mods)
244528127ac76bc2eda65c7e8407b11669b25513149cristy%    %O   page (canvas) offset ( = %X%Y )
245528127ac76bc2eda65c7e8407b11669b25513149cristy%    %P   page (canvas) size ( = %Wx%H )
246528127ac76bc2eda65c7e8407b11669b25513149cristy%    %Q   image compression quality ( 0 = default )
247528127ac76bc2eda65c7e8407b11669b25513149cristy%    %S   ?? scenes ??
248528127ac76bc2eda65c7e8407b11669b25513149cristy%    %T   image time delay (in centi-seconds)
249528127ac76bc2eda65c7e8407b11669b25513149cristy%    %U   image resolution units
250528127ac76bc2eda65c7e8407b11669b25513149cristy%    %W   page (canvas) width
251528127ac76bc2eda65c7e8407b11669b25513149cristy%    %X   page (canvas) x offset (including sign)
252528127ac76bc2eda65c7e8407b11669b25513149cristy%    %Y   page (canvas) y offset (including sign)
253528127ac76bc2eda65c7e8407b11669b25513149cristy%    %Z   unique filename (used for delegates)
254528127ac76bc2eda65c7e8407b11669b25513149cristy%    %@   CALCULATED: trim bounding box (without actually trimming)
255528127ac76bc2eda65c7e8407b11669b25513149cristy%    %#   CALCULATED: 'signature' hash of image values
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AnnotateImage method is:
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2595cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info,
2605cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        ExceptionInfo *exception)
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2685cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
2695cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType AnnotateImage(Image *image,
2725cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const DrawInfo *draw_info,ExceptionInfo *exception)
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
275151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    primitive[MagickPathExtent],
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    **textlist;
2773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate,
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GeometryInfo
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    geometry_info;
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  PointInfo
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset;
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  RectangleInfo
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    geometry;
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
294bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    length;
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  TypeMetric
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    metrics;
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
303bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
3045846039e7fade723e168819490eb771446e4b81fcristy    height,
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_lines;
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
308e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info != (DrawInfo *) NULL);
312e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(draw_info->signature == MagickCoreSignature);
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->text == (char *) NULL)
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (*draw_info->text == '\0')
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  textlist=StringToList(draw_info->text);
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (textlist == (char **) NULL)
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=strlen(textlist[0]);
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=1; textlist[i] != (char *) NULL; i++)
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (strlen(textlist[i]) > length)
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      length=strlen(textlist[i]);
324bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  number_lines=(size_t) i;
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetGeometry(image,&geometry);
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetGeometryInfo(&geometry_info);
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (annotate_info->geometry != (char *) NULL)
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ParsePageGeometry(image,annotate_info->geometry,&geometry,
3325cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        exception);
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ParseGeometry(annotate_info->geometry,&geometry_info);
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3355cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
337a6400b1cfc3594644a0f02f3d77d920092f078eecristy  if (IsGrayColorspace(image->colorspace) != MagickFalse)
3380c81d063030f7b30a97c7856e95534243cdc9e13cristy    (void) SetImageColorspace(image,sRGBColorspace,exception);
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; textlist[i] != (char *) NULL; i++)
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Position text relative to image.
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    annotate_info->affine.tx=geometry_info.xi-image->page.x;
3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    annotate_info->affine.ty=geometry_info.psi-image->page.y;
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) CloneString(&annotate->text,textlist[i]);
3485cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    (void) GetTypeMetrics(image,annotate,&metrics,exception);
349bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    height=(ssize_t) (metrics.ascent-metrics.descent+
3505846039e7fade723e168819490eb771446e4b81fcristy      draw_info->interline_spacing+0.5);
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch (annotate->gravity)
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case UndefinedGravity:
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case NorthWestGravity:
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*height+annotate_info->affine.ry*
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (metrics.ascent+metrics.descent);
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*height+annotate_info->affine.sy*
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.ascent;
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case NorthGravity:
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width/2.0+i*annotate_info->affine.ry*height-
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(metrics.ascent+metrics.descent);
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*height+annotate_info->affine.sy*
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.ascent-annotate_info->affine.rx*(metrics.width-
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.bounds.x1)/2.0;
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case NorthEastGravity:
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width+i*annotate_info->affine.ry*height-
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(metrics.ascent+metrics.descent)-1.0;
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*height+annotate_info->affine.sy*
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.ascent-annotate_info->affine.rx*(metrics.width-
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.bounds.x1);
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case WestGravity:
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*height+annotate_info->affine.ry*
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height/2.0+i*annotate_info->affine.sy*height+
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
402d4f277c15e3edbbeb2a4cc643a21b958cd8061dfCristy          (number_lines-1.0)*height)/2.0;
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CenterGravity:
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width/2.0+i*annotate_info->affine.ry*height-
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
4116ad45e16bca2904129a25730316c9b4002055ea1Cristy          (number_lines-1.0)*height)/2.0;
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height/2.0+i*annotate_info->affine.sy*height-
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
416d4f277c15e3edbbeb2a4cc643a21b958cd8061dfCristy          (number_lines-1.0)*height)/2.0;
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EastGravity:
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width+i*annotate_info->affine.ry*height-
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (number_lines-1.0)*height)/2.0-1.0;
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height/2.0+i*annotate_info->affine.sy*height-
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
430d4f277c15e3edbbeb2a4cc643a21b958cd8061dfCristy          (number_lines-1.0)*height)/2.0;
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case SouthWestGravity:
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*height-annotate_info->affine.ry*
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (number_lines-1.0)*height;
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height+i*annotate_info->affine.sy*height-
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case SouthGravity:
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width/2.0+i*annotate_info->affine.ry*height-
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
4493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height+i*annotate_info->affine.sy*height-
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case SouthEastGravity:
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.width+i*annotate_info->affine.ry*height-
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ry*(number_lines-1.0)*height-1.0;
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          geometry.height+i*annotate_info->affine.sy*height-
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch (annotate->align)
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case LeftAlign:
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CenterAlign:
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case RightAlign:
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4954c08aed51c5899665ade97263692328eea4af106cristy    if (draw_info->undercolor.alpha != TransparentAlpha)
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        DrawInfo
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          *undercolor_info;
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Text box.
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        undercolor_info->fill=draw_info->undercolor;
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        undercolor_info->affine=draw_info->affine;
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
508151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy        (void) FormatLocaleString(primitive,MagickPathExtent,
509dcc02b0a70d924b55afa7ce2089c4c15b25f2e1fcristy          "rectangle 0.0,0.0 %g,%g",metrics.origin.x,(double) height);
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) CloneString(&undercolor_info->primitive,primitive);
511018f07f7333b25743d0afff892450cebdb905c1acristy        (void) DrawImage(image,undercolor_info,exception);
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) DestroyDrawInfo(undercolor_info);
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    annotate_info->affine.tx=offset.x;
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    annotate_info->affine.ty=offset.y;
516151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    (void) FormatLocaleString(primitive,MagickPathExtent,"stroke-width %g "
517a8549b176173db7680652304c372c64bb1a51737cristy      "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (annotate->decorate == OverlineDecoration)
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.descent-metrics.underline_position));
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) CloneString(&annotate_info->primitive,primitive);
523018f07f7333b25743d0afff892450cebdb905c1acristy        (void) DrawImage(image,annotate_info,exception);
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (annotate->decorate == UnderlineDecoration)
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          annotate_info->affine.ty-=(draw_info->affine.sy*
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            metrics.underline_position);
5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (void) CloneString(&annotate_info->primitive,primitive);
531018f07f7333b25743d0afff892450cebdb905c1acristy          (void) DrawImage(image,annotate_info,exception);
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Annotate image with text.
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
5365cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    status=RenderType(image,annotate,&offset,&metrics,exception);
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (annotate->decorate == LineThroughDecoration)
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        annotate_info->affine.ty-=(draw_info->affine.sy*(height+
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          metrics.underline_position+metrics.descent)/2.0);
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) CloneString(&annotate_info->primitive,primitive);
544018f07f7333b25743d0afff892450cebdb905c1acristy        (void) DrawImage(image,annotate_info,exception);
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Relinquish resources.
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyDrawInfo(annotate_info);
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate=DestroyDrawInfo(annotate);
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; textlist[i] != (char *) NULL; i++)
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    textlist[i]=DestroyString(textlist[i]);
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  textlist=(char **) RelinquishMagickMemory(textlist);
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  F o r m a t M a g i c k C a p t i o n                                      %
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  FormatMagickCaption() formats a caption so that it fits within the image
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  width.  It returns the number of lines in the formatted caption.
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the FormatMagickCaption method is:
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
574bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
5755cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const MagickBooleanType split,TypeMetric *metrics,char **caption,
5765cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        ExceptionInfo *exception)
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image:  The image.
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5846b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy%    o split: when no convenient line breaks-- insert newline.
5856b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy%
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: Return the font metrics in this structure.
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5886b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy%    o caption: the caption.
5896b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy%
5905cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
5915cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
593bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristyMagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
5945cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const MagickBooleanType split,TypeMetric *metrics,char **caption,
5955cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  ExceptionInfo *exception)
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
59774966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy  char
59874966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy    *text;
59974966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
60120aa2994f8d56f6f03a7a96b2a25d93b906989bcCristy    digit,
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register char
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p,
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *q,
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *s;
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
609bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
612bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    width;
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6156193b86c0b59030b647a10c75f37ec82d73e3695cristy  ssize_t
6166193b86c0b59030b647a10c75f37ec82d73e3695cristy    n;
6176193b86c0b59030b647a10c75f37ec82d73e3695cristy
61820aa2994f8d56f6f03a7a96b2a25d93b906989bcCristy  digit=MagickFalse;
61974966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy  text=AcquireString(draw_info->text);
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=draw_info->text;
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=(char *) NULL;
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
62420aa2994f8d56f6f03a7a96b2a25d93b906989bcCristy    if ((digit == MagickFalse) && (IsUTFSpace(GetUTFCode(p)) != MagickFalse))
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      s=p;
62620aa2994f8d56f6f03a7a96b2a25d93b906989bcCristy    digit=((GetUTFCode(p) >= 0x0030) && (GetUTFCode(p) <= 0x0039)) ?
62720aa2994f8d56f6f03a7a96b2a25d93b906989bcCristy      MagickTrue : MagickFalse;
6282911f2d54257d36e1086061dbcc312fdad781070cristy    if (GetUTFCode(p) == '\n')
629e2c81adf02cbe4bb92991389437a2a1daf8ed313cristy      q=draw_info->text;
630bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (i=0; i < (ssize_t) GetUTFOctets(p); i++)
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *q++=(*(p+i));
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *q='\0';
6335cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    status=GetTypeMetrics(image,draw_info,metrics,exception);
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
63678fed5ea9a7f0a35e641ce3bc6f835fb099c4d20cristy    width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5);
63774966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy    if ((width <= image->columns) || (strcmp(text,draw_info->text) == 0))
6386193b86c0b59030b647a10c75f37ec82d73e3695cristy      continue;
63974966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy    (void) strcpy(text,draw_info->text);
6404aa314e7f9e09c30fcedcd112156b1dfb712b62dcristy    if ((s != (char *) NULL) && (GetUTFOctets(s) == 1))
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *s='\n';
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p=s;
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
6464aa314e7f9e09c30fcedcd112156b1dfb712b62dcristy      if ((s != (char *) NULL) || (split != MagickFalse))
6476b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy        {
6486b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          char
6496b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy            *target;
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6516b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          /*
6526b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy            No convenient line breaks-- insert newline.
6536b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          */
6546b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          target=AcquireString(*caption);
6556b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          n=p-(*caption);
6566b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          CopyMagickString(target,*caption,n+1);
6576b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          ConcatenateMagickString(target,"\n",strlen(*caption)+1);
6586b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          ConcatenateMagickString(target,p,strlen(*caption)+2);
6596b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          (void) DestroyString(*caption);
6606b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          *caption=target;
6616b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy          p=(*caption)+n;
6626b1d05e71aed91c7f85ff155dfad281e24d16fe5cristy        }
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=draw_info->text;
6646193b86c0b59030b647a10c75f37ec82d73e3695cristy    s=(char *) NULL;
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
66674966dbfe99011d1f7bea577e97a3d9a7b9836c7cristy  text=DestroyString(text);
6676193b86c0b59030b647a10c75f37ec82d73e3695cristy  n=0;
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (GetUTFCode(p) == '\n')
6706193b86c0b59030b647a10c75f37ec82d73e3695cristy      n++;
6716193b86c0b59030b647a10c75f37ec82d73e3695cristy  return(n);
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   G e t M u l t i l i n e T y p e M e t r i c s                             %
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetMultilineTypeMetrics() returns the following information for the
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specified font and text:
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    character width
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    character height
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    ascender
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    descender
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    text width
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    text height
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    maximum horizontal advance
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: x1
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: y1
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: x2
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: y2
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    origin: x
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    origin: y
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    underline position
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    underline thickness
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This method is like GetTypeMetrics() but it returns the maximum text width
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  and height for multiple lines of text.
7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetMultilineTypeMetrics method is:
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType GetMultilineTypeMetrics(Image *image,
7105cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: Return the font metrics in this structure.
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7205cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
7215cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
7245cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    **textlist;
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
735bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  TypeMetric
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    extent;
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
742e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info != (DrawInfo *) NULL);
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info->text != (char *) NULL);
747e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(draw_info->signature == MagickCoreSignature);
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (*draw_info->text == '\0')
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->text=DestroyString(annotate_info->text);
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Convert newlines to multiple lines of text.
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  textlist=StringToList(draw_info->text);
7563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (textlist == (char **) NULL)
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->render=MagickFalse;
759024843f38984cd26602f0b3b28a0768dfa056bb5cristy  annotate_info->direction=UndefinedDirection;
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(&extent,0,sizeof(extent));
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Find the widest of the text lines.
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->text=textlist[0];
7665cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  status=GetTypeMetrics(image,annotate_info,&extent,exception);
7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  *metrics=extent;
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=1; textlist[i] != (char *) NULL; i++)
7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    annotate_info->text=textlist[i];
7715cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    status=GetTypeMetrics(image,annotate_info,&extent,exception);
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (extent.width > metrics->width)
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *metrics=extent;
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
775e2c81adf02cbe4bb92991389437a2a1daf8ed313cristy  metrics->height=(double) (i*(size_t) (metrics->ascent-metrics->descent+0.5)+
776e2c81adf02cbe4bb92991389437a2a1daf8ed313cristy    (i-1)*draw_info->interline_spacing);
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Relinquish resources.
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->text=(char *) NULL;
7813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyDrawInfo(annotate_info);
7823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=0; textlist[i] != (char *) NULL; i++)
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    textlist[i]=DestroyString(textlist[i]);
7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  textlist=(char **) RelinquishMagickMemory(textlist);
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
7893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   G e t T y p e M e t r i c s                                               %
7943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
7973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
7993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  GetTypeMetrics() returns the following information for the specified font
8003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  and text:
8013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    character width
8033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    character height
8043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    ascender
8053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    descender
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    text width
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    text height
8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    maximum horizontal advance
8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: x1
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: y1
8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: x2
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    bounds: y2
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    origin: x
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    origin: y
8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    underline position
8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    underline thickness
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GetTypeMetrics method is:
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
8215cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        TypeMetric *metrics,ExceptionInfo *exception)
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: Return the font metrics in this structure.
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8315cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
8325cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType GetTypeMetrics(Image *image,
8355cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
8413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
8423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  PointInfo
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset;
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
847e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
8483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info != (DrawInfo *) NULL);
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info->text != (char *) NULL);
852e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(draw_info->signature == MagickCoreSignature);
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->render=MagickFalse;
855024843f38984cd26602f0b3b28a0768dfa056bb5cristy  annotate_info->direction=UndefinedDirection;
8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset.x=0.0;
8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset.y=0.0;
8595cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  status=RenderType(image,annotate_info,&offset,metrics,exception);
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
862e7f5109f30fc7242d04a26174a9138483dda5b6acristy      "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
863a8549b176173db7680652304c372c64bb1a51737cristy      "bounds: %g,%g  %g,%g; origin: %g,%g; pixels per em: %g,%g; "
864e7f5109f30fc7242d04a26174a9138483dda5b6acristy      "underline position: %g; underline thickness: %g",annotate_info->text,
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      metrics->width,metrics->height,metrics->ascent,metrics->descent,
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
8674c08aed51c5899665ade97263692328eea4af106cristy      metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
8684c08aed51c5899665ade97263692328eea4af106cristy      metrics->pixels_per_em.x,metrics->pixels_per_em.y,
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      metrics->underline_position,metrics->underline_thickness);
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyDrawInfo(annotate_info);
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e n d e r T y p e                                                       %
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RenderType() renders text on the image.  It also returns the bounding box of
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the text relative to the image.
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RenderType method is:
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
8915cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o offset: (x,y) location of text relative to image.
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: bounding box of text.
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9035cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
9045cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
9063ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
9075cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
9093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const TypeInfo
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *type_info;
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
9163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  type_info=(const TypeInfo *) NULL;
9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->font != (char *) NULL)
9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (*draw_info->font == '@')
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
9245cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy            metrics,exception);
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          return(status);
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (*draw_info->font == '-')
9285cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        return(RenderX11(image,draw_info,offset,metrics,exception));
9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (IsPathAccessible(draw_info->font) != MagickFalse)
9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
9325cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy            metrics,exception);
9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          return(status);
9343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
9355cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      type_info=GetTypeInfo(draw_info->font,exception);
9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (type_info == (const TypeInfo *) NULL)
9375cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
938efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy          "UnableToReadFont","`%s'",draw_info->font);
9393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
9403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((type_info == (const TypeInfo *) NULL) &&
9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (draw_info->family != (const char *) NULL))
9423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
9433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
9445cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        draw_info->stretch,draw_info->weight,exception);
9453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (type_info == (const TypeInfo *) NULL)
9465cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
947efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy          "UnableToReadFont","`%s'",draw_info->family);
9483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
9493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (type_info == (const TypeInfo *) NULL)
950d984f27fbbb96073787c88f4c9409d7f836cedc5cristy    type_info=GetTypeInfoByFamily("Arial",draw_info->style,
9515cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      draw_info->stretch,draw_info->weight,exception);
952d984f27fbbb96073787c88f4c9409d7f836cedc5cristy  if (type_info == (const TypeInfo *) NULL)
953cbb34a4def108d6db032ca9631a433afd3ea5a5dcristy    type_info=GetTypeInfoByFamily("Helvetica",draw_info->style,
9545cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      draw_info->stretch,draw_info->weight,exception);
9553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (type_info == (const TypeInfo *) NULL)
956704acaaebbfeec018847456e79de0ce301db126ecristy    type_info=GetTypeInfoByFamily("Century Schoolbook",draw_info->style,
9575cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      draw_info->stretch,draw_info->weight,exception);
958704acaaebbfeec018847456e79de0ce301db126ecristy  if (type_info == (const TypeInfo *) NULL)
9596193b86c0b59030b647a10c75f37ec82d73e3695cristy    type_info=GetTypeInfoByFamily("Sans",draw_info->style,
9605cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      draw_info->stretch,draw_info->weight,exception);
9616193b86c0b59030b647a10c75f37ec82d73e3695cristy  if (type_info == (const TypeInfo *) NULL)
9623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
9635cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      draw_info->stretch,draw_info->weight,exception);
9643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (type_info == (const TypeInfo *) NULL)
9655cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    type_info=GetTypeInfo("*",exception);
966704acaaebbfeec018847456e79de0ce301db126ecristy  if (type_info == (const TypeInfo *) NULL)
9673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
9685cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics,
9695cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        exception);
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(status);
9713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
9723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
9733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->face=type_info->face;
9743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (type_info->metrics != (char *) NULL)
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) CloneString(&annotate_info->metrics,type_info->metrics);
9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (type_info->glyphs != (char *) NULL)
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) CloneString(&annotate_info->font,type_info->glyphs);
9785cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics,
9795cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy    exception);
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyDrawInfo(annotate_info);
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e n d e r F r e e t y p e                                               %
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RenderFreetype() renders text on the image with a Truetype font.  It also
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  returns the bounding box of the text relative to the image.
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RenderFreetype method is:
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
10015cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const char *encoding,const PointInfo *offset,TypeMetric *metrics,
10025cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        ExceptionInfo *exception)
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o encoding: the font encoding.
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o offset: (x,y) location of text relative to image.
10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: bounding box of text.
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10165cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
10175cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(MAGICKCORE_FREETYPE_DELEGATE)
10212857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy
102287dc5e4e6f9471304ba85f508de30e664b484d3aCristystatic size_t ComplexTextLayout(const Image *image,const DrawInfo *draw_info,
102387dc5e4e6f9471304ba85f508de30e664b484d3aCristy  const char *text,const size_t length,const FT_Face face,const FT_Int32 flags,
102487dc5e4e6f9471304ba85f508de30e664b484d3aCristy  GraphemeInfo **grapheme,ExceptionInfo *exception)
102569a0d3b5699c573f650e6b61f98ce4579d6f218cCristy{
102617f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy#if defined(MAGICKCORE_RAQM_DELEGATE)
10270d88ea3545d808eae9feeacdd57eec41db18d2baCristy  const char
10280d88ea3545d808eae9feeacdd57eec41db18d2baCristy    *features;
10290d88ea3545d808eae9feeacdd57eec41db18d2baCristy
103017f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  raqm_t
103117f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    *rq;
103217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
103317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  raqm_glyph_t
103417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    *glyphs;
103517f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
103687dc5e4e6f9471304ba85f508de30e664b484d3aCristy  register size_t
103787dc5e4e6f9471304ba85f508de30e664b484d3aCristy    i;
103887dc5e4e6f9471304ba85f508de30e664b484d3aCristy
10396720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  size_t
10406720ed7fdc6908b46f213f43c316fcccab53dbcdCristy    extent;
104187dc5e4e6f9471304ba85f508de30e664b484d3aCristy
10426720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  extent=0;
10430d88ea3545d808eae9feeacdd57eec41db18d2baCristy  rq=raqm_create();
104417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  if (rq == (raqm_t *) NULL)
104517f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    goto cleanup;
10460d88ea3545d808eae9feeacdd57eec41db18d2baCristy  if (raqm_set_text_utf8(rq,text,length) == 0)
104717f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    goto cleanup;
104887dc5e4e6f9471304ba85f508de30e664b484d3aCristy  if (raqm_set_par_direction(rq,(raqm_direction_t) draw_info->direction) == 0)
104917f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    goto cleanup;
10500d88ea3545d808eae9feeacdd57eec41db18d2baCristy  if (raqm_set_freetype_face(rq,face) == 0)
105117f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    goto cleanup;
10520d88ea3545d808eae9feeacdd57eec41db18d2baCristy  features=GetImageProperty(image,"type:features",exception);
10530d88ea3545d808eae9feeacdd57eec41db18d2baCristy  if (features != (const char *) NULL)
105417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    {
105517f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      char
105617f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy        breaker,
105717f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy        quote,
105817f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy        *token;
105917f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
106017f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      int
106117f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy        next,
106217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy        status_token;
106317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
106487dc5e4e6f9471304ba85f508de30e664b484d3aCristy      TokenInfo
106587dc5e4e6f9471304ba85f508de30e664b484d3aCristy        *token_info;
106687dc5e4e6f9471304ba85f508de30e664b484d3aCristy
106717f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      next=0;
106817f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      token_info=AcquireTokenInfo();
106987dc5e4e6f9471304ba85f508de30e664b484d3aCristy      token=AcquireString("");
10700d88ea3545d808eae9feeacdd57eec41db18d2baCristy      status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
10710d88ea3545d808eae9feeacdd57eec41db18d2baCristy        &breaker,&next,&quote);
107217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      while (status_token == 0)
10730d88ea3545d808eae9feeacdd57eec41db18d2baCristy      {
10740d88ea3545d808eae9feeacdd57eec41db18d2baCristy        raqm_add_font_feature(rq,token,strlen(token));
10750d88ea3545d808eae9feeacdd57eec41db18d2baCristy        status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
10760d88ea3545d808eae9feeacdd57eec41db18d2baCristy          &breaker,&next,&quote);
10770d88ea3545d808eae9feeacdd57eec41db18d2baCristy      }
107817f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      token_info=DestroyTokenInfo(token_info);
107917f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      token=DestroyString(token);
108017f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    }
10810d88ea3545d808eae9feeacdd57eec41db18d2baCristy  if (raqm_layout(rq) == 0)
108217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    goto cleanup;
10836720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  glyphs=raqm_get_glyphs(rq,&extent);
108417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  if (glyphs == (raqm_glyph_t *) NULL)
108517f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    {
10866720ed7fdc6908b46f213f43c316fcccab53dbcdCristy      extent=0;
108717f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      goto cleanup;
108817f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    }
10896720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(extent,sizeof(**grapheme));
109017f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  if (*grapheme == (GraphemeInfo *) NULL)
109117f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    {
10926720ed7fdc6908b46f213f43c316fcccab53dbcdCristy      extent=0;
109317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy      goto cleanup;
109417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    }
10956720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  for (i=0; i < (ssize_t) extent; i++)
10960d88ea3545d808eae9feeacdd57eec41db18d2baCristy  {
10970d88ea3545d808eae9feeacdd57eec41db18d2baCristy    (*grapheme)[i].index=glyphs[i].index;
10980d88ea3545d808eae9feeacdd57eec41db18d2baCristy    (*grapheme)[i].x_offset=glyphs[i].x_offset;
10990d88ea3545d808eae9feeacdd57eec41db18d2baCristy    (*grapheme)[i].x_advance=glyphs[i].x_advance;
11000d88ea3545d808eae9feeacdd57eec41db18d2baCristy    (*grapheme)[i].y_offset=glyphs[i].y_offset;
11010d88ea3545d808eae9feeacdd57eec41db18d2baCristy    (*grapheme)[i].cluster=glyphs[i].cluster;
11020d88ea3545d808eae9feeacdd57eec41db18d2baCristy  }
110317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
110417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristycleanup:
11050d88ea3545d808eae9feeacdd57eec41db18d2baCristy  raqm_destroy(rq);
11066720ed7fdc6908b46f213f43c316fcccab53dbcdCristy  return(extent);
110714c8ae4cf8fdcb1c1ed0f8fd1a5c3290414fe733Cristy#else
110887dc5e4e6f9471304ba85f508de30e664b484d3aCristy  const char
110987dc5e4e6f9471304ba85f508de30e664b484d3aCristy    *p;
111087dc5e4e6f9471304ba85f508de30e664b484d3aCristy
111169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  FT_Error
111269a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    ft_status;
111369a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
111469a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  register ssize_t
111569a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    i;
111669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
111769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  ssize_t
111869a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    last_glyph;
111969a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
1120751a6671c9b7480f3672a7ef6aa6e392f064b46ddirk  magick_unreferenced(exception);
1121751a6671c9b7480f3672a7ef6aa6e392f064b46ddirk
112291c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy  /*
11239da9d9c28f5574cc630eb8d8a48186f4951c4e33Cristy    Simple layout for bi-directional text (right-to-left or left-to-right).
112491c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy  */
11250d88ea3545d808eae9feeacdd57eec41db18d2baCristy  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(length+1,sizeof(**grapheme));
112617f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  if (*grapheme == (GraphemeInfo *) NULL)
112769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    return(0);
112869a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  last_glyph=0;
1129d45bfbb9ef2f6b90eb038b56d1a416b59c68abe0shamsa  p=text;
1130d45bfbb9ef2f6b90eb038b56d1a416b59c68abe0shamsa  for (i=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p), i++)
113169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  {
113287dc5e4e6f9471304ba85f508de30e664b484d3aCristy    (*grapheme)[i].index=(ssize_t) FT_Get_Char_Index(face,GetUTFCode(p));
113391c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    (*grapheme)[i].x_offset=0;
113491c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    (*grapheme)[i].y_offset=0;
113591c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    if (((*grapheme)[i].index != 0) && (last_glyph != 0))
113669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy      {
113769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy        if (FT_HAS_KERNING(face))
113869a0d3b5699c573f650e6b61f98ce4579d6f218cCristy          {
113969a0d3b5699c573f650e6b61f98ce4579d6f218cCristy            FT_Vector
114050d31568365a106c91ca4e827757fc2c806c6b16Cristy              kerning;
114169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
114206d4a5a39532c883052f98c8e870d015be8db1ccCristy            ft_status=FT_Get_Kerning(face,(FT_UInt) last_glyph,(FT_UInt)
114306d4a5a39532c883052f98c8e870d015be8db1ccCristy              (*grapheme)[i].index,ft_kerning_default,&kerning);
114469a0d3b5699c573f650e6b61f98ce4579d6f218cCristy            if (ft_status == 0)
114587dc5e4e6f9471304ba85f508de30e664b484d3aCristy              (*grapheme)[i-1].x_advance+=(FT_Pos) ((draw_info->direction ==
114687dc5e4e6f9471304ba85f508de30e664b484d3aCristy                RightToLeftDirection ? -1.0 : 1.0)*kerning.x);
114769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy          }
114891c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy      }
114986bacded5c30fe8f40e3a992c3b07a7fd610cc12dirk    ft_status=FT_Load_Glyph(face,(FT_UInt) (*grapheme)[i].index,flags);
115091c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    (*grapheme)[i].x_advance=face->glyph->advance.x;
1151d45bfbb9ef2f6b90eb038b56d1a416b59c68abe0shamsa    (*grapheme)[i].cluster=p-text;
115291c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    last_glyph=(*grapheme)[i].index;
115369a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  }
115469a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  return((size_t) i);
115514c8ae4cf8fdcb1c1ed0f8fd1a5c3290414fe733Cristy#endif
115669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy}
115769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
11593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo *draw_info)
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  AffineMatrix
11623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    affine;
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
1165151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    path[MagickPathExtent];
11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine=draw_info->affine;
11689c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy  (void) FormatLocaleString(path,MagickPathExtent,"C%g,%g %g,%g %g,%g",
11699c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    affine.tx+p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,affine.ty-
11709c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    q->y/64.0,affine.tx+to->x/64.0,affine.ty-to->y/64.0);
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ConcatenateString(&draw_info->primitive,path);
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(0);
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  AffineMatrix
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    affine;
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
1181151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    path[MagickPathExtent];
11823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine=draw_info->affine;
11849c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy  (void) FormatLocaleString(path,MagickPathExtent,"L%g,%g",affine.tx+to->x/64.0,
11859c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    affine.ty-to->y/64.0);
11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ConcatenateString(&draw_info->primitive,path);
11873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(0);
11883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11903ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
11923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  AffineMatrix
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    affine;
11943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
1196151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    path[MagickPathExtent];
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine=draw_info->affine;
11999c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy  (void) FormatLocaleString(path,MagickPathExtent,"M%g,%g",affine.tx+to->x/64.0,
12009c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    affine.ty-to->y/64.0);
12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ConcatenateString(&draw_info->primitive,path);
12023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(0);
12033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo *draw_info)
12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  AffineMatrix
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    affine;
12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
1212151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    path[MagickPathExtent];
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine=draw_info->affine;
12159c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy  (void) FormatLocaleString(path,MagickPathExtent,"Q%g,%g %g,%g",affine.tx+
12169c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,affine.ty-
12179c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    to->y/64.0);
12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ConcatenateString(&draw_info->primitive,path);
12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(0);
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
12235cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const char *encoding,const PointInfo *offset,TypeMetric *metrics,
12245cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  ExceptionInfo *exception)
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if !defined(FT_OPEN_PATHNAME)
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define FT_OPEN_PATHNAME  ft_open_pathname
12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  typedef struct _GlyphInfo
12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    FT_UInt
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      id;
12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    FT_Vector
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      origin;
12373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    FT_Glyph
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image;
12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  } GlyphInfo;
12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const char
12433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *value;
12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_BBox
12493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bounds;
12503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_BitmapGlyph
12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bitmap;
12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Encoding
12553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    encoding_type;
12563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Error
1258f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status;
12593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Face
12613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    face;
12623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Int32
12643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    flags;
12653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Library
12673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    library;
12683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Matrix
12703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    affine;
12713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Open_Args
12733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    args;
12743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FT_Vector
12763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    origin;
12773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GlyphInfo
12793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    glyph,
12803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    last_glyph;
12813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
128217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  GraphemeInfo
128317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    *grapheme;
128417f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy
1285f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  MagickBooleanType
1286f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    status;
1287f8f295fde25dd8b1a50470d53b641d5265c0871fcristy
12883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  PointInfo
12893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    point,
12903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resolution;
12913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register char
12933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
12943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
129569a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  register ssize_t
129669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    i;
129769a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
129869a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  size_t
129969a0d3b5699c573f650e6b61f98ce4579d6f218cCristy    length;
130069a0d3b5699c573f650e6b61f98ce4579d6f218cCristy
13019d314ff2c17a77996c05413c2013880387e50f0ecristy  ssize_t
13029d314ff2c17a77996c05413c2013880387e50f0ecristy    code,
13039d314ff2c17a77996c05413c2013880387e50f0ecristy    y;
13049d314ff2c17a77996c05413c2013880387e50f0ecristy
13053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  static FT_Outline_Funcs
13063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    OutlineMethods =
13073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (FT_Outline_MoveTo_Func) TraceMoveTo,
13093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (FT_Outline_LineTo_Func) TraceLineTo,
13103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
13113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (FT_Outline_CubicTo_Func) TraceCubicBezier,
13123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      0, 0
13133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    };
13143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
13152857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  unsigned char
13162857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    *utf8;
13172857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy
13183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
13193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize Truetype library.
13203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1321f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  ft_status=FT_Init_FreeType(&library);
1322f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  if (ft_status != 0)
13233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
13243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
13253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  args.flags=FT_OPEN_PATHNAME;
13263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->font == (char *) NULL)
13273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    args.pathname=ConstantString("helvetica");
13283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
13293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (*draw_info->font != '@')
13303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      args.pathname=ConstantString(draw_info->font);
13313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
13323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      args.pathname=ConstantString(draw_info->font+1);
13333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  face=(FT_Face) NULL;
1334f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  ft_status=FT_Open_Face(library,&args,(long) draw_info->face,&face);
13353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  args.pathname=DestroyString(args.pathname);
1336f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  if (ft_status != 0)
13373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) FT_Done_FreeType(library);
13395cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
1340efe601ce9ea5ad34ad0e8ad6e61d9be9b148b2a3cristy        "UnableToReadFont","`%s'",draw_info->font);
13415cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      return(RenderPostscript(image,draw_info,offset,metrics,exception));
13423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
13433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((draw_info->metrics != (char *) NULL) &&
13443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (IsPathAccessible(draw_info->metrics) != MagickFalse))
13453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) FT_Attach_File(face,draw_info->metrics);
13463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  encoding_type=ft_encoding_unicode;
1347f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  ft_status=FT_Select_Charmap(face,encoding_type);
1348f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  if ((ft_status != 0) && (face->num_charmaps != 0))
1349f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status=FT_Set_Charmap(face,face->charmaps[0]);
13503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (encoding != (const char *) NULL)
13513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"AdobeCustom") == 0)
13533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_adobe_custom;
13543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"AdobeExpert") == 0)
13553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_adobe_expert;
13563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"AdobeStandard") == 0)
13573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_adobe_standard;
13583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"AppleRoman") == 0)
13593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_apple_roman;
13603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"BIG5") == 0)
13613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_big5;
13623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"GB2312") == 0)
13633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_gb2312;
13643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Johab") == 0)
13653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_johab;
13663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#if defined(ft_encoding_latin_1)
13673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Latin-1") == 0)
13683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_latin_1;
13693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
13703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Latin-2") == 0)
13713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_latin_2;
13723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"None") == 0)
13733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_none;
13743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"SJIScode") == 0)
13753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_sjis;
13763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Symbol") == 0)
13773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_symbol;
13783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Unicode") == 0)
13793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_unicode;
13803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(encoding,"Wansung") == 0)
13813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        encoding_type=ft_encoding_wansung;
1382f8f295fde25dd8b1a50470d53b641d5265c0871fcristy      ft_status=FT_Select_Charmap(face,encoding_type);
1383f8f295fde25dd8b1a50470d53b641d5265c0871fcristy      if (ft_status != 0)
1384e3b2bb83e885eb35642c7029cedab50c5e1b263dcristy        {
1385e3b2bb83e885eb35642c7029cedab50c5e1b263dcristy          (void) FT_Done_Face(face);
1386e3b2bb83e885eb35642c7029cedab50c5e1b263dcristy          (void) FT_Done_FreeType(library);
1387e3b2bb83e885eb35642c7029cedab50c5e1b263dcristy          ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
1388e3b2bb83e885eb35642c7029cedab50c5e1b263dcristy        }
13893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
13903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
13913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Set text size.
13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
13933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resolution.x=DefaultResolution;
13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resolution.y=DefaultResolution;
13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->density != (char *) NULL)
13963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
13973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GeometryInfo
13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        geometry_info;
13993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickStatusType
140169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy        flags;
14023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
140369a0d3b5699c573f650e6b61f98ce4579d6f218cCristy      flags=ParseGeometry(draw_info->density,&geometry_info);
14043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resolution.x=geometry_info.rho;
14053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resolution.y=geometry_info.sigma;
140669a0d3b5699c573f650e6b61f98ce4579d6f218cCristy      if ((flags & SigmaValue) == 0)
14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resolution.y=resolution.x;
14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1409f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  ft_status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (FT_UInt) resolution.y);
14122245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy  if (ft_status != 0)
14132245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy    {
14142245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy      (void) FT_Done_Face(face);
14152245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy      (void) FT_Done_FreeType(library);
14162245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy      ThrowBinaryException(TypeError,"UnableToReadFont",draw_info->font);
14172245bab833d2ab8dc9a2ec3389f5e1bd72ca9ec3Cristy    }
14183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->pixels_per_em.x=face->size->metrics.x_ppem;
14193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->pixels_per_em.y=face->size->metrics.y_ppem;
14203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->ascent=(double) face->size->metrics.ascender/64.0;
14213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->descent=(double) face->size->metrics.descender/64.0;
14223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->width=0;
14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->origin.x=0;
14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->origin.y=0;
14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->height=(double) face->size->metrics.height/64.0;
14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->max_advance=0.0;
14273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (face->size->metrics.max_advance > MagickEpsilon)
14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x1=0.0;
14303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y1=metrics->descent;
14313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x2=metrics->ascent+metrics->descent;
14323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y2=metrics->ascent+metrics->descent;
14333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->underline_position=face->underline_position/64.0;
14343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->underline_thickness=face->underline_thickness/64.0;
143571709bfb884744dbf7c9030810cc8599600ab7d3cristy  if ((draw_info->text == (char *) NULL) || (*draw_info->text == '\0'))
14363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
14373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) FT_Done_Face(face);
14383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) FT_Done_FreeType(library);
14393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickTrue);
14403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
14413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
14423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Compute bounding box.
14433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
14443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
14453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
1446e7f5109f30fc7242d04a26174a9138483dda5b6acristy      "font-encoding %s; text-encoding %s; pointsize %g",
14473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->font != (char *) NULL ? draw_info->font : "none",
14483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      encoding != (char *) NULL ? encoding : "none",
14493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
14503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->pointsize);
14513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  flags=FT_LOAD_NO_BITMAP;
145255a804e2631f770f45d3a671076b0dfe29fdf188cristy  if (draw_info->text_antialias == MagickFalse)
14534f9709e37140157c7845a03f3612534081a5b540cristy    flags|=FT_LOAD_TARGET_MONO;
145455a804e2631f770f45d3a671076b0dfe29fdf188cristy  else
145555a804e2631f770f45d3a671076b0dfe29fdf188cristy    {
1456a89189d6e227db53ecff8624fb6b4388560d9b4acristy#if defined(FT_LOAD_TARGET_LIGHT)
145755a804e2631f770f45d3a671076b0dfe29fdf188cristy      flags|=FT_LOAD_TARGET_LIGHT;
1458a89189d6e227db53ecff8624fb6b4388560d9b4acristy#elif defined(FT_LOAD_TARGET_LCD)
1459a89189d6e227db53ecff8624fb6b4388560d9b4acristy      flags|=FT_LOAD_TARGET_LCD;
146055a804e2631f770f45d3a671076b0dfe29fdf188cristy#endif
146155a804e2631f770f45d3a671076b0dfe29fdf188cristy    }
1462d15e65928aec551b7388c2863de3e3e628e2e0ddcristy  value=GetImageProperty(image,"type:hinting",exception);
146333204240c3ef57786ee59c2692ffe8ffdce97bf9cristy  if ((value != (const char *) NULL) && (LocaleCompare(value,"off") == 0))
14643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    flags|=FT_LOAD_NO_HINTING;
14653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  glyph.id=0;
14663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  glyph.image=NULL;
14673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  last_glyph.id=0;
14683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  last_glyph.image=NULL;
14693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  origin.x=0;
14703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  origin.y=0;
14713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine.xx=65536L;
14723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine.yx=0L;
14733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine.xy=0L;
14743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  affine.yy=65536L;
14753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->render != MagickFalse)
14763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
14773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
14783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
14793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
14803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
14813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
14823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
14839c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy  if (annotate_info->dash_pattern != (double *) NULL)
14849c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    annotate_info->dash_pattern[0]=0.0;
14853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloneString(&annotate_info->primitive,"path '");
1486ba4ad2dfd3d5b883e8aa7d6e8b4e6f9613dc3c45Cristy  status=MagickTrue;
14873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->render != MagickFalse)
14883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
14893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->storage_class != DirectClass)
14905cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy        (void) SetImageStorageClass(image,DirectClass,exception);
149117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      if (image->alpha_trait == UndefinedPixelTrait)
1492a64d8007a138a0efeedc286de10538f2e8c7fe6bcristy        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
14933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
14943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  point.x=0.0;
14953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  point.y=0.0;
14963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
1497bd51246ae63047fa139606f6c6862ff989ab1fbdcristy    if (GetUTFCode(p) < 0)
1498bd51246ae63047fa139606f6c6862ff989ab1fbdcristy      break;
14992857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  utf8=(unsigned char *) NULL;
1500d913ea1f524066a6a8bf3d046755a5c0f7eb471fcristy  if (GetUTFCode(p) == 0)
15012857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    p=draw_info->text;
15022857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  else
1503bd51246ae63047fa139606f6c6862ff989ab1fbdcristy    {
15042857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      utf8=ConvertLatin1ToUTF8((unsigned char *) draw_info->text);
15052857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      if (utf8 != (unsigned char *) NULL)
1506c9b129570a277337cf0e887229741497e2ead5cfcristy        p=(char *) utf8;
15072857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    }
150817f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  grapheme=(GraphemeInfo *) NULL;
150987dc5e4e6f9471304ba85f508de30e664b484d3aCristy  length=ComplexTextLayout(image,draw_info,p,strlen(p),face,flags,&grapheme,
15105eb36084e86f5ab4a877c2b31c19880b0b0b02e3Cristy    exception);
151169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  code=0;
151269a0d3b5699c573f650e6b61f98ce4579d6f218cCristy  for (i=0; i < (ssize_t) length; i++)
15132857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  {
15142857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    /*
15152857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      Render UTF-8 sequence.
15162857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    */
151786bacded5c30fe8f40e3a992c3b07a7fd610cc12dirk    glyph.id=(FT_UInt) grapheme[i].index;
15182857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if (glyph.id == 0)
15192857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      glyph.id=FT_Get_Char_Index(face,'?');
15202857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((glyph.id != 0) && (last_glyph.id != 0))
152169a0d3b5699c573f650e6b61f98ce4579d6f218cCristy      origin.x+=(FT_Pos) (64.0*draw_info->kerning);
15222857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    glyph.origin=origin;
152386bacded5c30fe8f40e3a992c3b07a7fd610cc12dirk    glyph.origin.x+=(FT_Pos) grapheme[i].x_offset;
152486bacded5c30fe8f40e3a992c3b07a7fd610cc12dirk    glyph.origin.y+=(FT_Pos) grapheme[i].y_offset;
1525f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status=FT_Load_Glyph(face,glyph.id,flags);
1526f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    if (ft_status != 0)
15272857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      continue;
1528f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status=FT_Get_Glyph(face->glyph,&glyph.image);
1529f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    if (ft_status != 0)
15302857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      continue;
1531f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->outline,
15322857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      &bounds);
1533f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    if (ft_status != 0)
15342857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      continue;
15352857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
15368e1dd685b642e235234931b24d11045041254eafCristy      if (bounds.xMin != 0)
15378e1dd685b642e235234931b24d11045041254eafCristy        metrics->bounds.x1=(double) bounds.xMin;
15382857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
15398e1dd685b642e235234931b24d11045041254eafCristy      if (bounds.yMin != 0)
15408e1dd685b642e235234931b24d11045041254eafCristy        metrics->bounds.y1=(double) bounds.yMin;
15412857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
15428e1dd685b642e235234931b24d11045041254eafCristy      if (bounds.xMax != 0)
15438e1dd685b642e235234931b24d11045041254eafCristy        metrics->bounds.x2=(double) bounds.xMax;
15442857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
15458e1dd685b642e235234931b24d11045041254eafCristy      if (bounds.yMax != 0)
15468e1dd685b642e235234931b24d11045041254eafCristy        metrics->bounds.y2=(double) bounds.yMax;
15479c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy    if (((draw_info->stroke.alpha != TransparentAlpha) ||
15489c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy         (draw_info->stroke_pattern != (Image *) NULL)) &&
15499c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        ((status != MagickFalse) && (draw_info->render != MagickFalse)))
1550f8f295fde25dd8b1a50470d53b641d5265c0871fcristy      {
15519c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        /*
15529c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy          Trace the glyph.
15539c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        */
15549c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        annotate_info->affine.tx=glyph.origin.x/64.0;
155569a0d3b5699c573f650e6b61f98ce4579d6f218cCristy        annotate_info->affine.ty=(-glyph.origin.y/64.0);
15569c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->outline,
15579c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy          &OutlineMethods,annotate_info);
15589c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy      }
15592857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    FT_Vector_Transform(&glyph.origin,&affine);
15602857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1561f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    ft_status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
15622857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      (FT_Vector *) NULL,MagickTrue);
1563f8f295fde25dd8b1a50470d53b641d5265c0871fcristy    if (ft_status != 0)
15642857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      continue;
15652857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    bitmap=(FT_BitmapGlyph) glyph.image;
15662857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    point.x=offset->x+bitmap->left;
15672f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy    if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
15682f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy      point.x=offset->x+(origin.x >> 6);
15692857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    point.y=offset->y-bitmap->top;
15702857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if (draw_info->render != MagickFalse)
15712857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      {
15722857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        CacheView
15732857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          *image_view;
1574bd51246ae63047fa139606f6c6862ff989ab1fbdcristy
15752f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy        register unsigned char
1576fa589d6096099562cbc2bc14e508931968a8c055dirk          *r;
15772f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy
15782857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        /*
15792857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          Rasterize the glyph.
15802857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        */
158146ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy        image_view=AcquireAuthenticCacheView(image,exception);
1582fa589d6096099562cbc2bc14e508931968a8c055dirk        r=bitmap->bitmap.buffer;
1583bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++)
15842857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        {
158587dc5e4e6f9471304ba85f508de30e664b484d3aCristy          double
158687dc5e4e6f9471304ba85f508de30e664b484d3aCristy            fill_opacity;
158787dc5e4e6f9471304ba85f508de30e664b484d3aCristy
1588bd51246ae63047fa139606f6c6862ff989ab1fbdcristy          MagickBooleanType
15892857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            active,
15902857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            sync;
1591bd51246ae63047fa139606f6c6862ff989ab1fbdcristy
1592101ab708b0574518ac5715da4d3915400e9df79acristy          PixelInfo
15932857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            fill_color;
15942857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy
15954c08aed51c5899665ade97263692328eea4af106cristy          register Quantum
159605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk            *magick_restrict q;
15972857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy
15988815806717c3b3e2b4f8700b4cc18b751bd3c23fcristy          register ssize_t
15998815806717c3b3e2b4f8700b4cc18b751bd3c23fcristy            x;
16008815806717c3b3e2b4f8700b4cc18b751bd3c23fcristy
160173ce31bc9ca5fc03ff0cef499e58ab2973add52ccristy          ssize_t
16022f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy            n,
160373ce31bc9ca5fc03ff0cef499e58ab2973add52ccristy            x_offset,
160473ce31bc9ca5fc03ff0cef499e58ab2973add52ccristy            y_offset;
160573ce31bc9ca5fc03ff0cef499e58ab2973add52ccristy
16062857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          if (status == MagickFalse)
16072857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            continue;
1608bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          x_offset=(ssize_t) ceil(point.x-0.5);
1609bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          y_offset=(ssize_t) ceil(point.y+y-0.5);
1610bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
16112857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            continue;
16124c08aed51c5899665ade97263692328eea4af106cristy          q=(Quantum *) NULL;
1613bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
16142857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            active=MagickFalse;
16152857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          else
16162857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            {
16172857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
16182857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                bitmap->bitmap.width,1,exception);
16194c08aed51c5899665ade97263692328eea4af106cristy              active=q != (Quantum *) NULL ? MagickTrue : MagickFalse;
16202857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            }
1621854209afe797f1a6ecec8679889302af4d4b0faccristy          n=y*bitmap->bitmap.pitch-1;
1622854209afe797f1a6ecec8679889302af4d4b0faccristy          for (x=0; x < (ssize_t) bitmap->bitmap.width; x++)
1623bd51246ae63047fa139606f6c6862ff989ab1fbdcristy          {
1624854209afe797f1a6ecec8679889302af4d4b0faccristy            n++;
16252857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            x_offset++;
16262f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy            if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
16273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              {
1628dcf8f73b2c558978add85031fe65f2607bbca057cristy                if (q != (Quantum *) NULL)
1629dcf8f73b2c558978add85031fe65f2607bbca057cristy                  q+=GetPixelChannels(image);
16302857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                continue;
16313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              }
16322f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy            if (bitmap->bitmap.pixel_mode != ft_pixel_mode_mono)
1633fa589d6096099562cbc2bc14e508931968a8c055dirk              fill_opacity=(double) (r[n])/(bitmap->bitmap.num_grays-1);
16342f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy            else
1635fa589d6096099562cbc2bc14e508931968a8c055dirk              fill_opacity=((r[(x >> 3)+y*bitmap->bitmap.pitch] &
16362f5b5c7c0813cc6f696a4dfc00aaf62e2dfb2a23cristy                (1 << (~x & 0x07)))) == 0 ? 0.0 : 1.0;
16372857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            if (draw_info->text_antialias == MagickFalse)
16382857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy              fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
16392857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            if (active == MagickFalse)
16402857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
16412857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                exception);
16426193b86c0b59030b647a10c75f37ec82d73e3695cristy            if (q == (Quantum *) NULL)
16439c5171c13c7186088b10ec322e199f60e455a7e1cristy              continue;
1644ec061ec752ff58a96a5de680b18e43fb8beea7c0cristy            GetPixelInfo(image,&fill_color);
164550be538de7d724dfbd0cba7d434d1404b49ce90ddirk            GetFillColor(draw_info,x_offset,y_offset,&fill_color,exception);
16464c08aed51c5899665ade97263692328eea4af106cristy            fill_opacity=fill_opacity*fill_color.alpha;
16474c08aed51c5899665ade97263692328eea4af106cristy            CompositePixelOver(image,&fill_color,fill_opacity,q,
16484c08aed51c5899665ade97263692328eea4af106cristy              GetPixelAlpha(image,q),q);
16492857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            if (active == MagickFalse)
16502857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy              {
16512857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                sync=SyncCacheViewAuthenticPixels(image_view,exception);
16522857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                if (sync == MagickFalse)
16532857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy                  status=MagickFalse;
16542857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy              }
1655ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy            q+=GetPixelChannels(image);
16563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
16572857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          sync=SyncCacheViewAuthenticPixels(image_view,exception);
16582857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy          if (sync == MagickFalse)
16592857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy            status=MagickFalse;
16603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
16612857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        image_view=DestroyCacheView(image_view);
16629c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy        if (((draw_info->stroke.alpha != TransparentAlpha) ||
16639c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy             (draw_info->stroke_pattern != (Image *) NULL)) &&
16649c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            (status != MagickFalse))
16659c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy          {
16669c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            /*
16679c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy              Draw text stroke.
16689c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            */
16699c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            annotate_info->linejoin=RoundJoin;
16709c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            annotate_info->affine.tx=offset->x;
16719c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            annotate_info->affine.ty=offset->y;
16729c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            (void) ConcatenateString(&annotate_info->primitive,"'");
16739c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            (void) DrawImage(image,annotate_info,exception);
16749c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy            (void) CloneString(&annotate_info->primitive,"path '");
16759c282cc8767db9a3fafe507398b52fbdd0c03d9fCristy          }
16762857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      }
16772857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    if ((bitmap->left+bitmap->bitmap.width) > metrics->width)
16782857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy      metrics->width=bitmap->left+bitmap->bitmap.width;
1679aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy    if ((fabs(draw_info->interword_spacing) >= MagickEpsilon) &&
168091c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy        (IsUTFSpace(GetUTFCode(p+grapheme[i].cluster)) != MagickFalse) &&
16812857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy        (IsUTFSpace(code) == MagickFalse))
168269a0d3b5699c573f650e6b61f98ce4579d6f218cCristy      origin.x+=(FT_Pos) (64.0*draw_info->interword_spacing);
16832857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    else
168491c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy      origin.x+=(FT_Pos) grapheme[i].x_advance;
1685aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy    metrics->origin.x=(double) origin.x;
1686aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy    metrics->origin.y=(double) origin.y;
1687bd5a96cd2b69f218f85a7adc306296a736f91a56cristy    if (last_glyph.id != 0)
1688bd5a96cd2b69f218f85a7adc306296a736f91a56cristy      FT_Done_Glyph(last_glyph.image);
16892857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    last_glyph=glyph;
169091c2741e03e3e692f6fe04eb02d059edbc0edb90Cristy    code=GetUTFCode(p+grapheme[i].cluster);
16912857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  }
169217f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy  if (grapheme != (GraphemeInfo *) NULL)
169317f8c7215fff88fc1362e9d98f4ccdffb6a74950Cristy    grapheme=(GraphemeInfo *) RelinquishMagickMemory(grapheme);
16942857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy  if (utf8 != (unsigned char *) NULL)
16952857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy    utf8=(unsigned char *) RelinquishMagickMemory(utf8);
1696bd5a96cd2b69f218f85a7adc306296a736f91a56cristy  if (last_glyph.id != 0)
1697bd5a96cd2b69f218f85a7adc306296a736f91a56cristy    FT_Done_Glyph(last_glyph.image);
16983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
16993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine font metrics.
17003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
17013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  glyph.id=FT_Get_Char_Index(face,'_');
17023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  glyph.origin=origin;
1703f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  ft_status=FT_Load_Glyph(face,glyph.id,flags);
1704f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  if (ft_status == 0)
17053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1706f8f295fde25dd8b1a50470d53b641d5265c0871fcristy      ft_status=FT_Get_Glyph(face->glyph,&glyph.image);
1707f8f295fde25dd8b1a50470d53b641d5265c0871fcristy      if (ft_status == 0)
17083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
1709f8f295fde25dd8b1a50470d53b641d5265c0871fcristy          ft_status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->
1710f8f295fde25dd8b1a50470d53b641d5265c0871fcristy            outline,&bounds);
1711f8f295fde25dd8b1a50470d53b641d5265c0871fcristy          if (ft_status == 0)
17123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
17133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              FT_Vector_Transform(&glyph.origin,&affine);
17143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1715f8f295fde25dd8b1a50470d53b641d5265c0871fcristy              ft_status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
17163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                (FT_Vector *) NULL,MagickTrue);
17173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              bitmap=(FT_BitmapGlyph) glyph.image;
17183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              if (bitmap->left > metrics->width)
17193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                metrics->width=bitmap->left;
17203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
17213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
1722e2c81adf02cbe4bb92991389437a2a1daf8ed313cristy      FT_Done_Glyph(glyph.image);
17233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
17243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x1/=64.0;
17253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y1/=64.0;
17263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x2/=64.0;
17273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y2/=64.0;
17283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->origin.x/=64.0;
17293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->origin.y/=64.0;
17303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
17313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Relinquish resources.
17323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
17333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyDrawInfo(annotate_info);
17343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) FT_Done_Face(face);
17353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) FT_Done_FreeType(library);
1736f8f295fde25dd8b1a50470d53b641d5265c0871fcristy  return(status);
17373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
17383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#else
17393ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
17403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const char *magick_unused(encoding),const PointInfo *offset,
17415cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  TypeMetric *metrics,ExceptionInfo *exception)
17423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
17435cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  (void) ThrowMagickException(exception,GetMagickModule(),
1744e5b39652d8d21bc3940d83b8d6088d4070a8a34aanthony    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (Freetype)",
1745ee08182aae410ed78e712a845bee7e51eedf73f3cristy    draw_info->font != (char *) NULL ? draw_info->font : "none");
1746e3b062a2f84bdc16645c3ef9de153b2c6f44d04ccristy  return(RenderPostscript(image,draw_info,offset,metrics,exception));
17473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
17483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
17493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
17513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e n d e r P o s t s c r i p t                                           %
17563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RenderPostscript() renders text on the image with a Postscript font.  It
17623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  also returns the bounding box of the text relative to the image.
17633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RenderPostscript method is:
17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
17675cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
17683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
17703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
17723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
17743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o offset: (x,y) location of text relative to image.
17763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: bounding box of text.
17783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17795cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
17805cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
17813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
17823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
178334838f589a9c3dff858321d07926c66f7f7fa2f7Cristystatic char *EscapeParenthesis(const char *source)
17843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
17853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
178634838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    *destination;
17873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register char
178934838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    *q;
17903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
179134838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  register const char
179234838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    *p;
17933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
179534838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    length;
17963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
179734838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  assert(source != (const char *) NULL);
179834838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  length=0;
179934838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  for (p=source; *p != '\0'; p++)
18003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
180134838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    if ((*p == '\\') || (*p == '(') || (*p == ')'))
18023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
180334838f589a9c3dff858321d07926c66f7f7fa2f7Cristy        if (~length < 1)
180434838f589a9c3dff858321d07926c66f7f7fa2f7Cristy          ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
180534838f589a9c3dff858321d07926c66f7f7fa2f7Cristy        length++;
18063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
180734838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    length++;
180834838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  }
180934838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  destination=(char *) NULL;
181034838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  if (~length >= (MagickPathExtent-1))
181134838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
181234838f589a9c3dff858321d07926c66f7f7fa2f7Cristy      sizeof(*destination));
181334838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  if (destination == (char *) NULL)
181434838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
181534838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  *destination='\0';
181634838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  q=destination;
181734838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  for (p=source; *p != '\0'; p++)
181834838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  {
181934838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    if ((*p == '\\') || (*p == '(') || (*p == ')'))
182034838f589a9c3dff858321d07926c66f7f7fa2f7Cristy      *q++='\\';
182134838f589a9c3dff858321d07926c66f7f7fa2f7Cristy    *q++=(*p);
18223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
182334838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  *q='\0';
182434838f589a9c3dff858321d07926c66f7f7fa2f7Cristy  return(destination);
18253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
18263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18273ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType RenderPostscript(Image *image,
18285cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics,
18295cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  ExceptionInfo *exception)
18303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
18313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
1832151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    filename[MagickPathExtent],
1833151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    geometry[MagickPathExtent],
18343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *text;
18353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FILE
18373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *file;
18383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
18403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_image;
18413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ImageInfo
18433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *annotate_info;
18443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  int
18463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    unique_file;
18473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
18493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    identity;
18503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  PointInfo
18523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    extent,
18533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    point,
18543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resolution;
18553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1856bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
18573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
18583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
185914d712974a2c2cd2aebf8db11c7ca686bb67596fcristy  size_t
186014d712974a2c2cd2aebf8db11c7ca686bb67596fcristy    length;
186114d712974a2c2cd2aebf8db11c7ca686bb67596fcristy
18629d314ff2c17a77996c05413c2013880387e50f0ecristy  ssize_t
18639d314ff2c17a77996c05413c2013880387e50f0ecristy    y;
18649d314ff2c17a77996c05413c2013880387e50f0ecristy
18653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
18663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Render label with a Postscript font.
18673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
18683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
18693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
1870e7f5109f30fc7242d04a26174a9138483dda5b6acristy      "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
18713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->font : "none",draw_info->pointsize);
18723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  file=(FILE *) NULL;
18733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unique_file=AcquireUniqueFileResource(filename);
18743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (unique_file != -1)
18753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    file=fdopen(unique_file,"wb");
18763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((unique_file == -1) || (file == (FILE *) NULL))
18773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
18785cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",filename);
18793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
18803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1881b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"%%!PS-Adobe-3.0\n");
1882b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"/ReencodeType\n");
1883b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"{\n");
1884b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"  findfont dup length\n");
1885b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,
18863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    "  dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
1887b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,
18883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    "  /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
1889b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"} bind def\n");
18903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
18913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Sample to compute bounding box.
18923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1893aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy  identity=(fabs(draw_info->affine.sx-draw_info->affine.sy) < MagickEpsilon) &&
1894aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy    (fabs(draw_info->affine.rx) < MagickEpsilon) &&
1895aa83c2c383e62bd5342c0d38dc5f6e746998bde8cristy    (fabs(draw_info->affine.ry) < MagickEpsilon) ? MagickTrue : MagickFalse;
18963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  extent.x=0.0;
18973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  extent.y=0.0;
189814d712974a2c2cd2aebf8db11c7ca686bb67596fcristy  length=strlen(draw_info->text);
189914d712974a2c2cd2aebf8db11c7ca686bb67596fcristy  for (i=0; i <= (ssize_t) (length+2); i++)
19003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
19013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
19023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->affine.ry*2.0*draw_info->pointsize);
19033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
19043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      draw_info->affine.sy*2.0*draw_info->pointsize);
19053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (point.x > extent.x)
19063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      extent.x=point.x;
19073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (point.y > extent.y)
19083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      extent.y=point.y;
19093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1910b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"%g %g moveto\n",identity  != MagickFalse ? 0.0 :
19113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    extent.x/2.0,extent.y/2.0);
1912b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"%g %g scale\n",draw_info->pointsize,
19133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    draw_info->pointsize);
19143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (strchr(draw_info->font,'/') != (char *) NULL))
1916b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy    (void) FormatLocaleFile(file,
19173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
19183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
19191e604812fad85bb96f757a2393015ae3d061c39acristy    (void) FormatLocaleFile(file,
19201e604812fad85bb96f757a2393015ae3d061c39acristy      "/%s-ISO dup /%s ReencodeType findfont setfont\n",draw_info->font,
19211e604812fad85bb96f757a2393015ae3d061c39acristy      draw_info->font);
1922b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"[%g %g %g %g 0 0] concat\n",
19238cd5b3193212b4aebce08c4e7afbb66b09778029cristy    draw_info->affine.sx,-draw_info->affine.rx,-draw_info->affine.ry,
19248cd5b3193212b4aebce08c4e7afbb66b09778029cristy    draw_info->affine.sy);
19253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  text=EscapeParenthesis(draw_info->text);
19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (identity == MagickFalse)
19271e604812fad85bb96f757a2393015ae3d061c39acristy    (void) FormatLocaleFile(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",
19281e604812fad85bb96f757a2393015ae3d061c39acristy      text);
1929b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"(%s) show\n",text);
19303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  text=DestroyString(text);
1931b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleFile(file,"showpage\n");
19323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) fclose(file);
1933151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy  (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0!",
1934e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy    floor(extent.x+0.5),floor(extent.y+0.5));
19353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=AcquireImageInfo();
1936151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy  (void) FormatLocaleString(annotate_info->filename,MagickPathExtent,"ps:%s",
19373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filename);
19383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloneString(&annotate_info->page,geometry);
19393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->density != (char *) NULL)
19403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) CloneString(&annotate_info->density,draw_info->density);
19413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info->antialias=draw_info->text_antialias;
19425cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  annotate_image=ReadImage(annotate_info,exception);
19435cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy  CatchException(exception);
19443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_info=DestroyImageInfo(annotate_info);
19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) RelinquishUniqueFileResource(filename);
19463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (annotate_image == (Image *) NULL)
19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
194855cb9f15b804f98ac7d37615b8f5f8888fc792f4cristy  (void) NegateImage(annotate_image,MagickFalse,exception);
19493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resolution.x=DefaultResolution;
19503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resolution.y=DefaultResolution;
19513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->density != (char *) NULL)
19523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GeometryInfo
19543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        geometry_info;
19553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickStatusType
19573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        flags;
19583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      flags=ParseGeometry(draw_info->density,&geometry_info);
19603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resolution.x=geometry_info.rho;
19613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resolution.y=geometry_info.sigma;
19623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ((flags & SigmaValue) == 0)
19633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resolution.y=resolution.x;
19643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (identity == MagickFalse)
1966e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy    (void) TransformImage(&annotate_image,"0x0",(char *) NULL,exception);
19673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
19683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      RectangleInfo
19703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        crop_info;
19713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19725cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy      crop_info=GetImageBoundingBox(annotate_image,exception);
1973bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      crop_info.height=(size_t) ((resolution.y/DefaultResolution)*
19743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
1975bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      crop_info.y=(ssize_t) ceil((resolution.y/DefaultResolution)*extent.y/8.0-
197606609eef311d5af857f65f20ed3af6860c1994becristy        0.5);
1977151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy      (void) FormatLocaleString(geometry,MagickPathExtent,
19786d8abbae64da926477182d86d5007bc2c5a8b979cristy        "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
1979e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy        crop_info.height,(double) crop_info.x,(double) crop_info.y);
1980e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy      (void) TransformImage(&annotate_image,geometry,(char *) NULL,exception);
19813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
19833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ExpandAffine(&draw_info->affine)*draw_info->pointsize;
19843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->pixels_per_em.y=metrics->pixels_per_em.x;
19853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->ascent=metrics->pixels_per_em.x;
19863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->descent=metrics->pixels_per_em.y/-5.0;
19873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->width=(double) annotate_image->columns/
19883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ExpandAffine(&draw_info->affine);
19893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->height=1.152*metrics->pixels_per_em.x;
19903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->max_advance=metrics->pixels_per_em.x;
19913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x1=0.0;
19923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y1=metrics->descent;
19933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.x2=metrics->ascent+metrics->descent;
19943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->bounds.y2=metrics->ascent+metrics->descent;
19953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->underline_position=(-2.0);
19963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  metrics->underline_thickness=1.0;
19973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (draw_info->render == MagickFalse)
19983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      annotate_image=DestroyImage(annotate_image);
20003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickTrue);
20013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
20024c08aed51c5899665ade97263692328eea4af106cristy  if (draw_info->fill.alpha != TransparentAlpha)
20033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2004bd65948def60e897a2641d9503470945c304f46fcristy      CacheView
2005bd65948def60e897a2641d9503470945c304f46fcristy        *annotate_view;
2006bd65948def60e897a2641d9503470945c304f46fcristy
20073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickBooleanType
20083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        sync;
20093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2010101ab708b0574518ac5715da4d3915400e9df79acristy      PixelInfo
20113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        fill_color;
20123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
20143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Render fill color.
20153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
201617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      if (image->alpha_trait == UndefinedPixelTrait)
201763240888c3975789a09c2494a4654b523931df96cristy        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
201817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      if (annotate_image->alpha_trait == UndefinedPixelTrait)
201963240888c3975789a09c2494a4654b523931df96cristy        (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel,
202063240888c3975789a09c2494a4654b523931df96cristy          exception);
20213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      fill_color=draw_info->fill;
202246ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy      annotate_view=AcquireAuthenticCacheView(annotate_image,exception);
2023bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (y=0; y < (ssize_t) annotate_image->rows; y++)
20243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
2025bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        register ssize_t
20263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          x;
20273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20284c08aed51c5899665ade97263692328eea4af106cristy        register Quantum
202905d2ff7ebf21f659f5b11e45afb294e152f4330cdirk          *magick_restrict q;
20303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
20323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          1,exception);
20336193b86c0b59030b647a10c75f37ec82d73e3695cristy        if (q == (Quantum *) NULL)
20343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
2035bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (x=0; x < (ssize_t) annotate_image->columns; x++)
20363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
203750be538de7d724dfbd0cba7d434d1404b49ce90ddirk          GetFillColor(draw_info,x,y,&fill_color,exception);
203855cb9f15b804f98ac7d37615b8f5f8888fc792f4cristy          SetPixelAlpha(annotate_image,ClampToQuantum((((double) QuantumScale*
203955cb9f15b804f98ac7d37615b8f5f8888fc792f4cristy            GetPixelIntensity(annotate_image,q)*fill_color.alpha))),q);
20404c08aed51c5899665ade97263692328eea4af106cristy          SetPixelRed(annotate_image,fill_color.red,q);
20414c08aed51c5899665ade97263692328eea4af106cristy          SetPixelGreen(annotate_image,fill_color.green,q);
20424c08aed51c5899665ade97263692328eea4af106cristy          SetPixelBlue(annotate_image,fill_color.blue,q);
2043ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy          q+=GetPixelChannels(annotate_image);
20443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
20453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
20463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (sync == MagickFalse)
20473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
20483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
20493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      annotate_view=DestroyCacheView(annotate_view);
205039172408bad7ef2ef00a815fa9abf9979e7857cbcristy      (void) CompositeImage(image,annotate_image,OverCompositeOp,MagickTrue,
2051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        (ssize_t) ceil(offset->x-0.5),(ssize_t) ceil(offset->y-(metrics->ascent+
2052e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy        metrics->descent)-0.5),exception);
20533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
20543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  annotate_image=DestroyImage(annotate_image);
20553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
20563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
20573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
20593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+   R e n d e r X 1 1                                                         %
20643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RenderX11() renders text on the image with an X11 font.  It also returns the
20703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  bounding box of the text relative to the image.
20713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RenderX11 method is:
20733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
20755cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%        const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
20763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
20783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
20803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
20823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o offset: (x,y) location of text relative to image.
20843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o metrics: bounding box of text.
20863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20875cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%    o exception: return any errors or warnings in this structure.
20885cbc016effaa2d7ee617f46ca0a2371533d4ae17cristy%
20893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2090cc168c2dcad169c22f123761f2f53d867fb2f149cristystatic MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
2091cc168c2dcad169c22f123761f2f53d867fb2f149cristy  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
20923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
20933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
20943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
20953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2096d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  if (annotate_semaphore == (SemaphoreInfo *) NULL)
209704b11db5504ecdf205114ae7e9e68774a1ff0b9bcristy    ActivateSemaphoreInfo(&annotate_semaphore);
2098d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  LockSemaphoreInfo(annotate_semaphore);
2099534d0a353b31242ce2f7b26c4eb4fe53f914d0f5cristy  status=XRenderImage(image,draw_info,offset,metrics,exception);
2100d7ecaca521e2840f1308b758f7b3a3a9fd2dce38cristy  UnlockSemaphoreInfo(annotate_semaphore);
2101534d0a353b31242ce2f7b26c4eb4fe53f914d0f5cristy  return(status);
21023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2103