root / ImageMagick / trunk / magick / annotate.c

Revision 12127, 70.6 kB (checked in by cristy, 29 hours ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%           AAA   N   N  N   N   OOO   TTTTT   AAA   TTTTT  EEEEE             %
7%          A   A  NN  N  NN  N  O   O    T    A   A    T    E                 %
8%          AAAAA  N N N  N N N  O   O    T    AAAAA    T    EEE               %
9%          A   A  N  NN  N  NN  O   O    T    A   A    T    E                 %
10%          A   A  N   N  N   N   OOO     T    A   A    T    EEEEE             %
11%                                                                             %
12%                                                                             %
13%                  ImageMagick Image Annotation Methods                       %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36% Digital Applications (www.digapp.com) contributed the stroked text algorithm.
37% It was written by Leonard Rosenthol.
38%
39%
40*/
41
42/*
43  Include declarations.
44*/
45#include "magick/studio.h"
46#include "magick/annotate.h"
47#include "magick/cache-view.h"
48#include "magick/client.h"
49#include "magick/color.h"
50#include "magick/color-private.h"
51#include "magick/composite.h"
52#include "magick/composite-private.h"
53#include "magick/constitute.h"
54#include "magick/draw.h"
55#include "magick/draw-private.h"
56#include "magick/exception.h"
57#include "magick/exception-private.h"
58#include "magick/gem.h"
59#include "magick/geometry.h"
60#include "magick/image-private.h"
61#include "magick/log.h"
62#include "magick/quantum.h"
63#include "magick/quantum-private.h"
64#include "magick/property.h"
65#include "magick/resource_.h"
66#include "magick/statistic.h"
67#include "magick/string_.h"
68#include "magick/transform.h"
69#include "magick/type.h"
70#include "magick/utility.h"
71#include "magick/xwindow-private.h"
72#if defined(MAGICKCORE_FREETYPE_DELEGATE)
73#if defined(__MINGW32__)
74undef interface
75#endif
76#if defined(MAGICKCORE_HAVE_FT2BUILD_H)
77include <ft2build.h>
78#endif
79#if defined(FT_FREETYPE_H)
80include FT_FREETYPE_H
81#else
82include <freetype/freetype.h>
83#endif
84#if defined(FT_GLYPH_H)
85include FT_GLYPH_H
86#else
87include <freetype/ftglyph.h>
88#endif
89#if defined(FT_OUTLINE_H)
90include FT_OUTLINE_H
91#else
92include <freetype/ftoutln.h>
93#endif
94#if defined(FT_BBOX_H)
95include FT_BBOX_H
96#else
97include <freetype/ftbbox.h>
98#endif /* defined(FT_BBOX_H) */
99#endif
100
101/*
102  Forward declarations.
103*/
104static MagickBooleanType
105  RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
106  RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
107  RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
108    TypeMetric *),
109  RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *);
110
111/*
112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113%                                                                             %
114%                                                                             %
115%                                                                             %
116%   A n n o t a t e I m a g e                                                 %
117%                                                                             %
118%                                                                             %
119%                                                                             %
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121%
122%  AnnotateImage() annotates an image with text.  Optionally you can include
123%  any of the following bits of information about the image by embedding
124%  the appropriate special characters:
125%
126%    %b   file size in bytes.
127%    %c   comment.
128%    %d   directory in which the image resides.
129%    %e   extension of the image file.
130%    %f   original filename of the image.
131%    %h   height of image.
132%    %i   filename of the image.
133%    %k   number of unique colors.
134%    %l   image label.
135%    %m   image file format.
136%    %n   number of images in a image sequence.
137%    %o   output image filename.
138%    %p   page number of the image.
139%    %q   image depth (8 or 16).
140%    %q   image depth (8 or 16).
141%    %s   image scene number.
142%    %t   image filename without any extension.
143%    %u   a unique temporary filename.
144%    %w   image width.
145%    %x   x resolution of the image.
146%    %y   y resolution of the image.
147%
148%  The format of the AnnotateImage method is:
149%
150%      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info)
151%
152%  A description of each parameter follows:
153%
154%    o image: the image.
155%
156%    o draw_info: the draw info.
157%
158*/
159MagickExport MagickBooleanType AnnotateImage(Image *image,
160  const DrawInfo *draw_info)
161{
162  char
163    primitive[MaxTextExtent],
164    **textlist;
165
166  DrawInfo
167    *annotate,
168    *annotate_info;
169
170  GeometryInfo
171    geometry_info;
172
173  MagickBooleanType
174    status;
175
176  PointInfo
177    offset;
178
179  RectangleInfo
180    geometry;
181
182  register long
183    i;
184
185  size_t
186    length;
187
188  TypeMetric
189    metrics;
190
191  unsigned long
192    height,
193    number_lines;
194
195  assert(image != (Image *) NULL);
196  assert(image->signature == MagickSignature);
197  if (image->debug != MagickFalse)
198    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
199  assert(draw_info != (DrawInfo *) NULL);
200  assert(draw_info->signature == MagickSignature);
201  if (draw_info->text == (char *) NULL)
202    return(MagickFalse);
203  if (*draw_info->text == '\0')
204    return(MagickTrue);
205  textlist=StringToList(draw_info->text);
206  if (textlist == (char **) NULL)
207    return(MagickFalse);
208  length=strlen(textlist[0]);
209  for (i=1; textlist[i] != (char *) NULL; i++)
210    if (strlen(textlist[i]) > length)
211      length=strlen(textlist[i]);
212  number_lines=(unsigned long) i;
213  annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
214  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
215  SetGeometry(image,&geometry);
216  SetGeometryInfo(&geometry_info);
217  if (annotate_info->geometry != (char *) NULL)
218    {
219      (void) ParsePageGeometry(image,annotate_info->geometry,&geometry);
220      (void) ParseGeometry(annotate_info->geometry,&geometry_info);
221    }
222  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
223    return(MagickFalse);
224  status=MagickTrue;
225  for (i=0; textlist[i] != (char *) NULL; i++)
226  {
227    /*
228      Position text relative to image.
229    */
230    annotate_info->affine.tx=geometry_info.xi-image->page.x;
231    annotate_info->affine.ty=geometry_info.psi-image->page.y;
232    (void) CloneString(&annotate->text,textlist[i]);
233    (void) GetTypeMetrics(image,annotate,&metrics);
234    height=(unsigned long) (metrics.ascent-metrics.descent+0.5);
235    switch (annotate->gravity)
236    {
237      case UndefinedGravity:
238      default:
239      {
240        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
241        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
242        break;
243      }
244      case NorthWestGravity:
245      {
246        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
247          annotate_info->affine.ry*height+annotate_info->affine.ry*
248          (metrics.ascent+metrics.descent);
249        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
250          annotate_info->affine.sy*height+annotate_info->affine.sy*
251          metrics.ascent;
252        break;
253      }
254      case NorthGravity:
255      {
256        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
257          geometry.width/2.0+i*annotate_info->affine.ry*height-
258          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
259          annotate_info->affine.ry*(metrics.ascent+metrics.descent);
260        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
261          annotate_info->affine.sy*height+annotate_info->affine.sy*
262          metrics.ascent-annotate_info->affine.rx*(metrics.width-
263          metrics.bounds.x1)/2.0;
264        break;
265      }
266      case NorthEastGravity:
267      {
268        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
269          geometry.width+i*annotate_info->affine.ry*height-
270          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
271          annotate_info->affine.ry*(metrics.ascent+metrics.descent);
272        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
273          annotate_info->affine.sy*height+annotate_info->affine.sy*
274          metrics.ascent-annotate_info->affine.rx*(metrics.width-
275          metrics.bounds.x1);
276        break;
277      }
278      case WestGravity:
279      {
280        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
281          annotate_info->affine.ry*height+annotate_info->affine.ry*
282          (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
283        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
284          geometry.height/2.0+i*annotate_info->affine.sy*height+
285          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
286          (number_lines-1.0)*height)/2.0;
287        break;
288      }
289      case StaticGravity:
290      case CenterGravity:
291      {
292        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
293          geometry.width/2.0+i*annotate_info->affine.ry*height-
294          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
295          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
296          (number_lines-1)*height)/2.0;
297        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
298          geometry.height/2.0+i*annotate_info->affine.sy*height-
299          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
300          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
301          (number_lines-1.0)*height)/2.0;
302        break;
303      }
304      case EastGravity:
305      {
306        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
307          geometry.width+i*annotate_info->affine.ry*height-
308          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
309          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
310          (number_lines-1.0)*height)/2.0;
311        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
312          geometry.height/2.0+i*annotate_info->affine.sy*height-
313          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
314          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
315          (number_lines-1.0)*height)/2.0;
316        break;
317      }
318      case SouthWestGravity:
319      {
320        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
321          annotate_info->affine.ry*height-annotate_info->affine.ry*
322          (number_lines-1.0)*height;
323        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
324          geometry.height+i*annotate_info->affine.sy*height-
325          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
326        break;
327      }
328      case SouthGravity:
329      {
330        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
331          geometry.width/2.0+i*annotate_info->affine.ry*height-
332          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
333          annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
334        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
335          geometry.height+i*annotate_info->affine.sy*height-
336          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
337          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
338        break;
339      }
340      case SouthEastGravity:
341      {
342        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
343          geometry.width+i*annotate_info->affine.ry*height-
344          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
345          annotate_info->affine.ry*(number_lines-1.0)*height;
346        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
347          geometry.height+i*annotate_info->affine.sy*height-
348          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
349          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
350        break;
351      }
352    }
353    switch (annotate->align)
354    {
355      case LeftAlign:
356      {
357        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
358        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
359        break;
360      }
361      case CenterAlign:
362      {
363        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
364          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
365        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
366          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
367        break;
368      }
369      case RightAlign:
370      {
371        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
372          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
373        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
374          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
375        break;
376      }
377      default:
378        break;
379    }
380    if (draw_info->undercolor.opacity != TransparentOpacity)
381      {
382        DrawInfo
383          *undercolor_info;
384
385        /*
386          Text box.
387        */
388        undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
389        undercolor_info->fill=draw_info->undercolor;
390        undercolor_info->affine=draw_info->affine;
391        undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
392        undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
393        (void) FormatMagickString(primitive,MaxTextExtent,
394          "rectangle 0,0 %g,%ld",metrics.origin.x,height);
395        (void) CloneString(&undercolor_info->primitive,primitive);
396        (void) DrawImage(image,undercolor_info);
397        (void) DestroyDrawInfo(undercolor_info);
398      }
399    annotate_info->affine.tx=offset.x;
400    annotate_info->affine.ty=offset.y;
401    (void) FormatMagickString(primitive,MaxTextExtent,"stroke-width %g "
402      "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
403    if (annotate->decorate == OverlineDecoration)
404      {
405        annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
406          metrics.descent-metrics.underline_position+2));
407        (void) CloneString(&annotate_info->primitive,primitive);
408        (void) DrawImage(image,annotate_info);
409      }
410    else
411      if (annotate->decorate == UnderlineDecoration)
412        {
413          annotate_info->affine.ty-=(draw_info->affine.sy*
414            metrics.underline_position+2);
415          (void) CloneString(&annotate_info->primitive,primitive);
416          (void) DrawImage(image,annotate_info);
417        }
418    /*
419      Annotate image with text.
420    */
421    status=RenderType(image,annotate,&offset,&metrics);
422    if (status == MagickFalse)
423      break;
424    if (annotate->decorate == LineThroughDecoration)
425      {
426        annotate_info->affine.ty-=(draw_info->affine.sy*(height+
427          metrics.underline_position+metrics.descent)/2.0);
428        (void) CloneString(&annotate_info->primitive,primitive);
429        (void) DrawImage(image,annotate_info);
430      }
431  }
432  /*
433    Relinquish resources.
434  */
435  annotate_info=DestroyDrawInfo(annotate_info);
436  annotate=DestroyDrawInfo(annotate);
437  for (i=0; textlist[i] != (char *) NULL; i++)
438    textlist[i]=DestroyString(textlist[i]);
439  textlist=(char **) RelinquishMagickMemory(textlist);
440  return(status);
441}
442
443#if defined(MAGICKCORE_FREETYPE_DELEGATE)
444/*
445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446%                                                                             %
447%                                                                             %
448%                                                                             %
449+   E n c o d e S J I S                                                       %
450%                                                                             %
451%                                                                             %
452%                                                                             %
453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454%
455%  EncodeSJIS() converts an ASCII text string to 2-bytes per character code
456%  (like UCS-2).  Returns the translated codes and the character count.
457%  Characters under 0x7f are just copied, characters over 0x80 are tied with
458%  the next character.
459%
460%  Katsutoshi Shibuya contributed this method.
461%
462%  The format of the EncodeSJIS function is:
463%
464%      encoding=EncodeSJIS(const Image *image,const char *text,size_t count)
465%
466%  A description of each parameter follows:
467%
468%    o image: the image.
469%
470%    o text: the text.
471%
472%    o count: return the number of characters generated by the encoding.
473%
474*/
475
476static int GetOneCharacter(const unsigned char *text,size_t *length)
477{
478  int
479    c;
480
481  if (*length < 1)
482    return(-1);
483  c=text[0];
484  if ((c & 0x80) == 0)
485    {
486      *length=1;
487      return((int) c);
488    }
489  if (*length < 2)
490    {
491      *length=0;
492      return(-1);
493    }
494  *length=2;
495  c=((int) (text[0]) << 8);
496  c|=text[1];
497  return((int) c);
498}
499
500static unsigned long *EncodeSJIS(const char *text,size_t *count)
501{
502  int
503    c;
504
505  register const char
506    *p;
507
508  register unsigned long
509    *q;
510
511  size_t
512    length;
513
514  unsigned long
515    *encoding;
516
517  *count=0;
518  if ((text == (char *) NULL) || (*text == '\0'))
519    return((unsigned long *) NULL);
520  length=strlen(text);
521  if (~length < MaxTextExtent)
522    return((unsigned long *) NULL);
523  length+=MaxTextExtent;
524  encoding=(unsigned long *) AcquireQuantumMemory(length,sizeof(*encoding));
525  if (encoding == (unsigned long *) NULL)
526    return((unsigned long *) NULL);
527  q=encoding;
528  for (p=text; *p != '\0'; p+=length)
529  {
530    length=strlen(p);
531    c=GetOneCharacter((const unsigned char *) p,&length);
532    if (c < 0)
533      {
534        q=encoding;
535        for (p=text; *p != '\0'; p++)
536          *q++=(unsigned char) *p;
537        break;
538      }
539    *q=(unsigned long) c;
540    q++;
541  }
542  *count=q-encoding;
543  return(encoding);
544}
545#endif
546
547#if defined(MAGICKCORE_FREETYPE_DELEGATE)
548/*
549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550%                                                                             %
551%                                                                             %
552%                                                                             %
553+   E n c o d e T e x t                                                       %
554%                                                                             %
555%                                                                             %
556%                                                                             %
557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
558%
559%  EncodeText() converts an ASCII text string to wide text and returns the
560%  translation and the character count.
561%
562%  The format of the EncodeText function is:
563%
564%      encoding=EncodeText(const char *text,size_t count)
565%
566%  A description of each parameter follows:
567%
568%    o text: the text.
569%
570%    o count: return the number of characters generated by the encoding.
571%
572*/
573static unsigned long *EncodeText(const char *text,size_t *count)
574{
575  register const char
576    *p;
577
578  register unsigned long
579    *q;
580
581  size_t
582    length;
583
584  unsigned long
585    *encoding;
586
587  *count=0;
588  if ((text == (char *) NULL) || (*text == '\0'))
589    return((unsigned long *) NULL);
590  length=strlen(text);
591  if (~length < MaxTextExtent)
592    return((unsigned long *) NULL);
593  length+=MaxTextExtent;
594  encoding=(unsigned long *) AcquireQuantumMemory(length,sizeof(*encoding));
595  if (encoding == (unsigned long *) NULL)
596    return((unsigned long *) NULL);
597  q=encoding;
598  for (p=text; *p != '\0'; p++)
599    *q++=(unsigned char) *p;
600  *count=q-encoding;
601  return(encoding);
602}
603#endif
604
605#if defined(MAGICKCORE_FREETYPE_DELEGATE)
606/*
607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608%                                                                             %
609%                                                                             %
610%                                                                             %
611+   E n c o d e U n i c o d e                                                 %
612%                                                                             %
613%                                                                             %
614%                                                                             %
615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616%
617%  EncodeUnicode() converts an ASCII text string to Unicode and returns the
618%  Unicode translation and the character count.  Characters under 0x7f are
619%  just copied, characters over 0x80 are tied with the next character.
620%
621%  The format of the EncodeUnicode function is:
622%
623%      unsigned short *EncodeUnicode(const unsigned char *text,size_t count)
624%
625%  A description of each parameter follows:
626%
627%    o unicode:  EncodeUnicode() returns a pointer to an unsigned short array
628%      representing the encoded version of the ASCII string.
629%
630%    o text: the text.
631%
632%    o count: return the number of characters generated by the encoding.
633%
634*/
635
636static long GetUnicodeCharacter(const unsigned char *text,size_t *length)
637{
638  unsigned long
639    c;
640
641  if (*length < 1)
642    return(-1);
643  c=text[0];
644  if ((c & 0x80) == 0)
645    {
646      *length=1;
647      return((long) c);
648    }
649  if ((*length < 2) || ((text[1] & 0xc0) != 0x80))
650    {
651      *length=0;
652      return(-1);
653    }
654  if ((c & 0xe0) != 0xe0)
655    {
656      *length=2;
657      c=(text[0] & 0x1f) << 6;
658      c|=text[1] & 0x3f;
659      return((long) c);
660    }
661  if ((*length < 3) || ((text[2] & 0xc0) != 0x80))
662    {
663      *length=0;
664      return(-1);
665    }
666  if ((c & 0xf0) != 0xf0)
667    {
668      *length=3;
669      c=(text[0] & 0xf) << 12;
670      c|=(text[1] & 0x3f) << 6;
671      c|=text[2] & 0x3f;
672      return((long) c);
673    }
674  if ((*length < 4) || ((c & 0xf8) != 0xf0) || ((text[3] & 0xc0) != 0x80))
675    {
676      *length=0;
677      return(-1);
678    }
679  *length=4;
680  c=(text[0] & 0x7) << 18;
681  c|=(text[1] & 0x3f) << 12;
682  c|=(text[2] & 0x3f) << 6;
683  c|=text[3] & 0x3f;
684  return((long) c);
685}
686
687static unsigned long *EncodeUnicode(const char *text,size_t *count)
688{
689  long
690    c;
691
692  register const char
693    *p;
694
695  register unsigned long
696    *q;
697
698  size_t
699    length;
700
701  unsigned long
702    *unicode;
703
704  *count=0;
705  if ((text == (char *) NULL) || (*text == '\0'))
706    return((unsigned long *) NULL);
707  length=strlen(text);
708  if (~length < MaxTextExtent)
709    return((unsigned long *) NULL);
710  length+=MaxTextExtent;
711  unicode=(unsigned long *) AcquireQuantumMemory(length,sizeof(*unicode));
712  if (unicode == (unsigned long *) NULL)
713    return((unsigned long *) NULL);
714  q=unicode;
715  for (p=text; *p != '\0'; p+=length)
716  {
717    length=strlen(p);
718    c=GetUnicodeCharacter((const unsigned char *) p,&length);
719    if (c < 0)
720      {
721        q=unicode;
722        for (p=text; *p != '\0'; p++)
723          *q++=(unsigned char) *p;
724        break;
725      }
726    *q=(unsigned long) c;
727    q++;
728  }
729  *count=q-unicode;
730  return(unicode);
731}
732#endif
733
734/*
735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736%                                                                             %
737%                                                                             %
738%                                                                             %
739%  F o r m a t M a g i c k C a p t i o n                                      %
740%                                                                             %
741%                                                                             %
742%                                                                             %
743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744%
745%  FormatMagickCaption() formats a caption so that it fits within the image
746%  width.  It returns the number of lines in the formatted caption.
747%
748%  The format of the FormatMagickCaption method is:
749%
750%      long FormatMagickCaption(Image *image,DrawInfo *draw_info,char *caption,
751%        TypeMetric *metrics)
752%
753%  A description of each parameter follows.
754%
755%    o image:  The image.
756%
757%    o draw_info: the draw info.
758%
759%    o metrics: Return the font metrics in this structure.
760%
761*/
762MagickExport long FormatMagickCaption(Image *image,DrawInfo *draw_info,
763  char *caption,TypeMetric *metrics)
764{
765  MagickBooleanType
766    status;
767
768  register char
769    *p,
770    *q,
771    *s;
772
773  register long
774    i;
775
776  unsigned long
777    width;
778
779  q=draw_info->text;
780  s=(char *) NULL;
781  for (p=caption; *p != '\0'; p++)
782  {
783    if (isspace((int) ((unsigned char) *p)) != 0)
784      s=p;
785    *q++=(*p);
786    *q='\0';
787    status=GetTypeMetrics(image,draw_info,metrics);
788    if (status == MagickFalse)
789      break;
790    width=(unsigned long) (metrics->width+0.5);
791    if (*p != '\n')
792      if (width <= image->columns)
793        continue;
794    if (s == (char *) NULL)
795      {
796        s=p;
797        while ((isspace((int) ((unsigned char) *s)) == 0) && (*s != '\0'))
798          s++;
799      }
800    if (*s != '\0')
801      {
802        *s='\n';
803        p=s;
804        s=(char *) NULL;
805      }
806    q=draw_info->text;
807  }
808  i=0;
809  for (p=caption; *p != '\0'; p++)
810    if (*p == '\n')
811      i++;
812  return(i);
813}
814
815/*
816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817%                                                                             %
818%                                                                             %
819%                                                                             %
820%   G e t M u l t i l i n e T y p e M e t r i c s                             %
821%                                                                             %
822%                                                                             %
823%                                                                             %
824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825%
826%  GetMultilineTypeMetrics() returns the following information for the
827%  specified font and text:
828%
829%    character width
830%    character height
831%    ascender
832%    descender
833%    text width
834%    text height
835%    maximum horizontal advance
836%    bounds: x1
837%    bounds: y1
838%    bounds: x2
839%    bounds: y2
840%    origin: x
841%    origin: y
842%    underline position
843%    underline thickness
844%
845%  This method is like GetTypeMetrics() but it returns the maximum text width
846%  and height for multiple lines of text.
847%
848%  The format of the GetMultilineTypeMetrics method is:
849%
850%      MagickBooleanType GetMultilineTypeMetrics(Image *image,
851%        const DrawInfo *draw_info,TypeMetric *metrics)
852%
853%  A description of each parameter follows:
854%
855%    o image: the image.
856%
857%    o draw_info: the draw info.
858%
859%    o metrics: Return the font metrics in this structure.
860%
861*/
862MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
863  const DrawInfo *draw_info,TypeMetric *metrics)
864{
865  char
866    **textlist;
867
868  DrawInfo
869    *annotate_info;
870
871  MagickBooleanType
872    status;
873
874  register long
875    i;
876
877  TypeMetric
878    extent;
879
880  unsigned long
881    number_lines;
882
883  assert(image != (Image *) NULL);
884  assert(image->signature == MagickSignature);
885  if (image->debug != MagickFalse)
886    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
887  assert(draw_info != (DrawInfo *) NULL);
888  assert(draw_info->text != (char *) NULL);
889  assert(draw_info->signature == MagickSignature);
890  if (*draw_info->text == '\0')
891    return(MagickFalse);
892  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
893  annotate_info->text=DestroyString(annotate_info->text);
894  /*
895    Convert newlines to multiple lines of text.
896  */
897  textlist=StringToList(draw_info->text);
898  if (textlist == (char **) NULL)
899    return(MagickFalse);
900  annotate_info->render=MagickFalse;
901  (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
902  (void) ResetMagickMemory(&extent,0,sizeof(extent));
903  /*
904    Find the widest of the text lines.
905  */
906  annotate_info->text=textlist[0];
907  status=GetTypeMetrics(image,annotate_info,&extent);
908  *metrics=extent;
909  for (i=1; textlist[i] != (char *) NULL; i++)
910  {
911    annotate_info->text=textlist[i];
912    status=GetTypeMetrics(image,annotate_info,&extent);
913    if (extent.width > metrics->width)
914      *metrics=extent;
915  }
916  number_lines=(unsigned long) i;
917  metrics->height=(double) number_lines*(long) (metrics->ascent-
918    metrics->descent+0.5);
919  /*
920    Relinquish resources.
921  */
922  annotate_info->text=(char *) NULL;
923  annotate_info=DestroyDrawInfo(annotate_info);
924  for (i=0; textlist[i] != (char *) NULL; i++)
925    textlist[i]=DestroyString(textlist[i]);
926  textlist=(char **) RelinquishMagickMemory(textlist);
927  return(status);
928}
929
930/*
931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932%                                                                             %
933%                                                                             %
934%                                                                             %
935%   G e t T y p e M e t r i c s                                               %
936%                                                                             %
937%                                                                             %
938%                                                                             %
939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
940%
941%  GetTypeMetrics() returns the following information for the specified font
942%  and text:
943%
944%    character width
945%    character height
946%    ascender
947%    descender
948%    text width
949%    text height
950%    maximum horizontal advance
951%    bounds: x1
952%    bounds: y1
953%    bounds: x2
954%    bounds: y2
955%    origin: x
956%    origin: y
957%    underline position
958%    underline thickness
959%
960%  The format of the GetTypeMetrics method is:
961%
962%      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
963%        TypeMetric *metrics)
964%
965%  A description of each parameter follows: