MagickCore  7.1.0
Convert, Edit, Or Compose Bitmap Images
annotate.c
Go to the documentation of this file.
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 % MagickCore Image Annotation Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright @ 1999 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 % https://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 "MagickCore/studio.h"
46 #include "MagickCore/annotate.h"
48 #include "MagickCore/attribute.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/client.h"
53 #include "MagickCore/color.h"
56 #include "MagickCore/composite.h"
58 #include "MagickCore/constitute.h"
59 #include "MagickCore/draw.h"
61 #include "MagickCore/enhance.h"
62 #include "MagickCore/exception.h"
64 #include "MagickCore/gem.h"
65 #include "MagickCore/geometry.h"
67 #include "MagickCore/log.h"
68 #include "MagickCore/quantum.h"
71 #include "MagickCore/policy.h"
72 #include "MagickCore/property.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/semaphore.h"
75 #include "MagickCore/statistic.h"
76 #include "MagickCore/string_.h"
77 #include "MagickCore/token.h"
79 #include "MagickCore/transform.h"
81 #include "MagickCore/type.h"
82 #include "MagickCore/utility.h"
84 #include "MagickCore/xwindow.h"
86 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
87 #if defined(__MINGW32__)
88 # undef interface
89 #endif
90 #include <ft2build.h>
91 #if defined(FT_FREETYPE_H)
92 # include FT_FREETYPE_H
93 #else
94 # include <freetype/freetype.h>
95 #endif
96 #if defined(FT_GLYPH_H)
97 # include FT_GLYPH_H
98 #else
99 # include <freetype/ftglyph.h>
100 #endif
101 #if defined(FT_OUTLINE_H)
102 # include FT_OUTLINE_H
103 #else
104 # include <freetype/ftoutln.h>
105 #endif
106 #if defined(FT_BBOX_H)
107 # include FT_BBOX_H
108 #else
109 # include <freetype/ftbbox.h>
110 #endif /* defined(FT_BBOX_H) */
111 #endif
112 #if defined(MAGICKCORE_RAQM_DELEGATE)
113 #include <raqm.h>
114 #endif
115 typedef struct _GraphemeInfo
116 {
117  size_t
119  x_offset,
120  x_advance,
121  y_offset;
122 
123  size_t
125 } GraphemeInfo;
126 
127 /*
128  Annotate semaphores.
129 */
130 static SemaphoreInfo
132 
133 /*
134  Forward declarations.
135 */
136 static MagickBooleanType
137  RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
138  ExceptionInfo *),
139  RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
140  ExceptionInfo *),
141  RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
143  RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *,
144  ExceptionInfo *);
145 
146 /*
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 % %
149 % %
150 % %
151 + A n n o t a t e C o m p o n e n t G e n e s i s %
152 % %
153 % %
154 % %
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 %
157 % AnnotateComponentGenesis() instantiates the annotate component.
158 %
159 % The format of the AnnotateComponentGenesis method is:
160 %
161 % MagickBooleanType AnnotateComponentGenesis(void)
162 %
163 */
165 {
166  if (annotate_semaphore == (SemaphoreInfo *) NULL)
168  return(MagickTrue);
169 }
170 
171 /*
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % %
174 % %
175 % %
176 + A n n o t a t e C o m p o n e n t T e r m i n u s %
177 % %
178 % %
179 % %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
181 %
182 % AnnotateComponentTerminus() destroys the annotate component.
183 %
184 % The format of the AnnotateComponentTerminus method is:
185 %
186 % AnnotateComponentTerminus(void)
187 %
188 */
190 {
191  if (annotate_semaphore == (SemaphoreInfo *) NULL)
194 }
195 
196 /*
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % %
199 % %
200 % %
201 % A n n o t a t e I m a g e %
202 % %
203 % %
204 % %
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 %
207 % AnnotateImage() annotates an image with text.
208 %
209 % The format of the AnnotateImage method is:
210 %
211 % MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info,
212 % ExceptionInfo *exception)
213 %
214 % A description of each parameter follows:
215 %
216 % o image: the image.
217 %
218 % o draw_info: the draw info.
219 %
220 % o exception: return any errors or warnings in this structure.
221 %
222 */
224  const DrawInfo *draw_info,ExceptionInfo *exception)
225 {
226  char
227  *p,
228  color[MagickPathExtent],
229  primitive[MagickPathExtent],
230  *text,
231  **textlist;
232 
233  DrawInfo
234  *annotate,
235  *annotate_info;
236 
238  geometry_info;
239 
241  status;
242 
243  PixelInfo
244  pixel;
245 
246  PointInfo
247  offset;
248 
250  geometry;
251 
252  ssize_t
253  i;
254 
255  TypeMetric
256  metrics;
257 
258  size_t
259  height,
260  number_lines;
261 
262  assert(image != (Image *) NULL);
263  assert(image->signature == MagickCoreSignature);
264  if (IsEventLogging() != MagickFalse)
265  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
266  assert(draw_info != (DrawInfo *) NULL);
267  assert(draw_info->signature == MagickCoreSignature);
268  if (draw_info->text == (char *) NULL)
269  return(MagickFalse);
270  if (*draw_info->text == '\0')
271  return(MagickTrue);
272  annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
273  text=annotate->text;
274  annotate->text=(char *) NULL;
275  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
276  number_lines=1;
277  for (p=text; *p != '\0'; p++)
278  if (*p == '\n')
279  number_lines++;
280  textlist=(char **) AcquireQuantumMemory(number_lines+1,sizeof(*textlist));
281  if (textlist == (char **) NULL)
282  {
283  annotate_info=DestroyDrawInfo(annotate_info);
284  annotate=DestroyDrawInfo(annotate);
285  text=DestroyString(text);
286  return(MagickFalse);
287  }
288  p=text;
289  for (i=0; i < (ssize_t) number_lines; i++)
290  {
291  char
292  *q;
293 
294  textlist[i]=p;
295  for (q=p; *q != '\0'; q++)
296  if ((*q == '\r') || (*q == '\n'))
297  break;
298  if (*q == '\r')
299  {
300  *q='\0';
301  q++;
302  }
303  *q='\0';
304  p=q+1;
305  }
306  textlist[i]=(char *) NULL;
307  SetGeometry(image,&geometry);
308  SetGeometryInfo(&geometry_info);
309  if (annotate_info->geometry != (char *) NULL)
310  {
311  (void) ParsePageGeometry(image,annotate_info->geometry,&geometry,
312  exception);
313  (void) ParseGeometry(annotate_info->geometry,&geometry_info);
314  }
315  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
316  {
317  annotate_info=DestroyDrawInfo(annotate_info);
318  annotate=DestroyDrawInfo(annotate);
319  textlist=(char **) RelinquishMagickMemory(textlist);
320  text=DestroyString(text);
321  return(MagickFalse);
322  }
323  if (IsGrayColorspace(image->colorspace) != MagickFalse)
324  (void) SetImageColorspace(image,sRGBColorspace,exception);
325  status=MagickTrue;
326  (void) memset(&metrics,0,sizeof(metrics));
327  for (i=0; textlist[i] != (char *) NULL; i++)
328  {
329  if (*textlist[i] == '\0')
330  continue;
331  /*
332  Position text relative to image.
333  */
334  annotate_info->affine.tx=geometry_info.xi-image->page.x;
335  annotate_info->affine.ty=geometry_info.psi-image->page.y;
336  (void) CloneString(&annotate->text,textlist[i]);
337  if ((metrics.width == 0) || (annotate->gravity != NorthWestGravity))
338  (void) GetTypeMetrics(image,annotate,&metrics,exception);
339  height=(size_t) floor(metrics.ascent-metrics.descent+0.5);
340  if (height == 0)
341  height=draw_info->pointsize;
342  height+=(size_t) floor(draw_info->interline_spacing+0.5);
343  switch (annotate->gravity)
344  {
345  case UndefinedGravity:
346  default:
347  {
348  offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
349  offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
350  break;
351  }
352  case NorthWestGravity:
353  {
354  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
355  annotate_info->affine.ry*height+annotate_info->affine.ry*
356  (metrics.ascent+metrics.descent);
357  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
358  annotate_info->affine.sy*height+annotate_info->affine.sy*
359  metrics.ascent;
360  break;
361  }
362  case NorthGravity:
363  {
364  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
365  geometry.width/2.0+i*annotate_info->affine.ry*height-
366  annotate_info->affine.sx*metrics.width/2.0+annotate_info->affine.ry*
367  (metrics.ascent+metrics.descent);
368  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
369  annotate_info->affine.sy*height+annotate_info->affine.sy*
370  metrics.ascent-annotate_info->affine.rx*metrics.width/2.0;
371  break;
372  }
373  case NorthEastGravity:
374  {
375  offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
376  geometry.width+i*annotate_info->affine.ry*height-
377  annotate_info->affine.sx*metrics.width+annotate_info->affine.ry*
378  (metrics.ascent+metrics.descent)-1.0;
379  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
380  annotate_info->affine.sy*height+annotate_info->affine.sy*
381  metrics.ascent-annotate_info->affine.rx*metrics.width;
382  break;
383  }
384  case WestGravity:
385  {
386  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
387  annotate_info->affine.ry*height+annotate_info->affine.ry*
388  (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
389  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
390  geometry.height/2.0+i*annotate_info->affine.sy*height+
391  annotate_info->affine.sy*(metrics.ascent+metrics.descent-
392  (number_lines-1.0)*height)/2.0;
393  break;
394  }
395  case CenterGravity:
396  {
397  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
398  geometry.width/2.0+i*annotate_info->affine.ry*height-
399  annotate_info->affine.sx*metrics.width/2.0+annotate_info->affine.ry*
400  (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
401  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
402  geometry.height/2.0+i*annotate_info->affine.sy*height-
403  annotate_info->affine.rx*metrics.width/2.0+annotate_info->affine.sy*
404  (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
405  break;
406  }
407  case EastGravity:
408  {
409  offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
410  geometry.width+i*annotate_info->affine.ry*height-
411  annotate_info->affine.sx*metrics.width+
412  annotate_info->affine.ry*(metrics.ascent+metrics.descent-
413  (number_lines-1.0)*height)/2.0-1.0;
414  offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
415  geometry.height/2.0+i*annotate_info->affine.sy*height-
416  annotate_info->affine.rx*metrics.width+
417  annotate_info->affine.sy*(metrics.ascent+metrics.descent-
418  (number_lines-1.0)*height)/2.0;
419  break;
420  }
421  case SouthWestGravity:
422  {
423  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
424  annotate_info->affine.ry*height-annotate_info->affine.ry*
425  (number_lines-1.0)*height;
426  offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
427  geometry.height+i*annotate_info->affine.sy*height-
428  annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
429  break;
430  }
431  case SouthGravity:
432  {
433  offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
434  geometry.width/2.0+i*annotate_info->affine.ry*height-
435  annotate_info->affine.sx*metrics.width/2.0-
436  annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
437  offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
438  geometry.height+i*annotate_info->affine.sy*height-
439  annotate_info->affine.rx*metrics.width/2.0-
440  annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
441  break;
442  }
443  case SouthEastGravity:
444  {
445  offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
446  geometry.width+i*annotate_info->affine.ry*height-
447  annotate_info->affine.sx*metrics.width-
448  annotate_info->affine.ry*(number_lines-1.0)*height-1.0;
449  offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
450  geometry.height+i*annotate_info->affine.sy*height-
451  annotate_info->affine.rx*metrics.width-
452  annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
453  break;
454  }
455  }
456  switch (annotate->align)
457  {
458  case LeftAlign:
459  {
460  offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
461  offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
462  break;
463  }
464  case CenterAlign:
465  {
466  offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
467  annotate_info->affine.sx*metrics.width/2.0;
468  offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
469  annotate_info->affine.rx*metrics.width/2.0;
470  break;
471  }
472  case RightAlign:
473  {
474  offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
475  annotate_info->affine.sx*metrics.width;
476  offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
477  annotate_info->affine.rx*metrics.width;
478  break;
479  }
480  default:
481  break;
482  }
483  if (draw_info->undercolor.alpha != TransparentAlpha)
484  {
485  DrawInfo
486  *undercolor_info;
487 
488  /*
489  Text box.
490  */
491  undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
492  undercolor_info->fill=draw_info->undercolor;
493  undercolor_info->affine=draw_info->affine;
494  undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
495  undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
496  (void) FormatLocaleString(primitive,MagickPathExtent,
497  "rectangle 0.0,0.0 %g,%g",metrics.origin.x,(double) height);
498  (void) CloneString(&undercolor_info->primitive,primitive);
499  (void) DrawImage(image,undercolor_info,exception);
500  (void) DestroyDrawInfo(undercolor_info);
501  }
502  annotate_info->affine.tx=offset.x;
503  annotate_info->affine.ty=offset.y;
504  pixel=annotate_info->fill;
505  if (annotate_info->stroke.alpha != TransparentAlpha)
506  pixel=annotate_info->stroke;
507  (void) QueryColorname(image,&pixel,AllCompliance,color,exception);
508  (void) FormatLocaleString(primitive,MagickPathExtent,"stroke %s "
509  "stroke-width %g line 0,0 %g,0",color,(double)
510  metrics.underline_thickness,(double) metrics.width);
511  /*
512  Annotate image with text.
513  */
514  switch (annotate->decorate)
515  {
516  case OverlineDecoration:
517  {
518  annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
519  metrics.descent-metrics.underline_position));
520  (void) CloneString(&annotate_info->primitive,primitive);
521  (void) DrawImage(image,annotate_info,exception);
522  break;
523  }
524  case UnderlineDecoration:
525  {
526  annotate_info->affine.ty-=(draw_info->affine.sy*
527  metrics.underline_position);
528  (void) CloneString(&annotate_info->primitive,primitive);
529  (void) DrawImage(image,annotate_info,exception);
530  break;
531  }
532  default:
533  break;
534  }
535  status=RenderType(image,annotate,&offset,&metrics,exception);
536  if (status == MagickFalse)
537  break;
538 
539  if (annotate->decorate == LineThroughDecoration) {
540  annotate_info->affine.ty-=(draw_info->affine.sy*(height+
541  metrics.underline_position+metrics.descent*2)/2.0);
542  (void) CloneString(&annotate_info->primitive,primitive);
543  (void) DrawImage(image,annotate_info,exception);
544  }
545  }
546  /*
547  Relinquish resources.
548  */
549  annotate_info=DestroyDrawInfo(annotate_info);
550  annotate=DestroyDrawInfo(annotate);
551  textlist=(char **) RelinquishMagickMemory(textlist);
552  text=DestroyString(text);
553  return(status);
554 }
555 
556 /*
557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
558 % %
559 % %
560 % %
561 % F o r m a t M a g i c k C a p t i o n %
562 % %
563 % %
564 % %
565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
566 %
567 % FormatMagickCaption() formats a caption so that it fits within the image
568 % width. It returns the number of lines in the formatted caption.
569 %
570 % The format of the FormatMagickCaption method is:
571 %
572 % ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
573 % const MagickBooleanType split,TypeMetric *metrics,char **caption,
574 % ExceptionInfo *exception)
575 %
576 % A description of each parameter follows.
577 %
578 % o image: The image.
579 %
580 % o draw_info: the draw info.
581 %
582 % o split: when no convenient line breaks-- insert newline.
583 %
584 % o metrics: Return the font metrics in this structure.
585 %
586 % o caption: the caption.
587 %
588 % o exception: return any errors or warnings in this structure.
589 %
590 */
591 
592 static inline char *ReplaceSpaceWithNewline(char **caption,char *space)
593 {
594  size_t
595  octets;
596 
597  octets=(size_t) GetUTFOctets(space);
598  if (octets == 1)
599  *space='\n';
600  else
601  {
602  char
603  *target;
604 
605  size_t
606  length,
607  offset;
608 
609  length=strlen(*caption);
610  *space='\n';
611  offset=space-(*caption);
612  target=AcquireString(*caption);
613  CopyMagickString(target,*caption,offset+2);
614  ConcatenateMagickString(target,space+octets,length);
615  (void) DestroyString(*caption);
616  *caption=target;
617  space=(*caption)+offset;
618  }
619  return(space);
620 }
621 
622 MagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
623  const MagickBooleanType split,TypeMetric *metrics,char **caption,
624  ExceptionInfo *exception)
625 {
627  status;
628 
629  char
630  *p,
631  *q,
632  *s;
633 
634  size_t
635  width;
636 
637  ssize_t
638  i,
639  n;
640 
641  q=draw_info->text;
642  s=(char *) NULL;
643  width=0;
644  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
645  {
646  int
647  code;
648 
649  code=GetUTFCode(p);
650  if (code == '\n')
651  {
652  q=draw_info->text;
653  continue;
654  }
655  if ((IsUTFSpace(code) != MagickFalse) &&
657  {
658  s=p;
659  if (width > image->columns)
660  p=ReplaceSpaceWithNewline(caption,s);
661  }
662  for (i=0; i < (ssize_t) GetUTFOctets(p); i++)
663  *q++=(*(p+i));
664  *q='\0';
665  status=GetTypeMetrics(image,draw_info,metrics,exception);
666  if (status == MagickFalse)
667  break;
668  width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5);
669  if (width <= image->columns)
670  continue;
671  if (s != (char *) NULL)
672  p=ReplaceSpaceWithNewline(caption,s);
673  else
674  if ((split != MagickFalse) || (GetUTFOctets(p) > 2))
675  {
676  /*
677  No convenient line breaks-- insert newline.
678  */
679  n=p-(*caption);
680  if ((n > 0) && ((*caption)[n-1] != '\n'))
681  {
682  char
683  *target;
684 
685  target=AcquireString(*caption);
686  CopyMagickString(target,*caption,n+1);
687  ConcatenateMagickString(target,"\n",strlen(*caption)+1);
688  ConcatenateMagickString(target,p,strlen(*caption)+2);
689  (void) DestroyString(*caption);
690  *caption=target;
691  p=(*caption)+n;
692  }
693  }
694  q=draw_info->text;
695  s=(char *) NULL;
696  }
697  n=0;
698  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
699  if (GetUTFCode(p) == '\n')
700  n++;
701  return(n);
702 }
703 
704 /*
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 % %
707 % %
708 % %
709 % G e t M u l t i l i n e T y p e M e t r i c s %
710 % %
711 % %
712 % %
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 %
715 % GetMultilineTypeMetrics() returns the following information for the
716 % specified font and text:
717 %
718 % character width
719 % character height
720 % ascender
721 % descender
722 % text width
723 % text height
724 % maximum horizontal advance
725 % bounds: x1
726 % bounds: y1
727 % bounds: x2
728 % bounds: y2
729 % origin: x
730 % origin: y
731 % underline position
732 % underline thickness
733 %
734 % This method is like GetTypeMetrics() but it returns the maximum text width
735 % and height for multiple lines of text.
736 %
737 % The format of the GetMultilineTypeMetrics method is:
738 %
739 % MagickBooleanType GetMultilineTypeMetrics(Image *image,
740 % const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
741 %
742 % A description of each parameter follows:
743 %
744 % o image: the image.
745 %
746 % o draw_info: the draw info.
747 %
748 % o metrics: Return the font metrics in this structure.
749 %
750 % o exception: return any errors or warnings in this structure.
751 %
752 */
754  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
755 {
756  char
757  **textlist;
758 
759  double
760  height;
761 
762  DrawInfo
763  *annotate_info;
764 
766  status;
767 
769  size;
770 
771  ssize_t
772  i;
773 
774  size_t
775  count;
776 
777  TypeMetric
778  extent;
779 
780  assert(image != (Image *) NULL);
781  assert(image->signature == MagickCoreSignature);
782  if (IsEventLogging() != MagickFalse)
783  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
784  assert(draw_info != (DrawInfo *) NULL);
785  assert(draw_info->text != (char *) NULL);
786  assert(draw_info->signature == MagickCoreSignature);
787  if (*draw_info->text == '\0')
788  return(MagickFalse);
789  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
790  annotate_info->text=DestroyString(annotate_info->text);
791  /*
792  Convert newlines to multiple lines of text.
793  */
794  textlist=StringToStrings(draw_info->text,&count);
795  if (textlist == (char **) NULL)
796  return(MagickFalse);
797  annotate_info->render=MagickFalse;
798  annotate_info->direction=UndefinedDirection;
799  (void) memset(metrics,0,sizeof(*metrics));
800  (void) memset(&extent,0,sizeof(extent));
801  /*
802  Find the widest of the text lines.
803  */
804  annotate_info->text=textlist[0];
805  status=GetTypeMetrics(image,annotate_info,&extent,exception);
806  *metrics=extent;
807  height=(count*(size_t) (metrics->ascent-metrics->descent+
808  0.5)+(count-1)*draw_info->interline_spacing);
809  size=(MagickSizeType) fabs(height);
811  {
813  "WidthOrHeightExceedsLimit","`%s'",image->filename);
814  status=MagickFalse;
815  }
816  else
817  {
818  for (i=1; i < (ssize_t) count; i++)
819  {
820  annotate_info->text=textlist[i];
821  status=GetTypeMetrics(image,annotate_info,&extent,exception);
822  if (status == MagickFalse)
823  break;
824  if (extent.width > metrics->width)
825  *metrics=extent;
826  size=(MagickSizeType) fabs(extent.width);
828  {
830  "WidthOrHeightExceedsLimit","`%s'",image->filename);
831  status=MagickFalse;
832  break;
833  }
834  }
835  metrics->height=(double) height;
836  }
837  /*
838  Relinquish resources.
839  */
840  annotate_info->text=(char *) NULL;
841  annotate_info=DestroyDrawInfo(annotate_info);
842  for (i=0; i < (ssize_t) count; i++)
843  textlist[i]=DestroyString(textlist[i]);
844  textlist=(char **) RelinquishMagickMemory(textlist);
845  return(status);
846 }
847 
848 /*
849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % %
851 % %
852 % %
853 % G e t T y p e M e t r i c s %
854 % %
855 % %
856 % %
857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 %
859 % GetTypeMetrics() returns the following information for the specified font
860 % and text:
861 %
862 % character width
863 % character height
864 % ascender
865 % descender
866 % text width
867 % text height
868 % maximum horizontal advance
869 % bounds: x1
870 % bounds: y1
871 % bounds: x2
872 % bounds: y2
873 % origin: x
874 % origin: y
875 % underline position
876 % underline thickness
877 %
878 % The format of the GetTypeMetrics method is:
879 %
880 % MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
881 % TypeMetric *metrics,ExceptionInfo *exception)
882 %
883 % A description of each parameter follows:
884 %
885 % o image: the image.
886 %
887 % o draw_info: the draw info.
888 %
889 % o metrics: Return the font metrics in this structure.
890 %
891 % o exception: return any errors or warnings in this structure.
892 %
893 */
895  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
896 {
897  DrawInfo
898  *annotate_info;
899 
901  status;
902 
903  PointInfo
904  offset;
905 
906  assert(image != (Image *) NULL);
907  assert(image->signature == MagickCoreSignature);
908  if (IsEventLogging() != MagickFalse)
909  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
910  assert(draw_info != (DrawInfo *) NULL);
911  assert(draw_info->text != (char *) NULL);
912  assert(draw_info->signature == MagickCoreSignature);
913  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
914  annotate_info->render=MagickFalse;
915  annotate_info->direction=UndefinedDirection;
916  (void) memset(metrics,0,sizeof(*metrics));
917  offset.x=0.0;
918  offset.y=0.0;
919  status=RenderType(image,annotate_info,&offset,metrics,exception);
920  if (draw_info->debug != MagickFalse)
921  (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
922  "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
923  "bounds: %g,%g %g,%g; origin: %g,%g; pixels per em: %g,%g; "
924  "underline position: %g; underline thickness: %g",annotate_info->text,
925  metrics->width,metrics->height,metrics->ascent,metrics->descent,
926  metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
927  metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
928  metrics->pixels_per_em.x,metrics->pixels_per_em.y,
929  metrics->underline_position,metrics->underline_thickness);
930  annotate_info=DestroyDrawInfo(annotate_info);
931  return(status);
932 }
933 
934 /*
935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
936 % %
937 % %
938 % %
939 + R e n d e r T y p e %
940 % %
941 % %
942 % %
943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
944 %
945 % RenderType() renders text on the image. It also returns the bounding box of
946 % the text relative to the image.
947 %
948 % The format of the RenderType method is:
949 %
950 % MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
951 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
952 %
953 % A description of each parameter follows:
954 %
955 % o image: the image.
956 %
957 % o draw_info: the draw info.
958 %
959 % o offset: (x,y) location of text relative to image.
960 %
961 % o metrics: bounding box of text.
962 %
963 % o exception: return any errors or warnings in this structure.
964 %
965 */
966 static MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
967  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
968 {
969  char
970  *font;
971 
972  const TypeInfo
973  *type_info;
974 
975  DrawInfo
976  *annotate_info;
977 
979  *sans_exception;
980 
982  status;
983 
984  type_info=(const TypeInfo *) NULL;
985  if (draw_info->font != (char *) NULL)
986  {
987  if (*draw_info->font == '@')
988  {
989  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
990  metrics,exception);
991  return(status);
992  }
993  if (*draw_info->font == '-')
994  return(RenderX11(image,draw_info,offset,metrics,exception));
995  if (*draw_info->font == '^')
996  return(RenderPostscript(image,draw_info,offset,metrics,exception));
997  if (IsPathAccessible(draw_info->font) != MagickFalse)
998  {
999  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
1000  metrics,exception);
1001  return(status);
1002  }
1003  type_info=GetTypeInfo(draw_info->font,exception);
1004  if (type_info == (const TypeInfo *) NULL)
1006  "UnableToReadFont","`%s'",draw_info->font);
1007  }
1008  if ((type_info == (const TypeInfo *) NULL) &&
1009  (draw_info->family != (const char *) NULL))
1010  {
1011  if (strstr(draw_info->family,",'\"") == (char *) NULL)
1012  type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
1013  draw_info->stretch,draw_info->weight,exception);
1014  if (type_info == (const TypeInfo *) NULL)
1015  {
1016  char
1017  **family;
1018 
1019  int
1020  number_families;
1021 
1022  ssize_t
1023  i;
1024 
1025  /*
1026  Parse font family list.
1027  */
1028  family=StringToArgv(draw_info->family,&number_families);
1029  for (i=1; i < (ssize_t) number_families; i++)
1030  {
1031  (void) SubstituteString(&family[i],",","");
1032  type_info=GetTypeInfoByFamily(family[i],draw_info->style,
1033  draw_info->stretch,draw_info->weight,exception);
1034  if ((type_info != (const TypeInfo *) NULL) &&
1035  (LocaleCompare(family[i],type_info->family) == 0))
1036  break;
1037  }
1038  for (i=0; i < (ssize_t) number_families; i++)
1039  family[i]=DestroyString(family[i]);
1040  family=(char **) RelinquishMagickMemory(family);
1041  if (type_info == (const TypeInfo *) NULL)
1043  "UnableToReadFont","`%s'",draw_info->family);
1044  }
1045  }
1046  font=GetPolicyValue("system:font");
1047  if (font != (char *) NULL)
1048  {
1049  if (IsPathAccessible(font) != MagickFalse)
1050  {
1051  /*
1052  Render with default system font.
1053  */
1054  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1055  annotate_info->font=font;
1056  status=RenderFreetype(image,annotate_info,annotate_info->encoding,
1057  offset,metrics,exception);
1058  annotate_info=DestroyDrawInfo(annotate_info);
1059  return(status);
1060  }
1061  font=DestroyString(font);
1062  }
1063  sans_exception=AcquireExceptionInfo();
1064  if (type_info == (const TypeInfo *) NULL)
1065  type_info=GetTypeInfoByFamily("Open Sans",draw_info->style,
1066  draw_info->stretch,draw_info->weight,sans_exception);
1067  if (type_info == (const TypeInfo *) NULL)
1068  type_info=GetTypeInfoByFamily("Sans Serif",draw_info->style,
1069  draw_info->stretch,draw_info->weight,sans_exception);
1070  if (type_info == (const TypeInfo *) NULL)
1071  type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
1072  draw_info->stretch,draw_info->weight,sans_exception);
1073  if (type_info == (const TypeInfo *) NULL)
1074  type_info=GetTypeInfo("*",sans_exception);
1075  sans_exception=DestroyExceptionInfo(sans_exception);
1076  if (type_info == (const TypeInfo *) NULL)
1077  {
1078  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics,
1079  exception);
1080  return(status);
1081  }
1082  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1083  annotate_info->face=type_info->face;
1084  if (type_info->metrics != (char *) NULL)
1085  (void) CloneString(&annotate_info->metrics,type_info->metrics);
1086  if (type_info->glyphs != (char *) NULL)
1087  (void) CloneString(&annotate_info->font,type_info->glyphs);
1088  status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics,
1089  exception);
1090  annotate_info=DestroyDrawInfo(annotate_info);
1091  return(status);
1092 }
1093 
1094 /*
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 % %
1097 % %
1098 % %
1099 + R e n d e r F r e e t y p e %
1100 % %
1101 % %
1102 % %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 %
1105 % RenderFreetype() renders text on the image with a Truetype font. It also
1106 % returns the bounding box of the text relative to the image.
1107 %
1108 % The format of the RenderFreetype method is:
1109 %
1110 % MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
1111 % const char *encoding,const PointInfo *offset,TypeMetric *metrics,
1112 % ExceptionInfo *exception)
1113 %
1114 % A description of each parameter follows:
1115 %
1116 % o image: the image.
1117 %
1118 % o draw_info: the draw info.
1119 %
1120 % o encoding: the font encoding.
1121 %
1122 % o offset: (x,y) location of text relative to image.
1123 %
1124 % o metrics: bounding box of text.
1125 %
1126 % o exception: return any errors or warnings in this structure.
1127 %
1128 */
1129 
1130 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
1131 
1132 static size_t ComplexTextLayout(const Image *image,const DrawInfo *draw_info,
1133  const char *text,const size_t length,const FT_Face face,const FT_Int32 flags,
1134  GraphemeInfo **grapheme,ExceptionInfo *exception)
1135 {
1136 #if defined(MAGICKCORE_RAQM_DELEGATE)
1137  const char
1138  *features;
1139 
1140  raqm_t
1141  *rq;
1142 
1143  raqm_glyph_t
1144  *glyphs;
1145 
1146  ssize_t
1147  i;
1148 
1149  size_t
1150  extent;
1151 
1152  magick_unreferenced(flags);
1153  extent=0;
1154  rq=raqm_create();
1155  if (rq == (raqm_t *) NULL)
1156  goto cleanup;
1157  if (raqm_set_text_utf8(rq,text,length) == 0)
1158  goto cleanup;
1159  if (raqm_set_par_direction(rq,(raqm_direction_t) draw_info->direction) == 0)
1160  goto cleanup;
1161  if (raqm_set_freetype_face(rq,face) == 0)
1162  goto cleanup;
1163  features=GetImageProperty(image,"type:features",exception);
1164  if (features != (const char *) NULL)
1165  {
1166  char
1167  breaker,
1168  quote,
1169  *token;
1170 
1171  int
1172  next,
1173  status_token;
1174 
1175  TokenInfo
1176  *token_info;
1177 
1178  next=0;
1179  token_info=AcquireTokenInfo();
1180  token=AcquireString("");
1181  status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
1182  &breaker,&next,&quote);
1183  while (status_token == 0)
1184  {
1185  raqm_add_font_feature(rq,token,(int) strlen(token));
1186  status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
1187  &breaker,&next,&quote);
1188  }
1189  token_info=DestroyTokenInfo(token_info);
1190  token=DestroyString(token);
1191  }
1192  if (raqm_layout(rq) == 0)
1193  goto cleanup;
1194  glyphs=raqm_get_glyphs(rq,&extent);
1195  if (glyphs == (raqm_glyph_t *) NULL)
1196  {
1197  extent=0;
1198  goto cleanup;
1199  }
1200  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(extent,sizeof(**grapheme));
1201  if (*grapheme == (GraphemeInfo *) NULL)
1202  {
1203  extent=0;
1204  goto cleanup;
1205  }
1206  for (i=0; i < (ssize_t) extent; i++)
1207  {
1208  (*grapheme)[i].index=glyphs[i].index;
1209  (*grapheme)[i].x_offset=glyphs[i].x_offset;
1210  (*grapheme)[i].x_advance=glyphs[i].x_advance;
1211  (*grapheme)[i].y_offset=glyphs[i].y_offset;
1212  (*grapheme)[i].cluster=glyphs[i].cluster;
1213  }
1214 
1215 cleanup:
1216  raqm_destroy(rq);
1217  return(extent);
1218 #else
1219  const char
1220  *p;
1221 
1222  ssize_t
1223  i;
1224 
1225  ssize_t
1226  last_glyph;
1227 
1228  /*
1229  Simple layout for bi-directional text (right-to-left or left-to-right).
1230  */
1231  magick_unreferenced(image);
1232  magick_unreferenced(exception);
1233  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(length+1,sizeof(**grapheme));
1234  if (*grapheme == (GraphemeInfo *) NULL)
1235  return(0);
1236  last_glyph=0;
1237  p=text;
1238  for (i=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p), i++)
1239  {
1240  (*grapheme)[i].index=(ssize_t) FT_Get_Char_Index(face,GetUTFCode(p));
1241  (*grapheme)[i].x_offset=0;
1242  (*grapheme)[i].y_offset=0;
1243  if (((*grapheme)[i].index != 0) && (last_glyph != 0))
1244  {
1245  if (FT_HAS_KERNING(face))
1246  {
1247  FT_Error
1248  ft_status;
1249 
1250  FT_Vector
1251  kerning;
1252 
1253  ft_status=FT_Get_Kerning(face,(FT_UInt) last_glyph,(FT_UInt)
1254  (*grapheme)[i].index,ft_kerning_default,&kerning);
1255  if (ft_status == 0)
1256  (*grapheme)[i-1].x_advance+=(FT_Pos) ((draw_info->direction ==
1257  RightToLeftDirection ? -1.0 : 1.0)*kerning.x);
1258  }
1259  }
1260  (void) FT_Load_Glyph(face,(FT_UInt) (*grapheme)[i].index,flags);
1261  (*grapheme)[i].x_advance=face->glyph->advance.x;
1262  (*grapheme)[i].cluster=p-text;
1263  last_glyph=(*grapheme)[i].index;
1264  }
1265  return((size_t) i);
1266 #endif
1267 }
1268 
1269 static void FTCloseStream(FT_Stream stream)
1270 {
1271  FILE *file = (FILE *) stream->descriptor.pointer;
1272  if (file != (FILE *) NULL)
1273  (void) fclose(file);
1274  stream->descriptor.pointer=NULL;
1275 }
1276 
1277 static unsigned long FTReadStream(FT_Stream stream,unsigned long offset,
1278  unsigned char *buffer,unsigned long count)
1279 {
1280  FILE *file = (FILE *) stream->descriptor.pointer;
1281  if (file == (FILE *) NULL)
1282  return(0);
1283  if (count == 0)
1284  return(0);
1285  if (fseek(file,(off_t) offset,SEEK_SET) != 0)
1286  return(0);
1287  return((unsigned long) fread(buffer,1,count,file));
1288 }
1289 
1290 static inline MagickBooleanType IsEmptyOutline(FT_Outline outline)
1291 {
1292  return((outline.n_points == 0) || (outline.n_contours <= 0) ? MagickTrue :
1293  MagickFalse);
1294 }
1295 
1296 static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
1297  DrawInfo *draw_info)
1298 {
1299  AffineMatrix
1300  affine;
1301 
1302  char
1303  path[MagickPathExtent];
1304 
1305  affine=draw_info->affine;
1306  (void) FormatLocaleString(path,MagickPathExtent,"C%g,%g %g,%g %g,%g",
1307  affine.tx+p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,affine.ty-
1308  q->y/64.0,affine.tx+to->x/64.0,affine.ty-to->y/64.0);
1309  (void) ConcatenateString(&draw_info->primitive,path);
1310  return(0);
1311 }
1312 
1313 static int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
1314 {
1315  AffineMatrix
1316  affine;
1317 
1318  char
1319  path[MagickPathExtent];
1320 
1321  affine=draw_info->affine;
1322  (void) FormatLocaleString(path,MagickPathExtent,"L%g,%g",affine.tx+to->x/64.0,
1323  affine.ty-to->y/64.0);
1324  (void) ConcatenateString(&draw_info->primitive,path);
1325  return(0);
1326 }
1327 
1328 static int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
1329 {
1330  AffineMatrix
1331  affine;
1332 
1333  char
1334  path[MagickPathExtent];
1335 
1336  affine=draw_info->affine;
1337  (void) FormatLocaleString(path,MagickPathExtent,"M%g,%g",affine.tx+to->x/64.0,
1338  affine.ty-to->y/64.0);
1339  (void) ConcatenateString(&draw_info->primitive,path);
1340  return(0);
1341 }
1342 
1343 static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
1344  DrawInfo *draw_info)
1345 {
1346  AffineMatrix
1347  affine;
1348 
1349  char
1350  path[MagickPathExtent];
1351 
1352  affine=draw_info->affine;
1353  (void) FormatLocaleString(path,MagickPathExtent,"Q%g,%g %g,%g",affine.tx+
1354  control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,affine.ty-
1355  to->y/64.0);
1356  (void) ConcatenateString(&draw_info->primitive,path);
1357  return(0);
1358 }
1359 
1360 static inline const char *FreetypeErrorMessage(FT_Error ft_status)
1361 {
1362 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 10
1363  return(FT_Error_String(ft_status));
1364 #else
1365  magick_unreferenced(ft_status);
1366  return((const char *) NULL);
1367 #endif
1368 }
1369 
1370 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
1371  const char *encoding,const PointInfo *offset,TypeMetric *metrics,
1372  ExceptionInfo *exception)
1373 {
1374 #if !defined(FT_OPEN_PATHNAME)
1375 #define FT_OPEN_PATHNAME ft_open_pathname
1376 #endif
1377 
1378 #define ThrowFreetypeErrorException(tag,ft_status,value) \
1379 { \
1380  const char \
1381  *error_string=FreetypeErrorMessage(ft_status); \
1382  if (error_string != (const char *) NULL) \
1383  (void) ThrowMagickException(exception,GetMagickModule(),TypeError, \
1384  tag,"`%s (%s)'",value, error_string); \
1385  else \
1386  (void) ThrowMagickException(exception,GetMagickModule(),TypeError, \
1387  tag,"`%s'",value); \
1388 }
1389 
1390  typedef struct _GlyphInfo
1391  {
1392  FT_UInt
1393  id;
1394 
1395  FT_Vector
1396  origin;
1397 
1398  FT_Glyph
1399  image;
1400  } GlyphInfo;
1401 
1402  char
1403  *p;
1404 
1405  const char
1406  *value;
1407 
1408  DrawInfo
1409  *annotate_info;
1410 
1411  FT_BBox
1412  bounds;
1413 
1414  FT_BitmapGlyph
1415  bitmap;
1416 
1417  FT_Encoding
1418  encoding_type;
1419 
1420  FT_Error
1421  ft_status;
1422 
1423  FT_Face
1424  face;
1425 
1426  FT_Int32
1427  flags;
1428 
1429  FT_Library
1430  library;
1431 
1432  FT_Long
1433  face_index;
1434 
1435  FT_Matrix
1436  affine;
1437 
1438  FT_Open_Args
1439  args;
1440 
1441  FT_StreamRec
1442  *stream;
1443 
1444  FT_UInt
1445  first_glyph_id,
1446  last_glyph_id,
1447  missing_glyph_id;
1448 
1449  FT_Vector
1450  origin;
1451 
1452  GlyphInfo
1453  glyph;
1454 
1455  GraphemeInfo
1456  *grapheme;
1457 
1459  status;
1460 
1461  PointInfo
1462  point,
1463  resolution;
1464 
1465  ssize_t
1466  i;
1467 
1468  size_t
1469  length;
1470 
1471  ssize_t
1472  code,
1473  last_character,
1474  y;
1475 
1476  static FT_Outline_Funcs
1477  OutlineMethods =
1478  {
1479  (FT_Outline_MoveTo_Func) TraceMoveTo,
1480  (FT_Outline_LineTo_Func) TraceLineTo,
1481  (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
1482  (FT_Outline_CubicTo_Func) TraceCubicBezier,
1483  0, 0
1484  };
1485 
1486  struct stat
1487  attributes;
1488 
1489  unsigned char
1490  *utf8;
1491 
1492  /*
1493  Initialize Truetype library.
1494  */
1495  ft_status=FT_Init_FreeType(&library);
1496  if (ft_status != 0)
1497  ThrowFreetypeErrorException("UnableToInitializeFreetypeLibrary",ft_status,
1498  image->filename);
1499  /*
1500  Open font face.
1501  */
1502  face_index=(FT_Long) draw_info->face;
1503  (void) memset(&args,0,sizeof(args));
1504  if (draw_info->font == (char *) NULL)
1505  args.pathname=ConstantString("helvetica");
1506  else
1507  if (*draw_info->font != '@')
1508  args.pathname=ConstantString(draw_info->font);
1509  else
1510  {
1511  /*
1512  Extract face index, e.g. @msgothic[1].
1513  */
1514  ImageInfo *image_info = AcquireImageInfo();
1515  (void) strcpy(image_info->filename,draw_info->font+1);
1516  (void) SetImageInfo(image_info,0,exception);
1517  face_index=(FT_Long) image_info->scene;
1518  args.pathname=ConstantString(image_info->filename);
1519  image_info=DestroyImageInfo(image_info);
1520  }
1521  /*
1522  Configure streaming interface.
1523  */
1524  stream=(FT_StreamRec *) AcquireCriticalMemory(sizeof(*stream));
1525  (void) memset(stream,0,sizeof(*stream));
1526  (void) stat(args.pathname,&attributes);
1527  stream->size=attributes.st_size;
1528  stream->descriptor.pointer=fopen_utf8(args.pathname,"rb");
1529  stream->read=(&FTReadStream);
1530  stream->close=(&FTCloseStream);
1531  args.flags=FT_OPEN_STREAM;
1532  args.stream=stream;
1533  face=(FT_Face) NULL;
1534  ft_status=FT_Open_Face(library,&args,face_index,&face);
1535  if (ft_status != 0)
1536  {
1537  (void) FT_Done_FreeType(library);
1538  ThrowFreetypeErrorException("UnableToReadFont",ft_status,args.pathname);
1539  args.pathname=DestroyString(args.pathname);
1540  return(MagickFalse);
1541  }
1542  args.pathname=DestroyString(args.pathname);
1543  if ((draw_info->metrics != (char *) NULL) &&
1544  (IsPathAccessible(draw_info->metrics) != MagickFalse))
1545  (void) FT_Attach_File(face,draw_info->metrics);
1546  encoding_type=FT_ENCODING_UNICODE;
1547  ft_status=FT_Select_Charmap(face,encoding_type);
1548  if ((ft_status != 0) && (face->num_charmaps != 0))
1549  ft_status=FT_Set_Charmap(face,face->charmaps[0]);
1550  if (encoding != (const char *) NULL)
1551  {
1552  if (LocaleCompare(encoding,"AdobeCustom") == 0)
1553  encoding_type=FT_ENCODING_ADOBE_CUSTOM;
1554  if (LocaleCompare(encoding,"AdobeExpert") == 0)
1555  encoding_type=FT_ENCODING_ADOBE_EXPERT;
1556  if (LocaleCompare(encoding,"AdobeStandard") == 0)
1557  encoding_type=FT_ENCODING_ADOBE_STANDARD;
1558  if (LocaleCompare(encoding,"AppleRoman") == 0)
1559  encoding_type=FT_ENCODING_APPLE_ROMAN;
1560  if (LocaleCompare(encoding,"BIG5") == 0)
1561  encoding_type=FT_ENCODING_BIG5;
1562 #if defined(FT_ENCODING_PRC)
1563  if (LocaleCompare(encoding,"GB2312") == 0)
1564  encoding_type=FT_ENCODING_PRC;
1565 #endif
1566 #if defined(FT_ENCODING_JOHAB)
1567  if (LocaleCompare(encoding,"Johab") == 0)
1568  encoding_type=FT_ENCODING_JOHAB;
1569 #endif
1570 #if defined(FT_ENCODING_ADOBE_LATIN_1)
1571  if (LocaleCompare(encoding,"Latin-1") == 0)
1572  encoding_type=FT_ENCODING_ADOBE_LATIN_1;
1573 #endif
1574 #if defined(FT_ENCODING_ADOBE_LATIN_2)
1575  if (LocaleCompare(encoding,"Latin-2") == 0)
1576  encoding_type=FT_ENCODING_OLD_LATIN_2;
1577 #endif
1578  if (LocaleCompare(encoding,"None") == 0)
1579  encoding_type=FT_ENCODING_NONE;
1580  if (LocaleCompare(encoding,"SJIScode") == 0)
1581  encoding_type=FT_ENCODING_SJIS;
1582  if (LocaleCompare(encoding,"Symbol") == 0)
1583  encoding_type=FT_ENCODING_MS_SYMBOL;
1584  if (LocaleCompare(encoding,"Unicode") == 0)
1585  encoding_type=FT_ENCODING_UNICODE;
1586  if (LocaleCompare(encoding,"Wansung") == 0)
1587  encoding_type=FT_ENCODING_WANSUNG;
1588  ft_status=FT_Select_Charmap(face,encoding_type);
1589  if (ft_status != 0)
1590  {
1591  (void) FT_Done_Face(face);
1592  (void) FT_Done_FreeType(library);
1593  ThrowFreetypeErrorException("UnrecognizedFontEncoding",ft_status,
1594  encoding);
1595  return(MagickFalse);
1596  }
1597  }
1598  /*
1599  Set text size.
1600  */
1601  resolution.x=DefaultResolution;
1602  resolution.y=DefaultResolution;
1603  if (draw_info->density != (char *) NULL)
1604  {
1605  GeometryInfo
1606  geometry_info;
1607 
1609  geometry_flags;
1610 
1611  geometry_flags=ParseGeometry(draw_info->density,&geometry_info);
1612  if ((geometry_flags & RhoValue) != 0)
1613  resolution.x=geometry_info.rho;
1614  resolution.y=resolution.x;
1615  if ((geometry_flags & SigmaValue) != 0)
1616  resolution.y=geometry_info.sigma;
1617  }
1618  ft_status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
1619  (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
1620  (FT_UInt) resolution.y);
1621  if (ft_status != 0)
1622  {
1623  (void) FT_Done_Face(face);
1624  (void) FT_Done_FreeType(library);
1625  ThrowFreetypeErrorException("UnableToReadFont",ft_status,
1626  draw_info->font);
1627  return(MagickFalse);
1628  }
1629  metrics->pixels_per_em.x=face->size->metrics.x_ppem;
1630  metrics->pixels_per_em.y=face->size->metrics.y_ppem;
1631  metrics->ascent=(double) face->size->metrics.ascender/64.0;
1632  metrics->descent=(double) face->size->metrics.descender/64.0;
1633  if (face->size->metrics.ascender == 0)
1634  {
1635  /*
1636  Sanitize buggy ascender and descender values.
1637  */
1638  metrics->ascent=face->size->metrics.y_ppem;
1639  if (face->size->metrics.descender == 0)
1640  metrics->descent=face->size->metrics.y_ppem/-3.5;
1641  }
1642  metrics->width=0;
1643  metrics->origin.x=0;
1644  metrics->origin.y=0;
1645  metrics->height=(double) face->size->metrics.height/64.0;
1646  metrics->max_advance=0.0;
1647  if (face->size->metrics.max_advance > MagickEpsilon)
1648  metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
1649  metrics->bounds.x1=0.0;
1650  metrics->bounds.y1=metrics->descent;
1651  metrics->bounds.x2=metrics->ascent+metrics->descent;
1652  metrics->bounds.y2=metrics->ascent+metrics->descent;
1653  metrics->underline_position=face->underline_position*
1654  (metrics->pixels_per_em.x*PerceptibleReciprocal(face->units_per_EM));
1655  metrics->underline_thickness=face->underline_thickness*
1656  (metrics->pixels_per_em.x*PerceptibleReciprocal(face->units_per_EM));
1657  first_glyph_id=0;
1658  FT_Get_First_Char(face,&first_glyph_id);
1659  if ((draw_info->text == (char *) NULL) || (*draw_info->text == '\0') ||
1660  (first_glyph_id == 0))
1661  {
1662  (void) FT_Done_Face(face);
1663  (void) FT_Done_FreeType(library);
1664  return(MagickTrue);
1665  }
1666  /*
1667  Compute bounding box.
1668  */
1669  if (draw_info->debug != MagickFalse)
1670  (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
1671  "font-encoding %s; text-encoding %s; pointsize %g",
1672  draw_info->font != (char *) NULL ? draw_info->font : "none",
1673  encoding != (char *) NULL ? encoding : "none",
1674  draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
1675  draw_info->pointsize);
1676  flags=FT_LOAD_DEFAULT;
1677  if (draw_info->render == MagickFalse)
1678  flags=FT_LOAD_NO_BITMAP;
1679  if (draw_info->text_antialias == MagickFalse)
1680  flags|=FT_LOAD_TARGET_MONO;
1681  else
1682  {
1683 #if defined(FT_LOAD_TARGET_LIGHT)
1684  flags|=FT_LOAD_TARGET_LIGHT;
1685 #elif defined(FT_LOAD_TARGET_LCD)
1686  flags|=FT_LOAD_TARGET_LCD;
1687 #endif
1688  }
1689  value=GetImageProperty(image,"type:hinting",exception);
1690  if ((value != (const char *) NULL) && (LocaleCompare(value,"off") == 0))
1691  flags|=FT_LOAD_NO_HINTING;
1692  glyph.id=0;
1693  glyph.image=(FT_Glyph) NULL;
1694  last_glyph_id=0;
1695  origin.x=0;
1696  origin.y=0;
1697  affine.xx=65536L;
1698  affine.yx=0L;
1699  affine.xy=0L;
1700  affine.yy=65536L;
1701  if (draw_info->render != MagickFalse)
1702  {
1703  affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
1704  affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
1705  affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
1706  affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
1707  }
1708  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1709  if (annotate_info->dash_pattern != (double *) NULL)
1710  annotate_info->dash_pattern[0]=0.0;
1711  (void) CloneString(&annotate_info->primitive,"path '");
1712  status=MagickTrue;
1713  if (draw_info->render != MagickFalse)
1714  {
1715  if (image->storage_class != DirectClass)
1716  (void) SetImageStorageClass(image,DirectClass,exception);
1717  if (image->alpha_trait == UndefinedPixelTrait)
1718  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1719  }
1720  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
1721  if (GetUTFCode(p) < 0)
1722  break;
1723  utf8=(unsigned char *) NULL;
1724  if (GetUTFCode(p) == 0)
1725  p=draw_info->text;
1726  else
1727  {
1728  utf8=ConvertLatin1ToUTF8((unsigned char *) draw_info->text);
1729  if (utf8 != (unsigned char *) NULL)
1730  p=(char *) utf8;
1731  }
1732  grapheme=(GraphemeInfo *) NULL;
1733  length=ComplexTextLayout(image,draw_info,p,strlen(p),face,flags,&grapheme,
1734  exception);
1735  missing_glyph_id=FT_Get_Char_Index(face,' ');
1736  code=0;
1737  last_character=(ssize_t) length-1;
1738  for (i=0; i < (ssize_t) length; i++)
1739  {
1740  FT_Outline
1741  outline;
1742 
1743  /*
1744  Render UTF-8 sequence.
1745  */
1746  glyph.id=(FT_UInt) grapheme[i].index;
1747  if (glyph.id == 0)
1748  glyph.id=missing_glyph_id;
1749  if ((glyph.id != 0) && (last_glyph_id != 0))
1750  origin.x+=(FT_Pos) (64.0*draw_info->kerning);
1751  glyph.origin=origin;
1752  glyph.origin.x+=(FT_Pos) grapheme[i].x_offset;
1753  glyph.origin.y+=(FT_Pos) grapheme[i].y_offset;
1754  if (glyph.image != (FT_Glyph) NULL)
1755  {
1756  FT_Done_Glyph(glyph.image);
1757  glyph.image=(FT_Glyph) NULL;
1758  }
1759  ft_status=FT_Load_Glyph(face,glyph.id,flags);
1760  if (ft_status != 0)
1761  continue;
1762  ft_status=FT_Get_Glyph(face->glyph,&glyph.image);
1763  if (ft_status != 0)
1764  continue;
1765  outline=((FT_OutlineGlyph) glyph.image)->outline;
1766  if ((glyph.image->format != FT_GLYPH_FORMAT_OUTLINE) &&
1767  (IsEmptyOutline(outline) == MagickFalse))
1768  continue;
1769  ft_status=FT_Outline_Get_BBox(&outline,&bounds);
1770  if (ft_status != 0)
1771  continue;
1772  if ((bounds.xMin < metrics->bounds.x1) && (bounds.xMin != 0))
1773  metrics->bounds.x1=(double) bounds.xMin;
1774  if ((bounds.yMin < metrics->bounds.y1) && (bounds.yMin != 0))
1775  metrics->bounds.y1=(double) bounds.yMin;
1776  if ((bounds.xMax > metrics->bounds.x2) && (bounds.xMax != 0))
1777  metrics->bounds.x2=(double) bounds.xMax;
1778  if ((bounds.yMax > metrics->bounds.y2) && (bounds.yMax != 0))
1779  metrics->bounds.y2=(double) bounds.yMax;
1780  if (((draw_info->stroke.alpha != TransparentAlpha) ||
1781  (draw_info->stroke_pattern != (Image *) NULL)) &&
1782  ((status != MagickFalse) && (draw_info->render != MagickFalse)))
1783  {
1784  /*
1785  Trace the glyph.
1786  */
1787  annotate_info->affine.tx=glyph.origin.x/64.0;
1788  annotate_info->affine.ty=(-glyph.origin.y/64.0);
1789  if (IsEmptyOutline(outline) == MagickFalse)
1790  ft_status=FT_Outline_Decompose(&outline,&OutlineMethods,
1791  annotate_info);
1792  }
1793  FT_Vector_Transform(&glyph.origin,&affine);
1794  (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1795  ft_status=FT_Glyph_To_Bitmap(&glyph.image,FT_RENDER_MODE_NORMAL,
1796  (FT_Vector *) NULL,MagickTrue);
1797  if (ft_status != 0)
1798  continue;
1799  bitmap=(FT_BitmapGlyph) glyph.image;
1800  point.x=offset->x+bitmap->left;
1801  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
1802  point.x+=(origin.x/64.0);
1803  point.y=offset->y-bitmap->top;
1804  if (draw_info->render != MagickFalse)
1805  {
1806  CacheView
1807  *image_view;
1808 
1810  transparent_fill;
1811 
1812  unsigned char
1813  *r;
1814 
1815  /*
1816  Rasterize the glyph.
1817  */
1818  transparent_fill=((draw_info->fill.alpha == TransparentAlpha) &&
1819  (draw_info->fill_pattern == (Image *) NULL) &&
1820  (draw_info->stroke.alpha == TransparentAlpha) &&
1821  (draw_info->stroke_pattern == (Image *) NULL)) ? MagickTrue :
1822  MagickFalse;
1823  image_view=AcquireAuthenticCacheView(image,exception);
1824  r=bitmap->bitmap.buffer;
1825  for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++)
1826  {
1827  double
1828  fill_opacity;
1829 
1831  active,
1832  sync;
1833 
1834  PixelInfo
1835  fill_color;
1836 
1837  Quantum
1838  *magick_restrict q;
1839 
1840  ssize_t
1841  x;
1842 
1843  ssize_t
1844  n,
1845  x_offset,
1846  y_offset;
1847 
1848  if (status == MagickFalse)
1849  continue;
1850  x_offset=CastDoubleToLong(ceil(point.x-0.5));
1851  y_offset=CastDoubleToLong(ceil(point.y+y-0.5));
1852  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
1853  continue;
1854  q=(Quantum *) NULL;
1855  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
1856  active=MagickFalse;
1857  else
1858  {
1859  q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
1860  bitmap->bitmap.width,1,exception);
1861  active=q != (Quantum *) NULL ? MagickTrue : MagickFalse;
1862  }
1863  n=y*bitmap->bitmap.pitch;
1864  for (x=0; x < (ssize_t) bitmap->bitmap.width; x++, n++)
1865  {
1866  x_offset=CastDoubleToLong(ceil(point.x+x-0.5));
1867  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
1868  {
1869  if (q != (Quantum *) NULL)
1870  q+=GetPixelChannels(image);
1871  continue;
1872  }
1873  fill_opacity=1.0;
1874  if (bitmap->bitmap.buffer != (unsigned char *) NULL)
1875  {
1876  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_grays)
1877  fill_opacity=(double) (r[n])/(bitmap->bitmap.num_grays-1);
1878  else
1879  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
1880  fill_opacity=((r[(x >> 3)+y*bitmap->bitmap.pitch] &
1881  (1 << (~x & 0x07)))) == 0 ? 0.0 : 1.0;
1882  }
1883  if (draw_info->text_antialias == MagickFalse)
1884  fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
1885  if (active == MagickFalse)
1886  q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
1887  exception);
1888  if (q == (Quantum *) NULL)
1889  continue;
1890  if (transparent_fill == MagickFalse)
1891  {
1892  GetPixelInfo(image,&fill_color);
1893  GetFillColor(draw_info,x_offset,y_offset,&fill_color,exception);
1894  fill_opacity=fill_opacity*fill_color.alpha;
1895  CompositePixelOver(image,&fill_color,fill_opacity,q,
1896  GetPixelAlpha(image,q),q);
1897  }
1898  else
1899  {
1900  double
1901  Sa,
1902  Da;
1903 
1904  Da=1.0-(QuantumScale*GetPixelAlpha(image,q));
1905  Sa=fill_opacity;
1906  fill_opacity=(1.0-RoundToUnity(Sa+Da-Sa*Da))*QuantumRange;
1907  SetPixelAlpha(image,fill_opacity,q);
1908  }
1909  if (active == MagickFalse)
1910  {
1911  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1912  if (sync == MagickFalse)
1913  status=MagickFalse;
1914  }
1915  q+=GetPixelChannels(image);
1916  }
1917  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1918  if (sync == MagickFalse)
1919  status=MagickFalse;
1920  }
1921  image_view=DestroyCacheView(image_view);
1922  if (((draw_info->stroke.alpha != TransparentAlpha) ||
1923  (draw_info->stroke_pattern != (Image *) NULL)) &&
1924  (status != MagickFalse))
1925  {
1926  /*
1927  Draw text stroke.
1928  */
1929  annotate_info->linejoin=RoundJoin;
1930  annotate_info->affine.tx=offset->x;
1931  annotate_info->affine.ty=offset->y;
1932  (void) ConcatenateString(&annotate_info->primitive,"'");
1933  if (strlen(annotate_info->primitive) > 7)
1934  (void) DrawImage(image,annotate_info,exception);
1935  (void) CloneString(&annotate_info->primitive,"path '");
1936  }
1937  }
1938  if ((fabs(draw_info->interword_spacing) >= MagickEpsilon) &&
1939  (IsUTFSpace(GetUTFCode(p+grapheme[i].cluster)) != MagickFalse) &&
1940  (IsUTFSpace(code) == MagickFalse))
1941  origin.x+=(FT_Pos) (64.0*draw_info->interword_spacing);
1942  else
1943  if (i == last_character)
1944  origin.x+=MagickMax((FT_Pos) grapheme[i].x_advance,bounds.xMax);
1945  else
1946  origin.x+=(FT_Pos) grapheme[i].x_advance;
1947  metrics->origin.x=(double) origin.x;
1948  metrics->origin.y=(double) origin.y;
1949  if (metrics->origin.x > metrics->width)
1950  metrics->width=metrics->origin.x;
1951  last_glyph_id=glyph.id;
1952  code=GetUTFCode(p+grapheme[i].cluster);
1953  }
1954  if (grapheme != (GraphemeInfo *) NULL)
1955  grapheme=(GraphemeInfo *) RelinquishMagickMemory(grapheme);
1956  if (utf8 != (unsigned char *) NULL)
1957  utf8=(unsigned char *) RelinquishMagickMemory(utf8);
1958  if (glyph.image != (FT_Glyph) NULL)
1959  {
1960  FT_Done_Glyph(glyph.image);
1961  glyph.image=(FT_Glyph) NULL;
1962  }
1963  /*
1964  Determine font metrics.
1965  */
1966  metrics->bounds.x1/=64.0;
1967  metrics->bounds.y1/=64.0;
1968  metrics->bounds.x2/=64.0;
1969  metrics->bounds.y2/=64.0;
1970  metrics->origin.x/=64.0;
1971  metrics->origin.y/=64.0;
1972  metrics->width=ceil(metrics->width/64.0);
1973  /*
1974  Relinquish resources.
1975  */
1976  annotate_info=DestroyDrawInfo(annotate_info);
1977  (void) FT_Done_Face(face);
1978  (void) FT_Done_FreeType(library);
1979  return(status);
1980 }
1981 #else
1982 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
1983  const char *magick_unused(encoding),const PointInfo *offset,
1984  TypeMetric *metrics,ExceptionInfo *exception)
1985 {
1986  (void) ThrowMagickException(exception,GetMagickModule(),
1987  MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (Freetype)",
1988  draw_info->font != (char *) NULL ? draw_info->font : "none");
1989  return(RenderPostscript(image,draw_info,offset,metrics,exception));
1990 }
1991 #endif
1992 
1993 /*
1994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 % %
1996 % %
1997 % %
1998 + R e n d e r P o s t s c r i p t %
1999 % %
2000 % %
2001 % %
2002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2003 %
2004 % RenderPostscript() renders text on the image with a Postscript font. It
2005 % also returns the bounding box of the text relative to the image.
2006 %
2007 % The format of the RenderPostscript method is:
2008 %
2009 % MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
2010 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
2011 %
2012 % A description of each parameter follows:
2013 %
2014 % o image: the image.
2015 %
2016 % o draw_info: the draw info.
2017 %
2018 % o offset: (x,y) location of text relative to image.
2019 %
2020 % o metrics: bounding box of text.
2021 %
2022 % o exception: return any errors or warnings in this structure.
2023 %
2024 */
2025 
2026 static char *EscapeParenthesis(const char *source)
2027 {
2028  char
2029  *destination;
2030 
2031  char
2032  *q;
2033 
2034  const char
2035  *p;
2036 
2037  size_t
2038  length;
2039 
2040  assert(source != (const char *) NULL);
2041  length=0;
2042  for (p=source; *p != '\0'; p++)
2043  {
2044  if ((*p == '\\') || (*p == '(') || (*p == ')'))
2045  {
2046  if (~length < 1)
2047  ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
2048  length++;
2049  }
2050  length++;
2051  }
2052  destination=(char *) NULL;
2053  if (~length >= (MagickPathExtent-1))
2054  destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
2055  sizeof(*destination));
2056  if (destination == (char *) NULL)
2057  ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
2058  *destination='\0';
2059  q=destination;
2060  for (p=source; *p != '\0'; p++)
2061  {
2062  if ((*p == '\\') || (*p == '(') || (*p == ')'))
2063  *q++='\\';
2064  *q++=(*p);
2065  }
2066  *q='\0';
2067  return(destination);
2068 }
2069 
2071  const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics,
2072  ExceptionInfo *exception)
2073 {
2074  char
2075  filename[MagickPathExtent],
2076  geometry[MagickPathExtent],
2077  *text;
2078 
2079  FILE
2080  *file;
2081 
2082  Image
2083  *annotate_image;
2084 
2085  ImageInfo
2086  *annotate_info;
2087 
2088  int
2089  unique_file;
2090 
2092  identity;
2093 
2094  PointInfo
2095  extent,
2096  point,
2097  resolution;
2098 
2099  ssize_t
2100  i;
2101 
2102  size_t
2103  length;
2104 
2105  ssize_t
2106  y;
2107 
2108  /*
2109  Render label with a Postscript font.
2110  */
2111  if (draw_info->debug != MagickFalse)
2113  "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
2114  draw_info->font : "none",draw_info->pointsize);
2115  file=(FILE *) NULL;
2116  unique_file=AcquireUniqueFileResource(filename);
2117  if (unique_file != -1)
2118  file=fdopen(unique_file,"wb");
2119  if ((unique_file == -1) || (file == (FILE *) NULL))
2120  {
2121  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",filename);
2122  return(MagickFalse);
2123  }
2124  (void) FormatLocaleFile(file,"%%!PS-Adobe-3.0\n");
2125  (void) FormatLocaleFile(file,"/ReencodeType\n");
2126  (void) FormatLocaleFile(file,"{\n");
2127  (void) FormatLocaleFile(file," findfont dup length\n");
2128  (void) FormatLocaleFile(file,
2129  " dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
2130  (void) FormatLocaleFile(file,
2131  " /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
2132  (void) FormatLocaleFile(file,"} bind def\n");
2133  /*
2134  Sample to compute bounding box.
2135  */
2136  identity=(fabs(draw_info->affine.sx-draw_info->affine.sy) < MagickEpsilon) &&
2137  (fabs(draw_info->affine.rx) < MagickEpsilon) &&
2138  (fabs(draw_info->affine.ry) < MagickEpsilon) ? MagickTrue : MagickFalse;
2139  extent.x=0.0;
2140  extent.y=0.0;
2141  length=strlen(draw_info->text);
2142  for (i=0; i <= (ssize_t) (length+2); i++)
2143  {
2144  point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
2145  draw_info->affine.ry*2.0*draw_info->pointsize);
2146  point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
2147  draw_info->affine.sy*2.0*draw_info->pointsize);
2148  if (point.x > extent.x)
2149  extent.x=point.x;
2150  if (point.y > extent.y)
2151  extent.y=point.y;
2152  }
2153  (void) FormatLocaleFile(file,"%g %g moveto\n",identity != MagickFalse ? 0.0 :
2154  extent.x/2.0,extent.y/2.0);
2155  (void) FormatLocaleFile(file,"%g %g scale\n",draw_info->pointsize,
2156  draw_info->pointsize);
2157  if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
2158  (strchr(draw_info->font,'/') != (char *) NULL))
2159  (void) FormatLocaleFile(file,
2160  "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
2161  else
2162  (void) FormatLocaleFile(file,
2163  "/%s-ISO dup /%s ReencodeType findfont setfont\n",draw_info->font,
2164  draw_info->font);
2165  (void) FormatLocaleFile(file,"[%g %g %g %g 0 0] concat\n",
2166  draw_info->affine.sx,-draw_info->affine.rx,-draw_info->affine.ry,
2167  draw_info->affine.sy);
2168  text=EscapeParenthesis(draw_info->text);
2169  if (identity == MagickFalse)
2170  (void) FormatLocaleFile(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",
2171  text);
2172  (void) FormatLocaleFile(file,"(%s) show\n",text);
2173  text=DestroyString(text);
2174  (void) FormatLocaleFile(file,"showpage\n");
2175  (void) fclose(file);
2176  (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0!",
2177  floor(extent.x+0.5),floor(extent.y+0.5));
2178  annotate_info=AcquireImageInfo();
2179  (void) FormatLocaleString(annotate_info->filename,MagickPathExtent,"ps:%s",
2180  filename);
2181  (void) CloneString(&annotate_info->page,geometry);
2182  if (draw_info->density != (char *) NULL)
2183  (void) CloneString(&annotate_info->density,draw_info->density);
2184  annotate_info->antialias=draw_info->text_antialias;
2185  annotate_image=ReadImage(annotate_info,exception);
2186  CatchException(exception);
2187  annotate_info=DestroyImageInfo(annotate_info);
2188  (void) RelinquishUniqueFileResource(filename);
2189  if (annotate_image == (Image *) NULL)
2190  return(MagickFalse);
2191  (void) NegateImage(annotate_image,MagickFalse,exception);
2192  resolution.x=DefaultResolution;
2193  resolution.y=DefaultResolution;
2194  if (draw_info->density != (char *) NULL)
2195  {
2196  GeometryInfo
2197  geometry_info;
2198 
2200  flags;
2201 
2202  flags=ParseGeometry(draw_info->density,&geometry_info);
2203  if ((flags & RhoValue) != 0)
2204  resolution.x=geometry_info.rho;
2205  resolution.y=resolution.x;
2206  if ((flags & SigmaValue) != 0)
2207  resolution.y=geometry_info.sigma;
2208  }
2209  if (identity == MagickFalse)
2210  (void) TransformImage(&annotate_image,"0x0",(char *) NULL,exception);
2211  else
2212  {
2214  crop_info;
2215 
2216  crop_info=GetImageBoundingBox(annotate_image,exception);
2217  crop_info.height=(size_t) ((resolution.y/DefaultResolution)*
2218  ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
2219  crop_info.y=CastDoubleToLong(ceil((resolution.y/DefaultResolution)*
2220  extent.y/8.0-0.5));
2221  (void) FormatLocaleString(geometry,MagickPathExtent,
2222  "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
2223  crop_info.height,(double) crop_info.x,(double) crop_info.y);
2224  (void) TransformImage(&annotate_image,geometry,(char *) NULL,exception);
2225  }
2226  metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
2227  ExpandAffine(&draw_info->affine)*draw_info->pointsize;
2228  metrics->pixels_per_em.y=metrics->pixels_per_em.x;
2229  metrics->ascent=metrics->pixels_per_em.y;
2230  metrics->descent=metrics->pixels_per_em.y/-5.0;
2231  metrics->width=(double) annotate_image->columns/
2232  ExpandAffine(&draw_info->affine);
2233  metrics->height=floor(metrics->ascent-metrics->descent+0.5);
2234  metrics->max_advance=metrics->pixels_per_em.x;
2235  metrics->bounds.x1=0.0;
2236  metrics->bounds.y1=metrics->descent;
2237  metrics->bounds.x2=metrics->ascent+metrics->descent;
2238  metrics->bounds.y2=metrics->ascent+metrics->descent;
2239  metrics->underline_position=(-2.0);
2240  metrics->underline_thickness=1.0;
2241  if (draw_info->render == MagickFalse)
2242  {
2243  annotate_image=DestroyImage(annotate_image);
2244  return(MagickTrue);
2245  }
2246  if (draw_info->fill.alpha != TransparentAlpha)
2247  {
2248  CacheView
2249  *annotate_view;
2250 
2252  sync;
2253 
2254  PixelInfo
2255  fill_color;
2256 
2257  /*
2258  Render fill color.
2259  */
2260  if (image->alpha_trait == UndefinedPixelTrait)
2261  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2262  if (annotate_image->alpha_trait == UndefinedPixelTrait)
2263  (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel,
2264  exception);
2265  fill_color=draw_info->fill;
2266  annotate_view=AcquireAuthenticCacheView(annotate_image,exception);
2267  for (y=0; y < (ssize_t) annotate_image->rows; y++)
2268  {
2269  ssize_t
2270  x;
2271 
2272  Quantum
2273  *magick_restrict q;
2274 
2275  q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
2276  1,exception);
2277  if (q == (Quantum *) NULL)
2278  break;
2279  for (x=0; x < (ssize_t) annotate_image->columns; x++)
2280  {
2281  GetFillColor(draw_info,x,y,&fill_color,exception);
2282  SetPixelAlpha(annotate_image,ClampToQuantum((((double) QuantumScale*
2283  GetPixelIntensity(annotate_image,q)*fill_color.alpha))),q);
2284  SetPixelRed(annotate_image,fill_color.red,q);
2285  SetPixelGreen(annotate_image,fill_color.green,q);
2286  SetPixelBlue(annotate_image,fill_color.blue,q);
2287  q+=GetPixelChannels(annotate_image);
2288  }
2289  sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
2290  if (sync == MagickFalse)
2291  break;
2292  }
2293  annotate_view=DestroyCacheView(annotate_view);
2294  (void) CompositeImage(image,annotate_image,OverCompositeOp,MagickTrue,
2295  (ssize_t) ceil(offset->x-0.5),(ssize_t) ceil(offset->y-(metrics->ascent+
2296  metrics->descent)-0.5),exception);
2297  }
2298  annotate_image=DestroyImage(annotate_image);
2299  return(MagickTrue);
2300 }
2301 
2302 /*
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2304 % %
2305 % %
2306 % %
2307 + R e n d e r X 1 1 %
2308 % %
2309 % %
2310 % %
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312 %
2313 % RenderX11() renders text on the image with an X11 font. It also returns the
2314 % bounding box of the text relative to the image.
2315 %
2316 % The format of the RenderX11 method is:
2317 %
2318 % MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
2319 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
2320 %
2321 % A description of each parameter follows:
2322 %
2323 % o image: the image.
2324 %
2325 % o draw_info: the draw info.
2326 %
2327 % o offset: (x,y) location of text relative to image.
2328 %
2329 % o metrics: bounding box of text.
2330 %
2331 % o exception: return any errors or warnings in this structure.
2332 %
2333 */
2334 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
2335  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
2336 {
2338  status;
2339 
2340  if (annotate_semaphore == (SemaphoreInfo *) NULL)
2343  status=XRenderImage(image,draw_info,offset,metrics,exception);
2345  return(status);
2346 }
double psi
Definition: geometry.h:108
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
size_t face
Definition: type.h:53
PixelInfo fill
Definition: draw.h:214
MagickExport MagickBooleanType NegateImage(Image *image, const MagickBooleanType grayscale, ExceptionInfo *exception)
Definition: enhance.c:3922
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:253
PixelInfo undercolor
Definition: draw.h:214
MagickExport TokenInfo * DestroyTokenInfo(TokenInfo *token_info)
Definition: token.c:130
#define TransparentAlpha
Definition: image.h:26
char * primitive
Definition: draw.h:204
double x2
Definition: image.h:107
double rx
Definition: geometry.h:97
MagickExport MagickBooleanType QueryColorname(const Image *magick_unused(image), const PixelInfo *color, const ComplianceType compliance, char *name, ExceptionInfo *exception)
Definition: color.c:2671
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:328
MagickPrivate void AnnotateComponentTerminus(void)
Definition: annotate.c:189
double interword_spacing
Definition: draw.h:312
MagickExport size_t ConcatenateMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:392
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
GravityType gravity
Definition: draw.h:285
MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:449
MagickExport const TypeInfo * GetTypeInfo(const char *name, ExceptionInfo *exception)
Definition: type.c:282
double interline_spacing
Definition: draw.h:312
static int GetUTFCode(const char *magick_restrict text)
static MagickBooleanType IsNonBreakingUTFSpace(const int code)
#define ThrowFatalException(severity, tag)
PixelInfo stroke
Definition: draw.h:214
double ty
Definition: geometry.h:97
size_t cluster
Definition: annotate.c:124
char * metrics
Definition: type.h:71
double kerning
Definition: draw.h:312
Definition: draw.h:90
double rho
Definition: geometry.h:108
static void GetFillColor(const DrawInfo *draw_info, const ssize_t x, const ssize_t y, PixelInfo *fill, ExceptionInfo *exception)
Definition: draw-private.h:29
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1768
Image * fill_pattern
Definition: draw.h:220
MagickExport SemaphoreInfo * AcquireSemaphoreInfo(void)
Definition: semaphore.c:192
MagickBooleanType render
Definition: draw.h:306
MagickRealType red
Definition: pixel.h:194
MagickBooleanType antialias
Definition: image.h:384
double pointsize
Definition: draw.h:276
MagickExport ExceptionInfo * AcquireExceptionInfo(void)
Definition: exception.c:115
StyleType style
Definition: draw.h:264
DecorationType decorate
Definition: draw.h:249
MagickBooleanType debug
Definition: draw.h:320
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:466
static MagickBooleanType IsGrayColorspace(const ColorspaceType colorspace)
MagickExport size_t CopyMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:731
#define DefaultResolution
Definition: image-private.h:29
static MagickBooleanType RenderPostscript(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:2070
size_t y_offset
Definition: annotate.c:118
MagickRealType alpha
Definition: pixel.h:194
Definition: draw.h:34
#define MagickEpsilon
Definition: magick-type.h:114
double sigma
Definition: geometry.h:108
ClassType storage_class
Definition: image.h:154
MagickExport MagickBooleanType CompositeImage(Image *image, const Image *composite, const CompositeOperator compose, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:1525
AffineMatrix affine
Definition: draw.h:211
size_t width
Definition: geometry.h:132
MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type, const MagickSizeType size)
Definition: resource.c:188
Definition: log.h:52
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:86
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
Definition: image.h:151
double tx
Definition: geometry.h:97
double x
Definition: geometry.h:125
MagickExport TokenInfo * AcquireTokenInfo(void)
Definition: token.c:97
#define MagickCoreSignature
MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:293
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:300
static MagickBooleanType RenderType(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:966
double stroke_width
Definition: draw.h:224
MagickExport double ExpandAffine(const AffineMatrix *affine)
Definition: gem.c:1469
MagickExport ssize_t FormatMagickCaption(Image *image, DrawInfo *draw_info, const MagickBooleanType split, TypeMetric *metrics, char **caption, ExceptionInfo *exception)
Definition: annotate.c:622
Image * stroke_pattern
Definition: draw.h:220
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:371
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:972
MagickBooleanType
Definition: magick-type.h:161
unsigned int MagickStatusType
Definition: magick-type.h:125
MagickExport char * AcquireString(const char *source)
Definition: string.c:94
MagickExport MagickStatusType ParsePageGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1626
static double PerceptibleReciprocal(const double x)
MagickExport int AcquireUniqueFileResource(char *path)
Definition: resource.c:551
LineJoin linejoin
Definition: draw.h:240
MagickExport MagickBooleanType AnnotateImage(Image *image, const DrawInfo *draw_info, ExceptionInfo *exception)
Definition: annotate.c:223
char * family
Definition: type.h:56
double width
Definition: draw.h:372
static ssize_t CastDoubleToLong(const double x)
Definition: image-private.h:55
static MagickBooleanType IsUTFSpace(const int code)
PointInfo origin
Definition: draw.h:384
MagickExport void * AcquireCriticalMemory(const size_t size)
Definition: memory.c:626
double height
Definition: draw.h:372
double x1
Definition: image.h:107
double descent
Definition: draw.h:372
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:665
char filename[MagickPathExtent]
Definition: image.h:480
static FILE * fopen_utf8(const char *path, const char *mode)
char * metrics
Definition: draw.h:255
size_t face
Definition: draw.h:261
double y
Definition: geometry.h:125
MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
Definition: resource.c:1100
size_t scene
Definition: image.h:396
#define magick_unused(x)
RectangleInfo page
Definition: image.h:212
MagickPrivate MagickBooleanType XRenderImage(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: xwindow.c:10021
size_t x_advance
Definition: annotate.c:118
char * family
Definition: draw.h:255
size_t MagickSizeType
Definition: magick-type.h:134
#define MagickPathExtent
double ry
Definition: geometry.h:97
char * glyphs
Definition: type.h:71
MagickExport MagickBooleanType IsEventLogging(void)
Definition: log.c:763
MagickExport MagickBooleanType DrawImage(Image *image, const DrawInfo *draw_info, ExceptionInfo *exception)
Definition: draw.c:4494
Definition: type.h:50
static SemaphoreInfo * annotate_semaphore
Definition: annotate.c:131
#define ThrowFileException(exception, severity, tag, context)
PixelTrait alpha_trait
Definition: image.h:280
MagickRealType blue
Definition: pixel.h:194
PointInfo pixels_per_em
Definition: draw.h:369
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:601
MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info, const unsigned int frames, ExceptionInfo *exception)
Definition: image.c:2788
static MagickBooleanType RenderX11(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:2334
double sx
Definition: geometry.h:97
double y2
Definition: image.h:107
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1699
MagickExport MagickBooleanType IsPathAccessible(const char *path)
Definition: utility.c:1497
char * density
Definition: draw.h:279
size_t signature
Definition: image.h:354
#define QuantumScale
Definition: magick-type.h:119
size_t columns
Definition: image.h:172
MagickExport const TypeInfo * GetTypeInfoByFamily(const char *family, const StyleType style, const StretchType stretch, const size_t weight, ExceptionInfo *exception)
Definition: type.c:328
MagickExport MagickBooleanType SubstituteString(char **string, const char *search, const char *replace)
Definition: string.c:2585
ssize_t x
Definition: geometry.h:136
StretchType stretch
Definition: draw.h:267
MagickExport DrawInfo * CloneDrawInfo(const ImageInfo *image_info, const DrawInfo *draw_info)
Definition: draw.c:268
size_t height
Definition: geometry.h:132
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickPrivate MagickBooleanType AnnotateComponentGenesis(void)
Definition: annotate.c:164
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2620
MagickExport void CatchException(ExceptionInfo *exception)
Definition: exception.c:203
static double RoundToUnity(const double value)
char * encoding
Definition: draw.h:273
#define MagickMax(x, y)
Definition: image-private.h:38
static size_t GetPixelChannels(const Image *magick_restrict image)
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1406
char filename[MagickPathExtent]
Definition: image.h:319
double max_advance
Definition: draw.h:372
#define GetMagickModule()
Definition: log.h:28
double sy
Definition: geometry.h:97
double underline_thickness
Definition: draw.h:372
MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image, const DrawInfo *draw_info, TypeMetric *metrics, ExceptionInfo *exception)
Definition: annotate.c:753
char * density
Definition: image.h:413
SegmentInfo bounds
Definition: draw.h:381
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1252
size_t signature
Definition: draw.h:323
MagickExport MagickBooleanType GetTypeMetrics(Image *image, const DrawInfo *draw_info, TypeMetric *metrics, ExceptionInfo *exception)
Definition: annotate.c:894
char * geometry
Definition: draw.h:204
unsigned short Quantum
Definition: magick-type.h:86
double xi
Definition: geometry.h:108
MagickExport RectangleInfo GetImageBoundingBox(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:391
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1418
MagickExport DrawInfo * DestroyDrawInfo(DrawInfo *draw_info)
Definition: draw.c:965
MagickExport char * DestroyString(char *string)
Definition: string.c:788
MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:98
size_t index
Definition: annotate.c:118
MagickExport const char * GetImageProperty(const Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:2245
AlignType align
Definition: draw.h:282
double underline_position
Definition: draw.h:372
static char * EscapeParenthesis(const char *source)
Definition: annotate.c:2026
MagickBooleanType text_antialias
Definition: draw.h:230
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:867
size_t x_offset
Definition: annotate.c:118
MagickExport char * GetPolicyValue(const char *name)
Definition: policy.c:533
static void SetPixelAlpha(const Image *magick_restrict image, const Quantum alpha, Quantum *magick_restrict pixel)
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1734
MagickExport MagickBooleanType ConcatenateString(char **magick_restrict destination, const char *magick_restrict source)
Definition: string.c:458
static MagickBooleanType RenderFreetype(Image *, const DrawInfo *, const char *, const PointInfo *, TypeMetric *, ExceptionInfo *)
char * text
Definition: draw.h:255
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1162
#define magick_unreferenced(x)
double ascent
Definition: draw.h:372
static unsigned int GetUTFOctets(const char *magick_restrict text)
char * encoding
Definition: type.h:71
MagickRealType green
Definition: pixel.h:194
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:250
MagickExport char ** StringToStrings(const char *text, size_t *count)
Definition: string.c:2331
static void SetPixelRed(const Image *magick_restrict image, const Quantum red, Quantum *magick_restrict pixel)
#define MagickPrivate
static unsigned char * ConvertLatin1ToUTF8(const unsigned char *magick_restrict content)
Definition: token-private.h:54
#define MagickExport
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1101
ssize_t y
Definition: geometry.h:136
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
double y1
Definition: image.h:107
MagickExport char ** StringToArgv(const char *text, int *argc)
Definition: string.c:2023
static char * ReplaceSpaceWithNewline(char **caption, char *space)
Definition: annotate.c:592
char * page
Definition: image.h:390
double * dash_pattern
Definition: draw.h:291
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
char * font
Definition: draw.h:255
MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:351
DirectionType direction
Definition: draw.h:317
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1181
MagickExport char * ConstantString(const char *source)
Definition: string.c:678
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:87
MagickExport int Tokenizer(TokenInfo *token_info, const unsigned flag, char *token, const size_t max_token_length, const char *line, const char *white, const char *break_set, const char *quote, const char escape, char *breaker, int *next, char *quoted)
Definition: token.c:835
static void CompositePixelOver(const Image *image, const PixelInfo *p, const double alpha, const Quantum *q, const double beta, Quantum *composite)
MagickExport ExceptionInfo * DestroyExceptionInfo(ExceptionInfo *exception)
Definition: exception.c:418
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)
struct _GraphemeInfo GraphemeInfo
size_t weight
Definition: draw.h:270
MagickPrivate MagickBooleanType TransformImage(Image **, const char *, const char *, ExceptionInfo *)
Definition: transform.c:2037