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

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1