annotate.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %           AAA   N   N  N   N   OOO   TTTTT   AAA   TTTTT  EEEEE             %
00007 %          A   A  NN  N  NN  N  O   O    T    A   A    T    E                 %
00008 %          AAAAA  N N N  N N N  O   O    T    AAAAA    T    EEE               %
00009 %          A   A  N  NN  N  NN  O   O    T    A   A    T    E                 %
00010 %          A   A  N   N  N   N   OOO     T    A   A    T    EEEEE             %
00011 %                                                                             %
00012 %                                                                             %
00013 %                   MagickCore Image Annotation Methods                       %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 % Digital Applications (www.digapp.com) contributed the stroked text algorithm.
00037 % It was written by Leonard Rosenthol.
00038 %
00039 %
00040 */
00041 
00042 /*
00043   Include declarations.
00044 */
00045 #include "magick/studio.h"
00046 #include "magick/annotate.h"
00047 #include "magick/cache-view.h"
00048 #include "magick/client.h"
00049 #include "magick/color.h"
00050 #include "magick/color-private.h"
00051 #include "magick/composite.h"
00052 #include "magick/composite-private.h"
00053 #include "magick/constitute.h"
00054 #include "magick/draw.h"
00055 #include "magick/draw-private.h"
00056 #include "magick/exception.h"
00057 #include "magick/exception-private.h"
00058 #include "magick/gem.h"
00059 #include "magick/geometry.h"
00060 #include "magick/image-private.h"
00061 #include "magick/log.h"
00062 #include "magick/quantum.h"
00063 #include "magick/quantum-private.h"
00064 #include "magick/property.h"
00065 #include "magick/resource_.h"
00066 #include "magick/statistic.h"
00067 #include "magick/string_.h"
00068 #include "magick/token-private.h"
00069 #include "magick/transform.h"
00070 #include "magick/type.h"
00071 #include "magick/utility.h"
00072 #include "magick/xwindow-private.h"
00073 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00074 #if defined(__MINGW32__)
00075 #  undef interface
00076 #endif
00077 #if defined(MAGICKCORE_HAVE_FT2BUILD_H)
00078 #  include <ft2build.h>
00079 #endif
00080 #if defined(FT_FREETYPE_H)
00081 #  include FT_FREETYPE_H
00082 #else
00083 #  include <freetype/freetype.h>
00084 #endif
00085 #if defined(FT_GLYPH_H)
00086 #  include FT_GLYPH_H
00087 #else
00088 #  include <freetype/ftglyph.h>
00089 #endif
00090 #if defined(FT_OUTLINE_H)
00091 #  include FT_OUTLINE_H
00092 #else
00093 #  include <freetype/ftoutln.h>
00094 #endif
00095 #if defined(FT_BBOX_H)
00096 #  include FT_BBOX_H
00097 #else
00098 #  include <freetype/ftbbox.h>
00099 #endif /* defined(FT_BBOX_H) */
00100 #endif
00101 
00102 /*
00103   Forward declarations.
00104 */
00105 static MagickBooleanType
00106   RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
00107   RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
00108   RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
00109     TypeMetric *),
00110   RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *);
00111 
00112 /*
00113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00114 %                                                                             %
00115 %                                                                             %
00116 %                                                                             %
00117 %   A n n o t a t e I m a g e                                                 %
00118 %                                                                             %
00119 %                                                                             %
00120 %                                                                             %
00121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00122 %
00123 %  AnnotateImage() annotates an image with text.  Optionally you can include
00124 %  any of the following bits of information about the image by embedding
00125 %  the appropriate special characters:
00126 %
00127 %    %b   file size in bytes.
00128 %    %c   comment.
00129 %    %d   directory in which the image resides.
00130 %    %e   extension of the image file.
00131 %    %f   original filename of the image.
00132 %    %h   height of image.
00133 %    %i   filename of the image.
00134 %    %k   number of unique colors.
00135 %    %l   image label.
00136 %    %m   image file format.
00137 %    %n   number of images in a image sequence.
00138 %    %o   output image filename.
00139 %    %p   page number of the image.
00140 %    %q   image depth (8 or 16).
00141 %    %q   image depth (8 or 16).
00142 %    %s   image scene number.
00143 %    %t   image filename without any extension.
00144 %    %u   a unique temporary filename.
00145 %    %w   image width.
00146 %    %x   x resolution of the image.
00147 %    %y   y resolution of the image.
00148 %
00149 %  The format of the AnnotateImage method is:
00150 %
00151 %      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info)
00152 %
00153 %  A description of each parameter follows:
00154 %
00155 %    o image: the image.
00156 %
00157 %    o draw_info: the draw info.
00158 %
00159 */
00160 MagickExport MagickBooleanType AnnotateImage(Image *image,
00161   const DrawInfo *draw_info)
00162 {
00163   char
00164     primitive[MaxTextExtent],
00165     **textlist;
00166 
00167   DrawInfo
00168     *annotate,
00169     *annotate_info;
00170 
00171   GeometryInfo
00172     geometry_info;
00173 
00174   MagickBooleanType
00175     status;
00176 
00177   PointInfo
00178     offset;
00179 
00180   RectangleInfo
00181     geometry;
00182 
00183   register long
00184     i;
00185 
00186   size_t
00187     length;
00188 
00189   TypeMetric
00190     metrics;
00191 
00192   unsigned long
00193     height,
00194     number_lines;
00195 
00196   assert(image != (Image *) NULL);
00197   assert(image->signature == MagickSignature);
00198   if (image->debug != MagickFalse)
00199     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00200   assert(draw_info != (DrawInfo *) NULL);
00201   assert(draw_info->signature == MagickSignature);
00202   if (draw_info->text == (char *) NULL)
00203     return(MagickFalse);
00204   if (*draw_info->text == '\0')
00205     return(MagickTrue);
00206   textlist=StringToList(draw_info->text);
00207   if (textlist == (char **) NULL)
00208     return(MagickFalse);
00209   length=strlen(textlist[0]);
00210   for (i=1; textlist[i] != (char *) NULL; i++)
00211     if (strlen(textlist[i]) > length)
00212       length=strlen(textlist[i]);
00213   number_lines=(unsigned long) i;
00214   annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00215   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00216   SetGeometry(image,&geometry);
00217   SetGeometryInfo(&geometry_info);
00218   if (annotate_info->geometry != (char *) NULL)
00219     {
00220       (void) ParsePageGeometry(image,annotate_info->geometry,&geometry,
00221         &image->exception);
00222       (void) ParseGeometry(annotate_info->geometry,&geometry_info);
00223     }
00224   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00225     return(MagickFalse);
00226   status=MagickTrue;
00227   for (i=0; textlist[i] != (char *) NULL; i++)
00228   {
00229     /*
00230       Position text relative to image.
00231     */
00232     annotate_info->affine.tx=geometry_info.xi-image->page.x;
00233     annotate_info->affine.ty=geometry_info.psi-image->page.y;
00234     (void) CloneString(&annotate->text,textlist[i]);
00235     (void) GetTypeMetrics(image,annotate,&metrics);
00236     height=(unsigned long) (metrics.ascent-metrics.descent+0.5);
00237     switch (annotate->gravity)
00238     {
00239       case UndefinedGravity:
00240       default:
00241       {
00242         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
00243         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
00244         break;
00245       }
00246       case NorthWestGravity:
00247       {
00248         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00249           annotate_info->affine.ry*height+annotate_info->affine.ry*
00250           (metrics.ascent+metrics.descent);
00251         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00252           annotate_info->affine.sy*height+annotate_info->affine.sy*
00253           metrics.ascent;
00254         break;
00255       }
00256       case NorthGravity:
00257       {
00258         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00259           geometry.width/2.0+i*annotate_info->affine.ry*height-
00260           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
00261           annotate_info->affine.ry*(metrics.ascent+metrics.descent);
00262         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00263           annotate_info->affine.sy*height+annotate_info->affine.sy*
00264           metrics.ascent-annotate_info->affine.rx*(metrics.width-
00265           metrics.bounds.x1)/2.0;
00266         break;
00267       }
00268       case NorthEastGravity:
00269       {
00270         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00271           geometry.width+i*annotate_info->affine.ry*height-
00272           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
00273           annotate_info->affine.ry*(metrics.ascent+metrics.descent)-1.0;
00274         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00275           annotate_info->affine.sy*height+annotate_info->affine.sy*
00276           metrics.ascent-annotate_info->affine.rx*(metrics.width-
00277           metrics.bounds.x1);
00278         break;
00279       }
00280       case WestGravity:
00281       {
00282         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00283           annotate_info->affine.ry*height+annotate_info->affine.ry*
00284           (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
00285         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00286           geometry.height/2.0+i*annotate_info->affine.sy*height+
00287           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00288           (number_lines-1.0)*height)/2.0;
00289         break;
00290       }
00291       case StaticGravity:
00292       case CenterGravity:
00293       {
00294         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00295           geometry.width/2.0+i*annotate_info->affine.ry*height-
00296           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
00297           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
00298           (number_lines-1)*height)/2.0;
00299         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00300           geometry.height/2.0+i*annotate_info->affine.sy*height-
00301           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
00302           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00303           (number_lines-1.0)*height)/2.0;
00304         break;
00305       }
00306       case EastGravity:
00307       {
00308         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00309           geometry.width+i*annotate_info->affine.ry*height-
00310           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
00311           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
00312           (number_lines-1.0)*height)/2.0-1.0;
00313         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00314           geometry.height/2.0+i*annotate_info->affine.sy*height-
00315           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
00316           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00317           (number_lines-1.0)*height)/2.0;
00318         break;
00319       }
00320       case SouthWestGravity:
00321       {
00322         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00323           annotate_info->affine.ry*height-annotate_info->affine.ry*
00324           (number_lines-1.0)*height;
00325         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00326           geometry.height+i*annotate_info->affine.sy*height-
00327           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00328         break;
00329       }
00330       case SouthGravity:
00331       {
00332         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00333           geometry.width/2.0+i*annotate_info->affine.ry*height-
00334           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
00335           annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
00336         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00337           geometry.height+i*annotate_info->affine.sy*height-
00338           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
00339           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00340         break;
00341       }
00342       case SouthEastGravity:
00343       {
00344         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00345           geometry.width+i*annotate_info->affine.ry*height-
00346           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
00347           annotate_info->affine.ry*(number_lines-1.0)*height-1.0;
00348         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00349           geometry.height+i*annotate_info->affine.sy*height-
00350           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
00351           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00352         break;
00353       }
00354     }
00355     switch (annotate->align)
00356     {
00357       case LeftAlign:
00358       {
00359         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
00360         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
00361         break;
00362       }
00363       case CenterAlign:
00364       {
00365         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
00366           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
00367         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
00368           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
00369         break;
00370       }
00371       case RightAlign:
00372       {
00373         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
00374           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
00375         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
00376           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
00377         break;
00378       }
00379       default:
00380         break;
00381     }
00382     if (draw_info->undercolor.opacity != TransparentOpacity)
00383       {
00384         DrawInfo
00385           *undercolor_info;
00386 
00387         /*
00388           Text box.
00389         */
00390         undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
00391         undercolor_info->fill=draw_info->undercolor;
00392         undercolor_info->affine=draw_info->affine;
00393         undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
00394         undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
00395         (void) FormatMagickString(primitive,MaxTextExtent,
00396           "rectangle 0,0 %g,%ld",metrics.origin.x,height);
00397         (void) CloneString(&undercolor_info->primitive,primitive);
00398         (void) DrawImage(image,undercolor_info);
00399         (void) DestroyDrawInfo(undercolor_info);
00400       }
00401     annotate_info->affine.tx=offset.x;
00402     annotate_info->affine.ty=offset.y;
00403     (void) FormatMagickString(primitive,MaxTextExtent,"stroke-width %g "
00404       "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
00405     if (annotate->decorate == OverlineDecoration)
00406       {
00407         annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
00408           metrics.descent-metrics.underline_position));
00409         (void) CloneString(&annotate_info->primitive,primitive);
00410         (void) DrawImage(image,annotate_info);
00411       }
00412     else
00413       if (annotate->decorate == UnderlineDecoration)
00414         {
00415           annotate_info->affine.ty-=(draw_info->affine.sy*
00416             metrics.underline_position);
00417           (void) CloneString(&annotate_info->primitive,primitive);
00418           (void) DrawImage(image,annotate_info);
00419         }
00420     /*
00421       Annotate image with text.
00422     */
00423     status=RenderType(image,annotate,&offset,&metrics);
00424     if (status == MagickFalse)
00425       break;
00426     if (annotate->decorate == LineThroughDecoration)
00427       {
00428         annotate_info->affine.ty-=(draw_info->affine.sy*(height+
00429           metrics.underline_position+metrics.descent)/2.0);
00430         (void) CloneString(&annotate_info->primitive,primitive);
00431         (void) DrawImage(image,annotate_info);
00432       }
00433   }
00434   /*
00435     Relinquish resources.
00436   */
00437   annotate_info=DestroyDrawInfo(annotate_info);
00438   annotate=DestroyDrawInfo(annotate);
00439   for (i=0; textlist[i] != (char *) NULL; i++)
00440     textlist[i]=DestroyString(textlist[i]);
00441   textlist=(char **) RelinquishMagickMemory(textlist);
00442   return(status);
00443 }
00444 
00445 /*
00446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00447 %                                                                             %
00448 %                                                                             %
00449 %                                                                             %
00450 %  F o r m a t M a g i c k C a p t i o n                                      %
00451 %                                                                             %
00452 %                                                                             %
00453 %                                                                             %
00454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00455 %
00456 %  FormatMagickCaption() formats a caption so that it fits within the image
00457 %  width.  It returns the number of lines in the formatted caption.
00458 %
00459 %  The format of the FormatMagickCaption method is:
00460 %
00461 %      long FormatMagickCaption(Image *image,DrawInfo *draw_info,char *caption,
00462 %        TypeMetric *metrics)
00463 %
00464 %  A description of each parameter follows.
00465 %
00466 %    o image:  The image.
00467 %
00468 %    o draw_info: the draw info.
00469 %
00470 %    o metrics: Return the font metrics in this structure.
00471 %
00472 */
00473 MagickExport long FormatMagickCaption(Image *image,DrawInfo *draw_info,
00474   char *caption,TypeMetric *metrics)
00475 {
00476   MagickBooleanType
00477     status;
00478 
00479   register char
00480     *p,
00481     *q,
00482     *s;
00483 
00484   register long
00485     i;
00486 
00487   unsigned long
00488     width;
00489 
00490   q=draw_info->text;
00491   s=(char *) NULL;
00492   for (p=caption; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
00493   {
00494     if (IsUTFSpace(GetUTFCode(p)) != MagickFalse)
00495       s=p;
00496     for (i=0; i < (long) GetUTFOctets(p); i++)
00497       *q++=(*(p+i));
00498     *q='\0';
00499     status=GetTypeMetrics(image,draw_info,metrics);
00500     if (status == MagickFalse)
00501       break;
00502     width=(unsigned long) (metrics->width+0.5);
00503     if (GetUTFCode(p) != '\n')
00504       if (width <= image->columns)
00505         continue;
00506     if (s == (char *) NULL)
00507       {
00508         s=p;
00509         while ((IsUTFSpace(GetUTFCode(s)) == MagickFalse) &&
00510                (GetUTFCode(s) != 0))
00511           s+=GetUTFOctets(s);
00512       }
00513     if (GetUTFCode(s) != 0)
00514       {
00515         *s='\n';
00516         p=s;
00517         s=(char *) NULL;
00518       }
00519     q=draw_info->text;
00520   }
00521   i=0;
00522   for (p=caption; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
00523     if (GetUTFCode(p) == '\n')
00524       i++;
00525   return(i);
00526 }
00527 
00528 /*
00529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00530 %                                                                             %
00531 %                                                                             %
00532 %                                                                             %
00533 %   G e t M u l t i l i n e T y p e M e t r i c s                             %
00534 %                                                                             %
00535 %                                                                             %
00536 %                                                                             %
00537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00538 %
00539 %  GetMultilineTypeMetrics() returns the following information for the
00540 %  specified font and text:
00541 %
00542 %    character width
00543 %    character height
00544 %    ascender
00545 %    descender
00546 %    text width
00547 %    text height
00548 %    maximum horizontal advance
00549 %    bounds: x1
00550 %    bounds: y1
00551 %    bounds: x2
00552 %    bounds: y2
00553 %    origin: x
00554 %    origin: y
00555 %    underline position
00556 %    underline thickness
00557 %
00558 %  This method is like GetTypeMetrics() but it returns the maximum text width
00559 %  and height for multiple lines of text.
00560 %
00561 %  The format of the GetMultilineTypeMetrics method is:
00562 %
00563 %      MagickBooleanType GetMultilineTypeMetrics(Image *image,
00564 %        const DrawInfo *draw_info,TypeMetric *metrics)
00565 %
00566 %  A description of each parameter follows:
00567 %
00568 %    o image: the image.
00569 %
00570 %    o draw_info: the draw info.
00571 %
00572 %    o metrics: Return the font metrics in this structure.
00573 %
00574 */
00575 MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
00576   const DrawInfo *draw_info,TypeMetric *metrics)
00577 {
00578   char
00579     **textlist;
00580 
00581   DrawInfo
00582     *annotate_info;
00583 
00584   MagickBooleanType
00585     status;
00586 
00587   register long
00588     i;
00589 
00590   TypeMetric
00591     extent;
00592 
00593   unsigned long
00594     number_lines;
00595 
00596   assert(image != (Image *) NULL);
00597   assert(image->signature == MagickSignature);
00598   if (image->debug != MagickFalse)
00599     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00600   assert(draw_info != (DrawInfo *) NULL);
00601   assert(draw_info->text != (char *) NULL);
00602   assert(draw_info->signature == MagickSignature);
00603   if (*draw_info->text == '\0')
00604     return(MagickFalse);
00605   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00606   annotate_info->text=DestroyString(annotate_info->text);
00607   /*
00608     Convert newlines to multiple lines of text.
00609   */
00610   textlist=StringToList(draw_info->text);
00611   if (textlist == (char **) NULL)
00612     return(MagickFalse);
00613   annotate_info->render=MagickFalse;
00614   (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
00615   (void) ResetMagickMemory(&extent,0,sizeof(extent));
00616   /*
00617     Find the widest of the text lines.
00618   */
00619   annotate_info->text=textlist[0];
00620   status=GetTypeMetrics(image,annotate_info,&extent);
00621   *metrics=extent;
00622   for (i=1; textlist[i] != (char *) NULL; i++)
00623   {
00624     annotate_info->text=textlist[i];
00625     status=GetTypeMetrics(image,annotate_info,&extent);
00626     if (extent.width > metrics->width)
00627       *metrics=extent;
00628   }
00629   number_lines=(unsigned long) i;
00630   metrics->height=(double) number_lines*(long) (metrics->ascent-
00631     metrics->descent+0.5);
00632   /*
00633     Relinquish resources.
00634   */
00635   annotate_info->text=(char *) NULL;
00636   annotate_info=DestroyDrawInfo(annotate_info);
00637   for (i=0; textlist[i] != (char *) NULL; i++)
00638     textlist[i]=DestroyString(textlist[i]);
00639   textlist=(char **) RelinquishMagickMemory(textlist);
00640   return(status);
00641 }
00642 
00643 /*
00644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00645 %                                                                             %
00646 %                                                                             %
00647 %                                                                             %
00648 %   G e t T y p e M e t r i c s                                               %
00649 %                                                                             %
00650 %                                                                             %
00651 %                                                                             %
00652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00653 %
00654 %  GetTypeMetrics() returns the following information for the specified font
00655 %  and text:
00656 %
00657 %    character width
00658 %    character height
00659 %    ascender
00660 %    descender
00661 %    text width
00662 %    text height
00663 %    maximum horizontal advance
00664 %    bounds: x1
00665 %    bounds: y1
00666 %    bounds: x2
00667 %    bounds: y2
00668 %    origin: x
00669 %    origin: y
00670 %    underline position
00671 %    underline thickness
00672 %
00673 %  The format of the GetTypeMetrics method is:
00674 %
00675 %      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
00676 %        TypeMetric *metrics)
00677 %
00678 %  A description of each parameter follows:
00679 %
00680 %    o image: the image.
00681 %
00682 %    o draw_info: the draw info.
00683 %
00684 %    o metrics: Return the font metrics in this structure.
00685 %
00686 */
00687 MagickExport MagickBooleanType GetTypeMetrics(Image *image,
00688   const DrawInfo *draw_info,TypeMetric *metrics)
00689 {
00690   DrawInfo
00691     *annotate_info;
00692 
00693   MagickBooleanType
00694     status;
00695 
00696   PointInfo
00697     offset;
00698 
00699   assert(image != (Image *) NULL);
00700   assert(image->signature == MagickSignature);
00701   if (image->debug != MagickFalse)
00702     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00703   assert(draw_info != (DrawInfo *) NULL);
00704   assert(draw_info->text != (char *) NULL);
00705   assert(draw_info->signature == MagickSignature);
00706   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00707   annotate_info->render=MagickFalse;
00708   (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
00709   offset.x=0.0;
00710   offset.y=0.0;
00711   status=RenderType(image,annotate_info,&offset,metrics);
00712   if (image->debug != MagickFalse)
00713     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
00714       "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
00715       "bounds: %g,%g  %g,%g; origin: %g,%g; pixels per em: %g,%g; "
00716       "underline position: %g; underline thickness: %g",annotate_info->text,
00717       metrics->width,metrics->height,metrics->ascent,metrics->descent,
00718       metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
00719       metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
00720       metrics->pixels_per_em.x,metrics->pixels_per_em.y,
00721       metrics->underline_position,metrics->underline_thickness);
00722   annotate_info=DestroyDrawInfo(annotate_info);
00723   return(status);
00724 }
00725 
00726 /*
00727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00728 %                                                                             %
00729 %                                                                             %
00730 %                                                                             %
00731 +   R e n d e r T y p e                                                       %
00732 %                                                                             %
00733 %                                                                             %
00734 %                                                                             %
00735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00736 %
00737 %  RenderType() renders text on the image.  It also returns the bounding box of
00738 %  the text relative to the image.
00739 %
00740 %  The format of the RenderType method is:
00741 %
00742 %      MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
00743 %        const PointInfo *offset,TypeMetric *metrics)
00744 %
00745 %  A description of each parameter follows:
00746 %
00747 %    o image: the image.
00748 %
00749 %    o draw_info: the draw info.
00750 %
00751 %    o offset: (x,y) location of text relative to image.
00752 %
00753 %    o metrics: bounding box of text.
00754 %
00755 */
00756 static MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
00757   const PointInfo *offset,TypeMetric *metrics)
00758 {
00759   const TypeInfo
00760     *type_info;
00761 
00762   DrawInfo
00763     *annotate_info;
00764 
00765   MagickBooleanType
00766     status;
00767 
00768   type_info=(const TypeInfo *) NULL;
00769   if (draw_info->font != (char *) NULL)
00770     {
00771       if (*draw_info->font == '@')
00772         {
00773           status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
00774             metrics);
00775           return(status);
00776         }
00777       if (*draw_info->font == '-')
00778         return(RenderX11(image,draw_info,offset,metrics));
00779       if (IsPathAccessible(draw_info->font) != MagickFalse)
00780         {
00781           status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
00782             metrics);
00783           return(status);
00784         }
00785       type_info=GetTypeInfo(draw_info->font,&image->exception);
00786       if (type_info == (const TypeInfo *) NULL)
00787         (void) ThrowMagickException(&image->exception,GetMagickModule(),
00788           TypeWarning,"UnableToReadFont","`%s'",draw_info->font);
00789     }
00790   if ((type_info == (const TypeInfo *) NULL) &&
00791       (draw_info->family != (const char *) NULL))
00792     {
00793       type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
00794         draw_info->stretch,draw_info->weight,&image->exception);
00795       if (type_info == (const TypeInfo *) NULL)
00796         (void) ThrowMagickException(&image->exception,GetMagickModule(),
00797           TypeWarning,"UnableToReadFont","`%s'",draw_info->family);
00798     }
00799   if (type_info == (const TypeInfo *) NULL)
00800     type_info=GetTypeInfoByFamily("arial",draw_info->style,
00801       draw_info->stretch,draw_info->weight,&image->exception);
00802   if (type_info == (const TypeInfo *) NULL)
00803     type_info=GetTypeInfoByFamily("helvetica",draw_info->style,
00804       draw_info->stretch,draw_info->weight,&image->exception);
00805   if (type_info == (const TypeInfo *) NULL)
00806     type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
00807       draw_info->stretch,draw_info->weight,&image->exception);
00808   if (type_info == (const TypeInfo *) NULL)
00809     {
00810       status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics);
00811       return(status);
00812     }
00813   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00814   annotate_info->face=type_info->face;
00815   if (type_info->metrics != (char *) NULL)
00816     (void) CloneString(&annotate_info->metrics,type_info->metrics);
00817   if (type_info->glyphs != (char *) NULL)
00818     (void) CloneString(&annotate_info->font,type_info->glyphs);
00819   status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics);
00820   annotate_info=DestroyDrawInfo(annotate_info);
00821   return(status);
00822 }
00823 
00824 /*
00825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00826 %                                                                             %
00827 %                                                                             %
00828 %                                                                             %
00829 +   R e n d e r F r e e t y p e                                               %
00830 %                                                                             %
00831 %                                                                             %
00832 %                                                                             %
00833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00834 %
00835 %  RenderFreetype() renders text on the image with a Truetype font.  It also
00836 %  returns the bounding box of the text relative to the image.
00837 %
00838 %  The format of the RenderFreetype method is:
00839 %
00840 %      MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
00841 %        const char *encoding,const PointInfo *offset,TypeMetric *metrics)
00842 %
00843 %  A description of each parameter follows:
00844 %
00845 %    o image: the image.
00846 %
00847 %    o draw_info: the draw info.
00848 %
00849 %    o encoding: the font encoding.
00850 %
00851 %    o offset: (x,y) location of text relative to image.
00852 %
00853 %    o metrics: bounding box of text.
00854 %
00855 */
00856 
00857 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00858 static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
00859   DrawInfo *draw_info)
00860 {
00861   AffineMatrix
00862     affine;
00863 
00864   char
00865     path[MaxTextExtent];
00866 
00867   affine=draw_info->affine;
00868   (void) FormatMagickString(path,MaxTextExtent,"C%g,%g %g,%g %g,%g",
00869     affine.tx+p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,
00870     affine.ty-q->y/64.0,affine.tx+to->x/64.0,affine.ty-to->y/64.0);
00871   (void) ConcatenateString(&draw_info->primitive,path);
00872   return(0);
00873 }
00874 
00875 static int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
00876 {
00877   AffineMatrix
00878     affine;
00879 
00880   char
00881     path[MaxTextExtent];
00882 
00883   affine=draw_info->affine;
00884   (void) FormatMagickString(path,MaxTextExtent,"L%g,%g",affine.tx+to->x/64.0,
00885     affine.ty-to->y/64.0);
00886   (void) ConcatenateString(&draw_info->primitive,path);
00887   return(0);
00888 }
00889 
00890 static int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
00891 {
00892   AffineMatrix
00893     affine;
00894 
00895   char
00896     path[MaxTextExtent];
00897 
00898   affine=draw_info->affine;
00899   (void) FormatMagickString(path,MaxTextExtent,"M%g,%g",affine.tx+to->x/64.0,
00900     affine.ty-to->y/64.0);
00901   (void) ConcatenateString(&draw_info->primitive,path);
00902   return(0);
00903 }
00904 
00905 static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
00906   DrawInfo *draw_info)
00907 {
00908   AffineMatrix
00909     affine;
00910 
00911   char
00912     path[MaxTextExtent];
00913 
00914   affine=draw_info->affine;
00915   (void) FormatMagickString(path,MaxTextExtent,"Q%g,%g %g,%g",
00916     affine.tx+control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,
00917     affine.ty-to->y/64.0);
00918   (void) ConcatenateString(&draw_info->primitive,path);
00919   return(0);
00920 }
00921 
00922 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
00923   const char *encoding,const PointInfo *offset,TypeMetric *metrics)
00924 {
00925 #if !defined(FT_OPEN_PATHNAME)
00926 #define FT_OPEN_PATHNAME  ft_open_pathname
00927 #endif
00928 
00929   typedef struct _GlyphInfo
00930   {
00931     FT_UInt
00932       id;
00933 
00934     FT_Vector
00935       origin;
00936 
00937     FT_Glyph
00938       image;
00939   } GlyphInfo;
00940 
00941   const char
00942     *value;
00943 
00944   DrawInfo
00945     *annotate_info;
00946 
00947   FT_BBox
00948     bounds;
00949 
00950   FT_BitmapGlyph
00951     bitmap;
00952 
00953   FT_Encoding
00954     encoding_type;
00955 
00956   FT_Error
00957     status;
00958 
00959   FT_Face
00960     face;
00961 
00962   FT_Int32
00963     flags;
00964 
00965   FT_Library
00966     library;
00967 
00968   FT_Matrix
00969     affine;
00970 
00971   FT_Open_Args
00972     args;
00973 
00974   FT_Vector
00975     origin;
00976 
00977   GlyphInfo
00978     glyph,
00979     last_glyph;
00980 
00981   long
00982     code,
00983     y;
00984 
00985   PointInfo
00986     point,
00987     resolution;
00988 
00989   register char
00990     *p;
00991 
00992   static FT_Outline_Funcs
00993     OutlineMethods =
00994     {
00995       (FT_Outline_MoveTo_Func) TraceMoveTo,
00996       (FT_Outline_LineTo_Func) TraceLineTo,
00997       (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
00998       (FT_Outline_CubicTo_Func) TraceCubicBezier,
00999       0, 0
01000     };
01001 
01002   /*
01003     Initialize Truetype library.
01004   */
01005   status=FT_Init_FreeType(&library);
01006   if (status != 0)
01007     ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
01008       image->filename);
01009   args.flags=FT_OPEN_PATHNAME;
01010   if (draw_info->font == (char *) NULL)
01011     args.pathname=ConstantString("helvetica");
01012   else
01013     if (*draw_info->font != '@')
01014       args.pathname=ConstantString(draw_info->font);
01015     else
01016       args.pathname=ConstantString(draw_info->font+1);
01017   face=(FT_Face) NULL;
01018   status=FT_Open_Face(library,&args,draw_info->face,&face);
01019   args.pathname=DestroyString(args.pathname);
01020   if (status != 0)
01021     {
01022       (void) FT_Done_FreeType(library);
01023       (void) ThrowMagickException(&image->exception,GetMagickModule(),
01024         TypeError,"UnableToReadFont","`%s'",draw_info->font);
01025       return(RenderPostscript(image,draw_info,offset,metrics));
01026     }
01027   if ((draw_info->metrics != (char *) NULL) &&
01028       (IsPathAccessible(draw_info->metrics) != MagickFalse))
01029     (void) FT_Attach_File(face,draw_info->metrics);
01030   encoding_type=ft_encoding_unicode;
01031   status=FT_Select_Charmap(face,encoding_type);
01032   if ((status != 0) && (face->num_charmaps != 0))
01033     status=FT_Set_Charmap(face,face->charmaps[0]);
01034   if (encoding != (const char *) NULL)
01035     {
01036       if (LocaleCompare(encoding,"AdobeCustom") == 0)
01037         encoding_type=ft_encoding_adobe_custom;
01038       if (LocaleCompare(encoding,"AdobeExpert") == 0)
01039         encoding_type=ft_encoding_adobe_expert;
01040       if (LocaleCompare(encoding,"AdobeStandard") == 0)
01041         encoding_type=ft_encoding_adobe_standard;
01042       if (LocaleCompare(encoding,"AppleRoman") == 0)
01043         encoding_type=ft_encoding_apple_roman;
01044       if (LocaleCompare(encoding,"BIG5") == 0)
01045         encoding_type=ft_encoding_big5;
01046       if (LocaleCompare(encoding,"GB2312") == 0)
01047         encoding_type=ft_encoding_gb2312;
01048       if (LocaleCompare(encoding,"Johab") == 0)
01049         encoding_type=ft_encoding_johab;
01050 #if defined(ft_encoding_latin_1)
01051       if (LocaleCompare(encoding,"Latin-1") == 0)
01052         encoding_type=ft_encoding_latin_1;
01053 #endif
01054       if (LocaleCompare(encoding,"Latin-2") == 0)
01055         encoding_type=ft_encoding_latin_2;
01056       if (LocaleCompare(encoding,"None") == 0)
01057         encoding_type=ft_encoding_none;
01058       if (LocaleCompare(encoding,"SJIScode") == 0)
01059         encoding_type=ft_encoding_sjis;
01060       if (LocaleCompare(encoding,"Symbol") == 0)
01061         encoding_type=ft_encoding_symbol;
01062       if (LocaleCompare(encoding,"Unicode") == 0)
01063         encoding_type=ft_encoding_unicode;
01064       if (LocaleCompare(encoding,"Wansung") == 0)
01065         encoding_type=ft_encoding_wansung;
01066       status=FT_Select_Charmap(face,encoding_type);
01067       if (status != 0)
01068         ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
01069     }
01070   /*
01071     Set text size.
01072   */
01073   resolution.x=DefaultResolution;
01074   resolution.y=DefaultResolution;
01075   if (draw_info->density != (char *) NULL)
01076     {
01077       GeometryInfo
01078         geometry_info;
01079 
01080       MagickStatusType
01081         flags;
01082 
01083       flags=ParseGeometry(draw_info->density,&geometry_info);
01084       resolution.x=geometry_info.rho;
01085       resolution.y=geometry_info.sigma;
01086       if ((flags & SigmaValue) == 0)
01087         resolution.y=resolution.x;
01088     }
01089   status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
01090     (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
01091     (FT_UInt) resolution.y);
01092   metrics->pixels_per_em.x=face->size->metrics.x_ppem;
01093   metrics->pixels_per_em.y=face->size->metrics.y_ppem;
01094   metrics->ascent=(double) face->size->metrics.ascender/64.0;
01095   metrics->descent=(double) face->size->metrics.descender/64.0;
01096   metrics->width=0;
01097   metrics->origin.x=0;
01098   metrics->origin.y=0;
01099   metrics->height=(double) face->size->metrics.height/64.0;
01100   metrics->max_advance=0.0;
01101   if (face->size->metrics.max_advance > MagickEpsilon)
01102     metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
01103   metrics->bounds.x1=0.0;
01104   metrics->bounds.y1=metrics->descent;
01105   metrics->bounds.x2=metrics->ascent+metrics->descent;
01106   metrics->bounds.y2=metrics->ascent+metrics->descent;
01107   metrics->underline_position=face->underline_position/64.0;
01108   metrics->underline_thickness=face->underline_thickness/64.0;
01109   if (*draw_info->text == '\0')
01110     {
01111       (void) FT_Done_Face(face);
01112       (void) FT_Done_FreeType(library);
01113       return(MagickTrue);
01114     }
01115   /*
01116     Compute bounding box.
01117   */
01118   if (image->debug != MagickFalse)
01119     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
01120       "font-encoding %s; text-encoding %s; pointsize %g",
01121       draw_info->font != (char *) NULL ? draw_info->font : "none",
01122       encoding != (char *) NULL ? encoding : "none",
01123       draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
01124       draw_info->pointsize);
01125   flags=FT_LOAD_NO_BITMAP;
01126   value=GetImageProperty(image,"type:hinting");
01127   if (LocaleCompare(value,"off") == 0)
01128     flags|=FT_LOAD_NO_HINTING;
01129   glyph.id=0;
01130   glyph.image=NULL;
01131   last_glyph.id=0;
01132   last_glyph.image=NULL;
01133   origin.x=0;
01134   origin.y=0;
01135   affine.xx=65536L;
01136   affine.yx=0L;
01137   affine.xy=0L;
01138   affine.yy=65536L;
01139   if (draw_info->render != MagickFalse)
01140     {
01141       affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
01142       affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
01143       affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
01144       affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
01145     }
01146   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
01147   (void) CloneString(&annotate_info->primitive,"path '");
01148   if (draw_info->render != MagickFalse)
01149     {
01150       if (image->storage_class != DirectClass)
01151         (void) SetImageStorageClass(image,DirectClass);
01152       if (image->matte == MagickFalse)
01153         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
01154     }
01155   point.x=0.0;
01156   point.y=0.0;
01157   code=0;
01158   for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
01159   {
01160     glyph.id=FT_Get_Char_Index(face,GetUTFCode(p));
01161     if (glyph.id == 0)
01162       glyph.id=FT_Get_Char_Index(face,'?');
01163     if ((glyph.id != 0) && (last_glyph.id != 0))
01164       {
01165         if (draw_info->kerning != 0.0)
01166           origin.x+=64.0*draw_info->kerning;
01167         else
01168           if (FT_HAS_KERNING(face))
01169             {
01170               FT_Vector
01171                 kerning;
01172 
01173               status=FT_Get_Kerning(face,last_glyph.id,glyph.id,
01174                 ft_kerning_default,&kerning);
01175               if (status == 0)
01176                 origin.x+=kerning.x;
01177             }
01178         }
01179     glyph.origin=origin;
01180     status=FT_Load_Glyph(face,glyph.id,flags);
01181     if (status != 0)
01182       continue;
01183     status=FT_Get_Glyph(face->glyph,&glyph.image);
01184     if (status != 0)
01185       continue;
01186     status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->outline,
01187       &bounds);
01188     if (status != 0)
01189       continue;
01190     if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
01191       metrics->bounds.x1=bounds.xMin;
01192     if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
01193       metrics->bounds.y1=bounds.yMin;
01194     if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
01195       metrics->bounds.x2=bounds.xMax;
01196     if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
01197       metrics->bounds.y2=bounds.yMax;
01198     if (draw_info->render != MagickFalse)
01199       if ((draw_info->stroke.opacity != TransparentOpacity) ||
01200           (draw_info->stroke_pattern != (Image *) NULL))
01201         {
01202           /*
01203             Trace the glyph.
01204           */
01205           annotate_info->affine.tx=glyph.origin.x/64.0;
01206           annotate_info->affine.ty=glyph.origin.y/64.0;
01207           (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->outline,
01208             &OutlineMethods,annotate_info);
01209         }
01210     FT_Vector_Transform(&glyph.origin,&affine);
01211     (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
01212     status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
01213       (FT_Vector *) NULL,MagickTrue);
01214     if (status != 0)
01215       continue;
01216     bitmap=(FT_BitmapGlyph) glyph.image;
01217     point.x=offset->x+bitmap->left;
01218     point.y=offset->y-bitmap->top;
01219     if (draw_info->render != MagickFalse)
01220       {
01221         ExceptionInfo
01222           *exception;
01223 
01224         MagickBooleanType
01225           status;
01226 
01227         ViewInfo
01228           *image_view;
01229 
01230         /*
01231           Rasterize the glyph.
01232         */
01233         status=MagickTrue;
01234         exception=(&image->exception);
01235         image_view=AcquireCacheView(image);
01236 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01237   #pragma omp parallel for schedule(dynamic,4) shared(status)
01238 #endif
01239         for (y=0; y < (long) bitmap->bitmap.rows; y++)
01240         {
01241           long
01242             x_offset,
01243             y_offset;
01244 
01245           MagickBooleanType
01246             active,
01247             sync;
01248 
01249           MagickRealType
01250             fill_opacity;
01251 
01252           PixelPacket
01253             fill_color;
01254 
01255           register long
01256             x;
01257 
01258           register PixelPacket
01259             *__restrict q;
01260 
01261           register unsigned char
01262             *p;
01263 
01264           if (status == MagickFalse)
01265             continue;
01266           x_offset=(long) (point.x+0.5);
01267           y_offset=(long) (point.y+y+0.5);
01268           if ((y_offset < 0) || (y_offset >= (long) image->rows))
01269             continue;
01270           q=(PixelPacket *) NULL;
01271           if ((x_offset < 0) || (x_offset >= (long) image->columns))
01272             active=MagickFalse;
01273           else
01274             {
01275               q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
01276                 bitmap->bitmap.width,1,exception);
01277               active=q != (PixelPacket *) NULL ? MagickTrue : MagickFalse;
01278             }
01279           p=bitmap->bitmap.buffer+y*bitmap->bitmap.width;
01280           for (x=0; x < (long) bitmap->bitmap.width; x++)
01281           {
01282             x_offset++;
01283             if ((*p == 0) || (x_offset < 0) ||
01284                 (x_offset >= (long) image->columns))
01285               {
01286                 p++;
01287                 q++;
01288                 continue;
01289               }
01290             fill_opacity=(MagickRealType) (*p)/(bitmap->bitmap.num_grays-1);
01291             if (draw_info->text_antialias == MagickFalse)
01292               fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
01293             if (active == MagickFalse)
01294               q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
01295                 exception);
01296             if (q == (PixelPacket *) NULL)
01297               {
01298                 p++;
01299                 q++;
01300                 continue;
01301               }
01302             (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color);
01303             fill_opacity=QuantumRange-fill_opacity*(QuantumRange-
01304               fill_color.opacity);
01305             MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q);
01306             if (active == MagickFalse)
01307               {
01308                 sync=SyncCacheViewAuthenticPixels(image_view,exception);
01309                 if (sync == MagickFalse)
01310                   status=MagickFalse;
01311               }
01312             p++;
01313             q++;
01314           }
01315           sync=SyncCacheViewAuthenticPixels(image_view,exception);
01316           if (sync == MagickFalse)
01317             status=MagickFalse;
01318         }
01319         image_view=DestroyCacheView(image_view);
01320       }
01321     if ((bitmap->left+bitmap->bitmap.width) > metrics->width)
01322       metrics->width=bitmap->left+bitmap->bitmap.width;
01323     if ((draw_info->interword_spacing != 0.0) &&
01324         (IsUTFSpace(GetUTFCode(p)) != MagickFalse) &&
01325         (IsUTFSpace(code) == MagickFalse))
01326       origin.x+=64.0*draw_info->interword_spacing;
01327     else
01328       origin.x+=face->glyph->advance.x;
01329     metrics->origin.x=origin.x;
01330     metrics->origin.y=origin.y;
01331     if (last_glyph.id != 0)
01332       FT_Done_Glyph(last_glyph.image);
01333     last_glyph=glyph;
01334     code=GetUTFCode(p);
01335   }
01336   if (last_glyph.id != 0)
01337     FT_Done_Glyph(last_glyph.image);
01338   if ((draw_info->stroke.opacity != TransparentOpacity) ||
01339       (draw_info->stroke_pattern != (Image *) NULL))
01340     {
01341       if (draw_info->render != MagickFalse)
01342         {
01343           /*
01344             Draw text stroke.
01345           */
01346           annotate_info->linejoin=RoundJoin;
01347           annotate_info->affine.tx=offset->x;
01348           annotate_info->affine.ty=offset->y;
01349           (void) ConcatenateString(&annotate_info->primitive,"'");
01350           (void) DrawImage(image,annotate_info);
01351         }
01352       }
01353   /*
01354     Determine font metrics.
01355   */
01356   glyph.id=FT_Get_Char_Index(face,'_');
01357   glyph.origin=origin;
01358   status=FT_Load_Glyph(face,glyph.id,flags);
01359   if (status == 0)
01360     {
01361       status=FT_Get_Glyph(face->glyph,&glyph.image);
01362       if (status == 0)
01363         {
01364           status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->
01365             outline,&bounds);
01366           if (status == 0)
01367             {
01368               FT_Vector_Transform(&glyph.origin,&affine);
01369               (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
01370               status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
01371                 (FT_Vector *) NULL,MagickTrue);
01372               bitmap=(FT_BitmapGlyph) glyph.image;
01373               if (bitmap->left > metrics->width)
01374                 metrics->width=bitmap->left;
01375             }
01376         }
01377       if (glyph.id != 0)
01378         FT_Done_Glyph(glyph.image);
01379     }
01380   metrics->width-=metrics->bounds.x1/64.0;
01381   metrics->bounds.x1/=64.0;
01382   metrics->bounds.y1/=64.0;
01383   metrics->bounds.x2/=64.0;
01384   metrics->bounds.y2/=64.0;
01385   metrics->origin.x/=64.0;
01386   metrics->origin.y/=64.0;
01387   /*
01388     Relinquish resources.
01389   */
01390   annotate_info=DestroyDrawInfo(annotate_info);
01391   (void) FT_Done_Face(face);
01392   (void) FT_Done_FreeType(library);
01393   return(MagickTrue);
01394 }
01395 #else
01396 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
01397   const char *magick_unused(encoding),const PointInfo *offset,
01398   TypeMetric *metrics)
01399 {
01400   (void) ThrowMagickException(&image->exception,GetMagickModule(),
01401     MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (Freetype)",
01402     draw_info->font);
01403   return(RenderPostscript(image,draw_info,offset,metrics));
01404 }
01405 #endif
01406 
01407 /*
01408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01409 %                                                                             %
01410 %                                                                             %
01411 %                                                                             %
01412 +   R e n d e r P o s t s c r i p t                                           %
01413 %                                                                             %
01414 %                                                                             %
01415 %                                                                             %
01416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01417 %
01418 %  RenderPostscript() renders text on the image with a Postscript font.  It
01419 %  also returns the bounding box of the text relative to the image.
01420 %
01421 %  The format of the RenderPostscript method is:
01422 %
01423 %      MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
01424 %        const PointInfo *offset,TypeMetric *metrics)
01425 %
01426 %  A description of each parameter follows:
01427 %
01428 %    o image: the image.
01429 %
01430 %    o draw_info: the draw info.
01431 %
01432 %    o offset: (x,y) location of text relative to image.
01433 %
01434 %    o metrics: bounding box of text.
01435 %
01436 */
01437 
01438 static inline size_t MagickMin(const size_t x,const size_t y)
01439 {
01440   if (x < y)
01441     return(x);
01442   return(y);
01443 }
01444 
01445 static char *EscapeParenthesis(const char *text)
01446 {
01447   char
01448     *buffer;
01449 
01450   register char
01451     *p;
01452 
01453   register long
01454     i;
01455 
01456   size_t
01457     escapes;
01458 
01459   escapes=0;
01460   buffer=AcquireString(text);
01461   p=buffer;
01462   for (i=0; i < (long) MagickMin(strlen(text),MaxTextExtent-escapes-1); i++)
01463   {
01464     if ((text[i] == '(') || (text[i] == ')'))
01465       {
01466         *p++='\\';
01467         escapes++;
01468       }
01469     *p++=text[i];
01470   }
01471   *p='\0';
01472   return(buffer);
01473 }
01474 
01475 static MagickBooleanType RenderPostscript(Image *image,
01476   const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics)
01477 {
01478   char
01479     filename[MaxTextExtent],
01480     geometry[MaxTextExtent],
01481     *text;
01482 
01483   FILE
01484     *file;
01485 
01486   Image
01487     *annotate_image;
01488 
01489   ImageInfo
01490     *annotate_info;
01491 
01492   int
01493     unique_file;
01494 
01495   long
01496     y;
01497 
01498   MagickBooleanType
01499     identity;
01500 
01501   PointInfo
01502     extent,
01503     point,
01504     resolution;
01505 
01506   register long
01507     i;
01508 
01509   /*
01510     Render label with a Postscript font.
01511   */
01512   if (image->debug != MagickFalse)
01513     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
01514       "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
01515       draw_info->font : "none",draw_info->pointsize);
01516   file=(FILE *) NULL;
01517   unique_file=AcquireUniqueFileResource(filename);
01518   if (unique_file != -1)
01519     file=fdopen(unique_file,"wb");
01520   if ((unique_file == -1) || (file == (FILE *) NULL))
01521     {
01522       ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
01523         filename);
01524       return(MagickFalse);
01525     }
01526   (void) fprintf(file,"%%!PS-Adobe-3.0\n");
01527   (void) fprintf(file,"/ReencodeType\n");
01528   (void) fprintf(file,"{\n");
01529   (void) fprintf(file,"  findfont dup length\n");
01530   (void) fprintf(file,
01531     "  dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
01532   (void) fprintf(file,
01533     "  /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
01534   (void) fprintf(file,"} bind def\n");
01535   /*
01536     Sample to compute bounding box.
01537   */
01538   identity=(draw_info->affine.sx == draw_info->affine.sy) &&
01539     (draw_info->affine.rx == 0.0) && (draw_info->affine.ry == 0.0) ?
01540     MagickTrue : MagickFalse;
01541   extent.x=0.0;
01542   extent.y=0.0;
01543   for (i=0; i <= (long) (strlen(draw_info->text)+2); i++)
01544   {
01545     point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
01546       draw_info->affine.ry*2.0*draw_info->pointsize);
01547     point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
01548       draw_info->affine.sy*2.0*draw_info->pointsize);
01549     if (point.x > extent.x)
01550       extent.x=point.x;
01551     if (point.y > extent.y)
01552       extent.y=point.y;
01553   }
01554   (void) fprintf(file,"%g %g moveto\n",identity  != MagickFalse ? 0.0 :
01555     extent.x/2.0,extent.y/2.0);
01556   (void) fprintf(file,"%g %g scale\n",draw_info->pointsize,
01557     draw_info->pointsize);
01558   if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
01559       (strchr(draw_info->font,'/') != (char *) NULL))
01560     (void) fprintf(file,
01561       "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
01562   else
01563     (void) fprintf(file,"/%s-ISO dup /%s ReencodeType findfont setfont\n",
01564       draw_info->font,draw_info->font);
01565   (void) fprintf(file,"[%g %g %g %g 0 0] concat\n",draw_info->affine.sx,
01566     -draw_info->affine.rx,-draw_info->affine.ry,draw_info->affine.sy);
01567   text=EscapeParenthesis(draw_info->text);
01568   if (identity == MagickFalse)
01569     (void) fprintf(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",text);
01570   (void) fprintf(file,"(%s) show\n",text);
01571   text=DestroyString(text);
01572   (void) fprintf(file,"showpage\n");
01573   (void) fclose(file);
01574   (void) FormatMagickString(geometry,MaxTextExtent,"%ldx%ld+0+0!",(long)
01575     (extent.x+0.5),(long) (extent.y+0.5));
01576   annotate_info=AcquireImageInfo();
01577   (void) FormatMagickString(annotate_info->filename,MaxTextExtent,"ps:%s",
01578     filename);
01579   (void) CloneString(&annotate_info->page,geometry);
01580   if (draw_info->density != (char *) NULL)
01581     (void) CloneString(&annotate_info->density,draw_info->density);
01582   annotate_info->antialias=draw_info->text_antialias;
01583   annotate_image=ReadImage(annotate_info,&image->exception);
01584   CatchException(&image->exception);
01585   annotate_info=DestroyImageInfo(annotate_info);
01586   (void) RelinquishUniqueFileResource(filename);
01587   if (annotate_image == (Image *) NULL)
01588     return(MagickFalse);
01589   resolution.x=DefaultResolution;
01590   resolution.y=DefaultResolution;
01591   if (draw_info->density != (char *) NULL)
01592     {
01593       GeometryInfo
01594         geometry_info;
01595 
01596       MagickStatusType
01597         flags;
01598 
01599       flags=ParseGeometry(draw_info->density,&geometry_info);
01600       resolution.x=geometry_info.rho;
01601       resolution.y=geometry_info.sigma;
01602       if ((flags & SigmaValue) == 0)
01603         resolution.y=resolution.x;
01604     }
01605   if (identity == MagickFalse)
01606     (void) TransformImage(&annotate_image,"0x0",(char *) NULL);
01607   else
01608     {
01609       RectangleInfo
01610         crop_info;
01611 
01612       crop_info=GetImageBoundingBox(annotate_image,&annotate_image->exception);
01613       crop_info.height=(unsigned long) ((resolution.y/DefaultResolution)*
01614         ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
01615       crop_info.y=(long) ((resolution.y/DefaultResolution)*extent.y/8.0+0.5);
01616       (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
01617         crop_info.width,crop_info.height,crop_info.x,crop_info.y);
01618       (void) TransformImage(&annotate_image,geometry,(char *) NULL);
01619     }
01620   metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
01621     ExpandAffine(&draw_info->affine)*draw_info->pointsize;
01622   metrics->pixels_per_em.y=metrics->pixels_per_em.x;
01623   metrics->ascent=metrics->pixels_per_em.x;
01624   metrics->descent=metrics->pixels_per_em.y/-5.0;
01625   metrics->width=(double) annotate_image->columns/
01626     ExpandAffine(&draw_info->affine);
01627   metrics->height=1.152*metrics->pixels_per_em.x;
01628   metrics->max_advance=metrics->pixels_per_em.x;
01629   metrics->bounds.x1=0.0;
01630   metrics->bounds.y1=metrics->descent;
01631   metrics->bounds.x2=metrics->ascent+metrics->descent;
01632   metrics->bounds.y2=metrics->ascent+metrics->descent;
01633   metrics->underline_position=(-2.0);
01634   metrics->underline_thickness=1.0;
01635   if (draw_info->render == MagickFalse)
01636     {
01637       annotate_image=DestroyImage(annotate_image);
01638       return(MagickTrue);
01639     }
01640   if (draw_info->fill.opacity != TransparentOpacity)
01641     {
01642       ExceptionInfo
01643         *exception;
01644 
01645       MagickBooleanType
01646         sync;
01647 
01648       PixelPacket
01649         fill_color;
01650 
01651       ViewInfo
01652         *annotate_view;
01653 
01654       /*
01655         Render fill color.
01656       */
01657       if (image->matte == MagickFalse)
01658         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
01659       if (annotate_image->matte == MagickFalse)
01660         (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel);
01661       fill_color=draw_info->fill;
01662       exception=(&image->exception);
01663       annotate_view=AcquireCacheView(annotate_image);
01664       for (y=0; y < (long) annotate_image->rows; y++)
01665       {
01666         register long
01667           x;
01668 
01669         register PixelPacket
01670           *__restrict q;
01671 
01672         q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
01673           1,exception);
01674         if (q == (PixelPacket *) NULL)
01675           break;
01676         for (x=0; x < (long) annotate_image->columns; x++)
01677         {
01678           (void) GetFillColor(draw_info,x,y,&fill_color);
01679           q->opacity=RoundToQuantum(QuantumRange-(((QuantumRange-
01680             (MagickRealType) PixelIntensityToQuantum(q))*(QuantumRange-
01681             fill_color.opacity))/QuantumRange));
01682           q->red=fill_color.red;
01683           q->green=fill_color.green;
01684           q->blue=fill_color.blue;
01685           q++;
01686         }
01687         sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
01688         if (sync == MagickFalse)
01689           break;
01690       }
01691       annotate_view=DestroyCacheView(annotate_view);
01692       (void) CompositeImage(image,OverCompositeOp,annotate_image,
01693         (long) (offset->x+0.5),(long) (offset->y-(metrics->ascent+
01694         metrics->descent)+0.5));
01695     }
01696   annotate_image=DestroyImage(annotate_image);
01697   return(MagickTrue);
01698 }
01699 
01700 /*
01701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01702 %                                                                             %
01703 %                                                                             %
01704 %                                                                             %
01705 +   R e n d e r X 1 1                                                         %
01706 %                                                                             %
01707 %                                                                             %
01708 %                                                                             %
01709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01710 %
01711 %  RenderX11() renders text on the image with an X11 font.  It also returns the
01712 %  bounding box of the text relative to the image.
01713 %
01714 %  The format of the RenderX11 method is:
01715 %
01716 %      MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
01717 %        const PointInfo *offset,TypeMetric *metrics)
01718 %
01719 %  A description of each parameter follows:
01720 %
01721 %    o image: the image.
01722 %
01723 %    o draw_info: the draw info.
01724 %
01725 %    o offset: (x,y) location of text relative to image.
01726 %
01727 %    o metrics: bounding box of text.
01728 %
01729 */
01730 #if defined(MAGICKCORE_X11_DELEGATE)
01731 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
01732   const PointInfo *offset,TypeMetric *metrics)
01733 {
01734   MagickBooleanType
01735     status;
01736 
01737   static DrawInfo
01738     cache_info;
01739 
01740   static Display
01741     *display = (Display *) NULL;
01742 
01743   static XAnnotateInfo
01744     annotate_info;
01745 
01746   static XFontStruct
01747     *font_info;
01748 
01749   static XPixelInfo
01750     pixel;
01751 
01752   static XResourceInfo
01753     resource_info;
01754 
01755   static XrmDatabase
01756     resource_database;
01757 
01758   static XStandardColormap
01759     *map_info;
01760 
01761   static XVisualInfo
01762     *visual_info;
01763 
01764   unsigned long
01765     height,
01766     width;
01767 
01768   if (display == (Display *) NULL)
01769     {
01770       ImageInfo
01771         *image_info;
01772 
01773       /*
01774         Open X server connection.
01775       */
01776       display=XOpenDisplay(draw_info->server_name);
01777       if (display == (Display *) NULL)
01778         {
01779           ThrowXWindowException(XServerError,"UnableToOpenXServer",
01780             draw_info->server_name);
01781           return(MagickFalse);
01782         }
01783       /*
01784         Get user defaults from X resource database.
01785       */
01786       (void) XSetErrorHandler(XError);
01787       image_info=AcquireImageInfo();
01788       resource_database=XGetResourceDatabase(display,GetClientName());
01789       XGetResourceInfo(image_info,resource_database,GetClientName(),
01790         &resource_info);
01791       resource_info.close_server=MagickFalse;
01792       resource_info.colormap=PrivateColormap;
01793       resource_info.font=AcquireString(draw_info->font);
01794       resource_info.background_color=AcquireString("#ffffffffffff");
01795       resource_info.foreground_color=AcquireString("#000000000000");
01796       map_info=XAllocStandardColormap();
01797       if (map_info == (XStandardColormap *) NULL)
01798         {
01799           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
01800             image->filename);
01801           return(MagickFalse);
01802         }
01803       /*
01804         Initialize visual info.
01805       */
01806       visual_info=XBestVisualInfo(display,map_info,&resource_info);
01807       if (visual_info == (XVisualInfo *) NULL)
01808         {
01809           ThrowXWindowException(XServerError,"UnableToGetVisual",
01810             image->filename);
01811           return(MagickFalse);
01812         }
01813       map_info->colormap=(Colormap) NULL;
01814       pixel.pixels=(unsigned long *) NULL;
01815       /*
01816         Initialize Standard Colormap info.
01817       */
01818       XGetMapInfo(visual_info,XDefaultColormap(display,visual_info->screen),
01819         map_info);
01820       XGetPixelPacket(display,visual_info,map_info,&resource_info,
01821         (Image *) NULL,&pixel);
01822       pixel.annotate_context=XDefaultGC(display,visual_info->screen);
01823       /*
01824         Initialize font info.
01825       */
01826       font_info=XBestFont(display,&resource_info,MagickFalse);
01827       if (font_info == (XFontStruct *) NULL)
01828         {
01829           ThrowXWindowException(XServerError,"UnableToLoadFont",
01830             draw_info->font);
01831           return(MagickFalse);
01832         }
01833       if ((map_info == (XStandardColormap *) NULL) ||
01834           (visual_info == (XVisualInfo *) NULL) ||
01835           (font_info == (XFontStruct *) NULL))
01836         {
01837           XFreeResources(display,visual_info,map_info,&pixel,font_info,
01838             &resource_info,(XWindowInfo *) NULL);
01839           ThrowXWindowException(XServerError,"UnableToLoadFont",
01840             image->filename);
01841           return(MagickFalse);
01842         }
01843       cache_info=(*draw_info);
01844     }
01845   /*
01846     Initialize annotate info.
01847   */
01848   XGetAnnotateInfo(&annotate_info);
01849   annotate_info.stencil=ForegroundStencil;
01850   if (cache_info.font != draw_info->font)
01851     {
01852       /*
01853         Type name has changed.
01854       */
01855       (void) XFreeFont(display,font_info);
01856       (void) CloneString(&resource_info.font,draw_info->font);
01857       font_info=XBestFont(display,&resource_info,MagickFalse);
01858       if (font_info == (XFontStruct *) NULL)
01859         {
01860           ThrowXWindowException(XServerError,"UnableToLoadFont",
01861             draw_info->font);
01862           return(MagickFalse);
01863         }
01864     }
01865   if (image->debug != MagickFalse)
01866     (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
01867       "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
01868       draw_info->font : "none",draw_info->pointsize);
01869   cache_info=(*draw_info);
01870   annotate_info.font_info=font_info;
01871   annotate_info.text=(char *) draw_info->text;
01872   annotate_info.width=(unsigned int) XTextWidth(font_info,draw_info->text,
01873     (int) strlen(draw_info->text));
01874   annotate_info.height=(unsigned int) font_info->ascent+font_info->descent;
01875   metrics->pixels_per_em.x=(double) font_info->max_bounds.width;
01876   metrics->pixels_per_em.y=(double) font_info->ascent+font_info->descent;
01877   metrics->ascent=(double) font_info->ascent+4;
01878   metrics->descent=(double) (-font_info->descent);
01879   metrics->width=annotate_info.width/ExpandAffine(&draw_info->affine);
01880   metrics->height=font_info->ascent+font_info->descent;
01881   metrics->max_advance=(double) font_info->max_bounds.width;
01882   metrics->bounds.x1=0.0;
01883   metrics->bounds.y1=metrics->descent;
01884   metrics->bounds.x2=metrics->ascent+metrics->descent;
01885   metrics->bounds.y2=metrics->ascent+metrics->descent;
01886   metrics->underline_position=(-2.0);
01887   metrics->underline_thickness=1.0;
01888   if (draw_info->render == MagickFalse)
01889     return(MagickTrue);
01890   if (draw_info->fill.opacity == TransparentOpacity)
01891     return(MagickTrue);
01892   /*
01893     Render fill color.
01894   */
01895   width=annotate_info.width;
01896   height=annotate_info.height;
01897   if ((draw_info->affine.rx != 0.0) || (draw_info->affine.ry != 0.0))
01898     {
01899       if (((draw_info->affine.sx-draw_info->affine.sy) == 0.0) &&
01900           ((draw_info->affine.rx+draw_info->affine.ry) == 0.0))
01901         annotate_info.degrees=(180.0/MagickPI)*
01902           atan2(draw_info->affine.rx,draw_info->affine.sx);
01903     }
01904   (void) FormatMagickString(annotate_info.geometry,MaxTextExtent,
01905     "%lux%lu+%ld+%ld",width,height,(long) (offset->x+0.5),
01906     (long) (offset->y-metrics->ascent-metrics->descent+0.5));
01907   pixel.pen_color.red=ScaleQuantumToShort(draw_info->fill.red);
01908   pixel.pen_color.green=ScaleQuantumToShort(draw_info->fill.green);
01909   pixel.pen_color.blue=ScaleQuantumToShort(draw_info->fill.blue);
01910   status=XAnnotateImage(display,&pixel,&annotate_info,image);
01911   if (status == 0)
01912     {
01913       ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
01914         image->filename);
01915       return(MagickFalse);
01916     }
01917   return(MagickTrue);
01918 }
01919 #else
01920 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
01921   const PointInfo *offset,TypeMetric *metrics)
01922 {
01923   (void) draw_info;
01924   (void) offset;
01925   (void) metrics;
01926   (void) ThrowMagickException(&image->exception,GetMagickModule(),
01927     MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
01928     image->filename);
01929   return(MagickFalse);
01930 }
01931 #endif

Generated on Thu Jul 2 12:03:13 2009 for MagickCore by  doxygen 1.5.8