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-2008 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/transform.h"
00069 #include "magick/type.h"
00070 #include "magick/utility.h"
00071 #include "magick/xwindow-private.h"
00072 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00073 #if defined(__MINGW32__)
00074 #  undef interface
00075 #endif
00076 #if defined(MAGICKCORE_HAVE_FT2BUILD_H)
00077 #  include <ft2build.h>
00078 #endif
00079 #if defined(FT_FREETYPE_H)
00080 #  include FT_FREETYPE_H
00081 #else
00082 #  include <freetype/freetype.h>
00083 #endif
00084 #if defined(FT_GLYPH_H)
00085 #  include FT_GLYPH_H
00086 #else
00087 #  include <freetype/ftglyph.h>
00088 #endif
00089 #if defined(FT_OUTLINE_H)
00090 #  include FT_OUTLINE_H
00091 #else
00092 #  include <freetype/ftoutln.h>
00093 #endif
00094 #if defined(FT_BBOX_H)
00095 #  include FT_BBOX_H
00096 #else
00097 #  include <freetype/ftbbox.h>
00098 #endif /* defined(FT_BBOX_H) */
00099 #endif
00100 
00101 /*
00102   Forward declarations.
00103 */
00104 static MagickBooleanType
00105   RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
00106   RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
00107   RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
00108     TypeMetric *),
00109   RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *);
00110 
00111 /*
00112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00113 %                                                                             %
00114 %                                                                             %
00115 %                                                                             %
00116 %   A n n o t a t e I m a g e                                                 %
00117 %                                                                             %
00118 %                                                                             %
00119 %                                                                             %
00120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00121 %
00122 %  AnnotateImage() annotates an image with text.  Optionally you can include
00123 %  any of the following bits of information about the image by embedding
00124 %  the appropriate special characters:
00125 %
00126 %    %b   file size in bytes.
00127 %    %c   comment.
00128 %    %d   directory in which the image resides.
00129 %    %e   extension of the image file.
00130 %    %f   original filename of the image.
00131 %    %h   height of image.
00132 %    %i   filename of the image.
00133 %    %k   number of unique colors.
00134 %    %l   image label.
00135 %    %m   image file format.
00136 %    %n   number of images in a image sequence.
00137 %    %o   output image filename.
00138 %    %p   page number of the image.
00139 %    %q   image depth (8 or 16).
00140 %    %q   image depth (8 or 16).
00141 %    %s   image scene number.
00142 %    %t   image filename without any extension.
00143 %    %u   a unique temporary filename.
00144 %    %w   image width.
00145 %    %x   x resolution of the image.
00146 %    %y   y resolution of the image.
00147 %
00148 %  The format of the AnnotateImage method is:
00149 %
00150 %      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info)
00151 %
00152 %  A description of each parameter follows:
00153 %
00154 %    o image: the image.
00155 %
00156 %    o draw_info: the draw info.
00157 %
00158 */
00159 MagickExport MagickBooleanType AnnotateImage(Image *image,
00160   const DrawInfo *draw_info)
00161 {
00162   char
00163     primitive[MaxTextExtent],
00164     **textlist;
00165 
00166   DrawInfo
00167     *annotate,
00168     *annotate_info;
00169 
00170   GeometryInfo
00171     geometry_info;
00172 
00173   MagickBooleanType
00174     status;
00175 
00176   PointInfo
00177     offset;
00178 
00179   RectangleInfo
00180     geometry;
00181 
00182   register long
00183     i;
00184 
00185   size_t
00186     length;
00187 
00188   TypeMetric
00189     metrics;
00190 
00191   unsigned long
00192     height,
00193     number_lines;
00194 
00195   assert(image != (Image *) NULL);
00196   assert(image->signature == MagickSignature);
00197   if (image->debug != MagickFalse)
00198     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00199   assert(draw_info != (DrawInfo *) NULL);
00200   assert(draw_info->signature == MagickSignature);
00201   if (draw_info->text == (char *) NULL)
00202     return(MagickFalse);
00203   if (*draw_info->text == '\0')
00204     return(MagickTrue);
00205   textlist=StringToList(draw_info->text);
00206   if (textlist == (char **) NULL)
00207     return(MagickFalse);
00208   length=strlen(textlist[0]);
00209   for (i=1; textlist[i] != (char *) NULL; i++)
00210     if (strlen(textlist[i]) > length)
00211       length=strlen(textlist[i]);
00212   number_lines=(unsigned long) i;
00213   annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00214   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00215   SetGeometry(image,&geometry);
00216   SetGeometryInfo(&geometry_info);
00217   if (annotate_info->geometry != (char *) NULL)
00218     {
00219       (void) ParsePageGeometry(image,annotate_info->geometry,&geometry);
00220       (void) ParseGeometry(annotate_info->geometry,&geometry_info);
00221     }
00222   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00223     return(MagickFalse);
00224   status=MagickTrue;
00225   for (i=0; textlist[i] != (char *) NULL; i++)
00226   {
00227     /*
00228       Position text relative to image.
00229     */
00230     annotate_info->affine.tx=geometry_info.xi-image->page.x;
00231     annotate_info->affine.ty=geometry_info.psi-image->page.y;
00232     (void) CloneString(&annotate->text,textlist[i]);
00233     (void) GetTypeMetrics(image,annotate,&metrics);
00234     height=(unsigned long) (metrics.ascent-metrics.descent+0.5);
00235     switch (annotate->gravity)
00236     {
00237       case UndefinedGravity:
00238       default:
00239       {
00240         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
00241         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
00242         break;
00243       }
00244       case NorthWestGravity:
00245       {
00246         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00247           annotate_info->affine.ry*height+annotate_info->affine.ry*
00248           (metrics.ascent+metrics.descent);
00249         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00250           annotate_info->affine.sy*height+annotate_info->affine.sy*
00251           metrics.ascent;
00252         break;
00253       }
00254       case NorthGravity:
00255       {
00256         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00257           geometry.width/2.0+i*annotate_info->affine.ry*height-
00258           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
00259           annotate_info->affine.ry*(metrics.ascent+metrics.descent);
00260         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00261           annotate_info->affine.sy*height+annotate_info->affine.sy*
00262           metrics.ascent-annotate_info->affine.rx*(metrics.width-
00263           metrics.bounds.x1)/2.0;
00264         break;
00265       }
00266       case NorthEastGravity:
00267       {
00268         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00269           geometry.width+i*annotate_info->affine.ry*height-
00270           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
00271           annotate_info->affine.ry*(metrics.ascent+metrics.descent);
00272         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
00273           annotate_info->affine.sy*height+annotate_info->affine.sy*
00274           metrics.ascent-annotate_info->affine.rx*(metrics.width-
00275           metrics.bounds.x1);
00276         break;
00277       }
00278       case WestGravity:
00279       {
00280         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00281           annotate_info->affine.ry*height+annotate_info->affine.ry*
00282           (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
00283         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00284           geometry.height/2.0+i*annotate_info->affine.sy*height+
00285           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00286           (number_lines-1.0)*height)/2.0;
00287         break;
00288       }
00289       case StaticGravity:
00290       case CenterGravity:
00291       {
00292         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00293           geometry.width/2.0+i*annotate_info->affine.ry*height-
00294           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
00295           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
00296           (number_lines-1)*height)/2.0;
00297         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00298           geometry.height/2.0+i*annotate_info->affine.sy*height-
00299           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
00300           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00301           (number_lines-1.0)*height)/2.0;
00302         break;
00303       }
00304       case EastGravity:
00305       {
00306         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00307           geometry.width+i*annotate_info->affine.ry*height-
00308           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
00309           annotate_info->affine.ry*(metrics.ascent+metrics.descent-
00310           (number_lines-1.0)*height)/2.0;
00311         offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
00312           geometry.height/2.0+i*annotate_info->affine.sy*height-
00313           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
00314           annotate_info->affine.sy*(metrics.ascent+metrics.descent-
00315           (number_lines-1.0)*height)/2.0;
00316         break;
00317       }
00318       case SouthWestGravity:
00319       {
00320         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
00321           annotate_info->affine.ry*height-annotate_info->affine.ry*
00322           (number_lines-1.0)*height;
00323         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00324           geometry.height+i*annotate_info->affine.sy*height-
00325           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00326         break;
00327       }
00328       case SouthGravity:
00329       {
00330         offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
00331           geometry.width/2.0+i*annotate_info->affine.ry*height-
00332           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
00333           annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
00334         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00335           geometry.height+i*annotate_info->affine.sy*height-
00336           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
00337           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00338         break;
00339       }
00340       case SouthEastGravity:
00341       {
00342         offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
00343           geometry.width+i*annotate_info->affine.ry*height-
00344           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
00345           annotate_info->affine.ry*(number_lines-1.0)*height;
00346         offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
00347           geometry.height+i*annotate_info->affine.sy*height-
00348           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
00349           annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
00350         break;
00351       }
00352     }
00353     switch (annotate->align)
00354     {
00355       case LeftAlign:
00356       {
00357         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
00358         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
00359         break;
00360       }
00361       case CenterAlign:
00362       {
00363         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
00364           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
00365         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
00366           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
00367         break;
00368       }
00369       case RightAlign:
00370       {
00371         offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
00372           annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
00373         offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
00374           annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
00375         break;
00376       }
00377       default:
00378         break;
00379     }
00380     if (draw_info->undercolor.opacity != TransparentOpacity)
00381       {
00382         DrawInfo
00383           *undercolor_info;
00384 
00385         /*
00386           Text box.
00387         */
00388         undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
00389         undercolor_info->fill=draw_info->undercolor;
00390         undercolor_info->affine=draw_info->affine;
00391         undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
00392         undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
00393         (void) FormatMagickString(primitive,MaxTextExtent,
00394           "rectangle 0,0 %g,%ld",metrics.origin.x,height);
00395         (void) CloneString(&undercolor_info->primitive,primitive);
00396         (void) DrawImage(image,undercolor_info);
00397         (void) DestroyDrawInfo(undercolor_info);
00398       }
00399     annotate_info->affine.tx=offset.x;
00400     annotate_info->affine.ty=offset.y;
00401     (void) FormatMagickString(primitive,MaxTextExtent,"stroke-width %g "
00402       "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
00403     if (annotate->decorate == OverlineDecoration)
00404       {
00405         annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
00406           metrics.descent-metrics.underline_position));
00407         (void) CloneString(&annotate_info->primitive,primitive);
00408         (void) DrawImage(image,annotate_info);
00409       }
00410     else
00411       if (annotate->decorate == UnderlineDecoration)
00412         {
00413           annotate_info->affine.ty-=(draw_info->affine.sy*
00414             metrics.underline_position);
00415           (void) CloneString(&annotate_info->primitive,primitive);
00416           (void) DrawImage(image,annotate_info);
00417         }
00418     /*
00419       Annotate image with text.
00420     */
00421     status=RenderType(image,annotate,&offset,&metrics);
00422     if (status == MagickFalse)
00423       break;
00424     if (annotate->decorate == LineThroughDecoration)
00425       {
00426         annotate_info->affine.ty-=(draw_info->affine.sy*(height+
00427           metrics.underline_position+metrics.descent)/2.0);
00428         (void) CloneString(&annotate_info->primitive,primitive);
00429         (void) DrawImage(image,annotate_info);
00430       }
00431   }
00432   /*
00433     Relinquish resources.
00434   */
00435   annotate_info=DestroyDrawInfo(annotate_info);
00436   annotate=DestroyDrawInfo(annotate);
00437   for (i=0; textlist[i] != (char *) NULL; i++)
00438     textlist[i]=DestroyString(textlist[i]);
00439   textlist=(char **) RelinquishMagickMemory(textlist);
00440   return(status);
00441 }
00442 
00443 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00444 /*
00445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00446 %                                                                             %
00447 %                                                                             %
00448 %                                                                             %
00449 +   E n c o d e S J I S                                                       %
00450 %                                                                             %
00451 %                                                                             %
00452 %                                                                             %
00453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00454 %
00455 %  EncodeSJIS() converts an ASCII text string to 2-bytes per character code
00456 %  (like UCS-2).  Returns the translated codes and the character count.
00457 %  Characters under 0x7f are just copied, characters over 0x80 are tied with
00458 %  the next character.
00459 %
00460 %  Katsutoshi Shibuya contributed this method.
00461 %
00462 %  The format of the EncodeSJIS function is:
00463 %
00464 %      encoding=EncodeSJIS(const Image *image,const char *text,size_t count)
00465 %
00466 %  A description of each parameter follows:
00467 %
00468 %    o image: the image.
00469 %
00470 %    o text: the text.
00471 %
00472 %    o count: return the number of characters generated by the encoding.
00473 %
00474 */
00475 
00476 static int GetOneCharacter(const unsigned char *text,size_t *length)
00477 {
00478   int
00479     c;
00480 
00481   if (*length < 1)
00482     return(-1);
00483   c=text[0];
00484   if ((c & 0x80) == 0)
00485     {
00486       *length=1;
00487       return((int) c);
00488     }
00489   if (*length < 2)
00490     {
00491       *length=0;
00492       return(-1);
00493     }
00494   *length=2;
00495   c=((int) (text[0]) << 8);
00496   c|=text[1];
00497   return((int) c);
00498 }
00499 
00500 static unsigned long *EncodeSJIS(const char *text,size_t *count)
00501 {
00502   int
00503     c;
00504 
00505   register const char
00506     *p;
00507 
00508   register unsigned long
00509     *q;
00510 
00511   size_t
00512     length;
00513 
00514   unsigned long
00515     *encoding;
00516 
00517   *count=0;
00518   if ((text == (char *) NULL) || (*text == '\0'))
00519     return((unsigned long *) NULL);
00520   length=strlen(text);
00521   if (~length < MaxTextExtent)
00522     return((unsigned long *) NULL);
00523   length+=MaxTextExtent;
00524   encoding=(unsigned long *) AcquireQuantumMemory(length,sizeof(*encoding));
00525   if (encoding == (unsigned long *) NULL)
00526     return((unsigned long *) NULL);
00527   q=encoding;
00528   for (p=text; *p != '\0'; p+=length)
00529   {
00530     length=strlen(p);
00531     c=GetOneCharacter((const unsigned char *) p,&length);
00532     if (c < 0)
00533       {
00534         q=encoding;
00535         for (p=text; *p != '\0'; p++)
00536           *q++=(unsigned char) *p;
00537         break;
00538       }
00539     *q=(unsigned long) c;
00540     q++;
00541   }
00542   *count=q-encoding;
00543   return(encoding);
00544 }
00545 #endif
00546 
00547 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00548 /*
00549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00550 %                                                                             %
00551 %                                                                             %
00552 %                                                                             %
00553 +   E n c o d e T e x t                                                       %
00554 %                                                                             %
00555 %                                                                             %
00556 %                                                                             %
00557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00558 %
00559 %  EncodeText() converts an ASCII text string to wide text and returns the
00560 %  translation and the character count.
00561 %
00562 %  The format of the EncodeText function is:
00563 %
00564 %      encoding=EncodeText(const char *text,size_t count)
00565 %
00566 %  A description of each parameter follows:
00567 %
00568 %    o text: the text.
00569 %
00570 %    o count: return the number of characters generated by the encoding.
00571 %
00572 */
00573 static unsigned long *EncodeText(const char *text,size_t *count)
00574 {
00575   register const char
00576     *p;
00577 
00578   register unsigned long
00579     *q;
00580 
00581   size_t
00582     length;
00583 
00584   unsigned long
00585     *encoding;
00586 
00587   *count=0;
00588   if ((text == (char *) NULL) || (*text == '\0'))
00589     return((unsigned long *) NULL);
00590   length=strlen(text);
00591   if (~length < MaxTextExtent)
00592     return((unsigned long *) NULL);
00593   length+=MaxTextExtent;
00594   encoding=(unsigned long *) AcquireQuantumMemory(length,sizeof(*encoding));
00595   if (encoding == (unsigned long *) NULL)
00596     return((unsigned long *) NULL);
00597   q=encoding;
00598   for (p=text; *p != '\0'; p++)
00599     *q++=(unsigned char) *p;
00600   *count=q-encoding;
00601   return(encoding);
00602 }
00603 #endif
00604 
00605 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
00606 /*
00607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00608 %                                                                             %
00609 %                                                                             %
00610 %                                                                             %
00611 +   E n c o d e U n i c o d e                                                 %
00612 %                                                                             %
00613 %                                                                             %
00614 %                                                                             %
00615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00616 %
00617 %  EncodeUnicode() converts an ASCII text string to Unicode and returns the
00618 %  Unicode translation and the character count.  Characters under 0x7f are
00619 %  just copied, characters over 0x80 are tied with the next character.
00620 %
00621 %  The format of the EncodeUnicode function is:
00622 %
00623 %      unsigned short *EncodeUnicode(const unsigned char *text,size_t count)
00624 %
00625 %  A description of each parameter follows:
00626 %
00627 %    o unicode:  EncodeUnicode() returns a pointer to an unsigned short array
00628 %      representing the encoded version of the ASCII string.
00629 %
00630 %    o text: the text.
00631 %
00632 %    o count: return the number of characters generated by the encoding.
00633 %
00634 */
00635 
00636 static long GetUnicodeCharacter(const unsigned char *text,size_t *length)
00637 {
00638   unsigned long
00639     c;
00640 
00641   if (*length < 1)
00642     return(-1);
00643   c=text[0];
00644   if ((c & 0x80) == 0)
00645     {
00646       *length=1;
00647       return((long) c);
00648     }
00649   if ((*length < 2) || ((text[1] & 0xc0) != 0x80))
00650     {
00651       *length=0;
00652       return(-1);
00653     }
00654   if ((c & 0xe0) != 0xe0)
00655     {
00656       *length=2;
00657       c=(text[0] & 0x1f) << 6;
00658       c|=text[1] & 0x3f;
00659       return((long) c);
00660     }
00661   if ((*length < 3) || ((text[2] & 0xc0) != 0x80))
00662     {
00663       *length=0;
00664       return(-1);
00665     }
00666   if ((c & 0xf0) != 0xf0)
00667     {
00668       *length=3;
00669       c=(text[0] & 0xf) << 12;
00670       c|=(text[1] & 0x3f) << 6;
00671       c|=text[2] & 0x3f;
00672       return((long) c);
00673     }
00674   if ((*length < 4) || ((c & 0xf8) != 0xf0) || ((text[3] & 0xc0) != 0x80))
00675     {
00676       *length=0;
00677       return(-1);
00678     }
00679   *length=4;
00680   c=(text[0] & 0x7) << 18;
00681   c|=(text[1] & 0x3f) << 12;
00682   c|=(text[2] & 0x3f) << 6;
00683   c|=text[3] & 0x3f;
00684   return((long) c);
00685 }
00686 
00687 static unsigned long *EncodeUnicode(const char *text,size_t *count)
00688 {
00689   long
00690     c;
00691 
00692   register const char
00693     *p;
00694 
00695   register unsigned long
00696     *q;
00697 
00698   size_t
00699     length;
00700 
00701   unsigned long
00702     *unicode;
00703 
00704   *count=0;
00705   if ((text == (char *) NULL) || (*text == '\0'))
00706     return((unsigned long *) NULL);
00707   length=strlen(text);
00708   if (~length < MaxTextExtent)
00709     return((unsigned long *) NULL);
00710   length+=MaxTextExtent;
00711   unicode=(unsigned long *) AcquireQuantumMemory(length,sizeof(*unicode));
00712   if (unicode == (unsigned long *) NULL)
00713     return((unsigned long *) NULL);
00714   q=unicode;
00715   for (p=text; *p != '\0'; p+=length)
00716   {
00717     length=strlen(p);
00718     c=GetUnicodeCharacter((const unsigned char *) p,&length);
00719     if (c < 0)
00720       {
00721         q=unicode;
00722         for (p=text; *p != '\0'; p++)
00723           *q++=(unsigned char) *p;
00724         break;
00725       }
00726     *q=(unsigned long) c;
00727     q++;
00728   }
00729   *count=q-unicode;
00730   return(unicode);
00731 }
00732 #endif
00733 
00734 /*
00735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00736 %                                                                             %
00737 %                                                                             %
00738 %                                                                             %
00739 %  F o r m a t M a g i c k C a p t i o n                                      %
00740 %                                                                             %
00741 %                                                                             %
00742 %                                                                             %
00743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00744 %
00745 %  FormatMagickCaption() formats a caption so that it fits within the image
00746 %  width.  It returns the number of lines in the formatted caption.
00747 %
00748 %  The format of the FormatMagickCaption method is:
00749 %
00750 %      long FormatMagickCaption(Image *image,DrawInfo *draw_info,char *caption,
00751 %        TypeMetric *metrics)
00752 %
00753 %  A description of each parameter follows.
00754 %
00755 %    o image:  The image.
00756 %
00757 %    o draw_info: the draw info.
00758 %
00759 %    o metrics: Return the font metrics in this structure.
00760 %
00761 */
00762 MagickExport long FormatMagickCaption(Image *image,DrawInfo *draw_info,
00763   char *caption,TypeMetric *metrics)
00764 {
00765   MagickBooleanType
00766     status;
00767 
00768   register char
00769     *p,
00770     *q,
00771     *s;
00772 
00773   register long
00774     i;
00775 
00776   unsigned long
00777     width;
00778 
00779   q=draw_info->text;
00780   s=(char *) NULL;
00781   for (p=caption; *p != '\0'; p++)
00782   {
00783     if (isspace((int) ((unsigned char) *p)) != 0)
00784       s=p;
00785     *q++=(*p);
00786     *q='\0';
00787     status=GetTypeMetrics(image,draw_info,metrics);
00788     if (status == MagickFalse)
00789       break;
00790     width=(unsigned long) (metrics->width+0.5);
00791     if (*p != '\n')
00792       if (width <= image->columns)
00793         continue;
00794     if (s == (char *) NULL)
00795       {
00796         s=p;
00797         while ((isspace((int) ((unsigned char) *s)) == 0) && (*s != '\0'))
00798           s++;
00799       }
00800     if (*s != '\0')
00801       {
00802         *s='\n';
00803         p=s;
00804         s=(char *) NULL;
00805       }
00806     q=draw_info->text;
00807   }
00808   i=0;
00809   for (p=caption; *p != '\0'; p++)
00810     if (*p == '\n')
00811       i++;
00812   return(i);
00813 }
00814 
00815 /*
00816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00817 %                                                                             %
00818 %                                                                             %
00819 %                                                                             %
00820 %   G e t M u l t i l i n e T y p e M e t r i c s                             %
00821 %                                                                             %
00822 %                                                                             %
00823 %                                                                             %
00824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00825 %
00826 %  GetMultilineTypeMetrics() returns the following information for the
00827 %  specified font and text:
00828 %
00829 %    character width
00830 %    character height
00831 %    ascender
00832 %    descender
00833 %    text width
00834 %    text height
00835 %    maximum horizontal advance
00836 %    bounds: x1
00837 %    bounds: y1
00838 %    bounds: x2
00839 %    bounds: y2
00840 %    origin: x
00841 %    origin: y
00842 %    underline position
00843 %    underline thickness
00844 %
00845 %  This method is like GetTypeMetrics() but it returns the maximum text width
00846 %  and height for multiple lines of text.
00847 %
00848 %  The format of the GetMultilineTypeMetrics method is:
00849 %
00850 %      MagickBooleanType GetMultilineTypeMetrics(Image *image,
00851 %        const DrawInfo *draw_info,TypeMetric *metrics)
00852 %
00853 %  A description of each parameter follows:
00854 %
00855 %    o image: the image.
00856 %
00857 %    o draw_info: the draw info.
00858 %
00859 %    o metrics: Return the font metrics in this structure.
00860 %
00861 */
00862 MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
00863   const DrawInfo *draw_info,TypeMetric *metrics)
00864 {
00865   char
00866     **textlist;
00867 
00868   DrawInfo
00869     *annotate_info;
00870 
00871   MagickBooleanType
00872     status;
00873 
00874   register long
00875     i;
00876 
00877   TypeMetric
00878     extent;
00879 
00880   unsigned long
00881     number_lines;
00882 
00883   assert(image != (Image *) NULL);
00884   assert(image->signature == MagickSignature);
00885   if (image->debug != MagickFalse)
00886     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00887   assert(draw_info != (DrawInfo *) NULL);
00888   assert(draw_info->text != (char *) NULL);
00889   assert(draw_info->signature == MagickSignature);
00890   if (*draw_info->text == '\0')
00891     return(MagickFalse);
00892   annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
00893   annotate_info->text=DestroyString(annotate_info->text);
00894   /*
00895     Convert newlines to multiple lines of text.
00896   */
00897   textlist=StringToList(draw_info->text);
00898   if (textlist == (char **) NULL)
00899     return(MagickFalse);
00900   annotate_info->render=MagickFalse;
00901   (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
00902   (void) ResetMagickMemory(&extent,0,sizeof(extent));
00903   /*
00904     Find the widest of the text lines.
00905   */
00906   annotate_info->text=textlist[0];
00907   status=GetTypeMetrics(image,annotate_info,&extent);
00908   *metrics=extent;
00909   for (i=1; textlist[i] != (char *) NULL; i++)
00910   {
00911     annotate_info->text=textlist[i];
00912     status=GetTypeMetrics(image,annotate_info,&extent);
00913     if (extent.width > metrics->width)
00914       *metrics=extent;
00915   }
00916   number_lines=(unsigned long) i;
00917   metrics->height=(double) number_lines*(long) (metrics->ascent-
00918     metrics->descent+0.5);
00919   /*
00920     Relinquish resources.
00921   */
00922   annotate_info->text=(char *) NULL;
00923   annotate_info=DestroyDrawInfo(annotate_info);
00924   for (i=0; textlist[i] != (char *) NULL; i++)
00925     textlist[i]=DestroyString(textlist[i]);
00926   textlist=(char **) RelinquishMagickMemory(textlist);
00927   return(status);
00928 }
00929 
00930 /*
00931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00932 %                                                                             %
00933 %                                                                             %
00934 %                                                                             %
00935 %   G e t T y p e M e t r i c s                                               %
00936 %                                                                             %
00937 %                                                                             %
00938 %                                                                             %
00939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00940 %
00941 %  GetTypeMetrics() returns the following information for the specified font
00942 %  and text:
00943 %
00944 %    character width
00945 %    character height
00946 %    ascender
00947 %    descender
00948 %    text width
00949 %    text height
00950 %    maximum horizontal advance
00951 %    bounds: x1
00952 %    bounds: y1
00953 %    bounds: x2
00954 %    bounds: y2
00955 %    origin: x
00956 %    origin: y
00957 %    underline position
00958 %    underline thickness
00959 %
00960 %  The format of the GetTypeMetrics method is:
00961 %
00962 %      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
00963 %        TypeMetric *metrics)
00964 %
00965 %  A description of each parameter follows:
00966 %
00967 %    o image: the image.
00968 %
00969 %    o draw_info: the draw info.
00970 %
00971 %    o metrics: Return the font metrics in this structure.
00972 %
00973 */
00974 MagickExport MagickBooleanType GetTypeMetrics(Image *image,
00975   const DrawInfo *draw_info,TypeMetric *metrics)
00976 {
00977   DrawInfo
00978     *annotate_info;
00979 
00980   MagickBooleanType
00981     status;
00982 
00983   PointInfo
00984     offset;
00985 
00986   assert(image != (Image *) NULL);