MagickCore  7.0.10
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-2021 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 (image->debug != 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 MagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
592  const MagickBooleanType split,TypeMetric *metrics,char **caption,
593  ExceptionInfo *exception)
594 {
596  status;
597 
598  char
599  *p,
600  *q,
601  *s;
602 
603  ssize_t
604  i;
605 
606  size_t
607  width;
608 
609  ssize_t
610  n;
611 
612  q=draw_info->text;
613  s=(char *) NULL;
614  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
615  {
616  if (IsUTFSpace(GetUTFCode(p)) != MagickFalse)
617  s=p;
618  if (GetUTFCode(p) == '\n')
619  {
620  q=draw_info->text;
621  continue;
622  }
623  for (i=0; i < (ssize_t) GetUTFOctets(p); i++)
624  *q++=(*(p+i));
625  *q='\0';
626  status=GetTypeMetrics(image,draw_info,metrics,exception);
627  if (status == MagickFalse)
628  break;
629  width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5);
630  if (width <= image->columns)
631  continue;
632  if (s != (char *) NULL)
633  {
634  for (i=0; i < (ssize_t) GetUTFOctets(s); i++)
635  *(s+i)=' ';
636  *s='\n';
637  p=s;
638  }
639  else
640  if ((split != MagickFalse) || (GetUTFOctets(p) > 2))
641  {
642  /*
643  No convenient line breaks-- insert newline.
644  */
645  n=p-(*caption);
646  if ((n > 0) && ((*caption)[n-1] != '\n'))
647  {
648  char
649  *target;
650 
651  target=AcquireString(*caption);
652  CopyMagickString(target,*caption,n+1);
653  ConcatenateMagickString(target,"\n",strlen(*caption)+1);
654  ConcatenateMagickString(target,p,strlen(*caption)+2);
655  (void) DestroyString(*caption);
656  *caption=target;
657  p=(*caption)+n;
658  }
659  }
660  q=draw_info->text;
661  s=(char *) NULL;
662  }
663  n=0;
664  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
665  if (GetUTFCode(p) == '\n')
666  n++;
667  return(n);
668 }
669 
670 /*
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 % %
673 % %
674 % %
675 % G e t M u l t i l i n e T y p e M e t r i c s %
676 % %
677 % %
678 % %
679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 %
681 % GetMultilineTypeMetrics() returns the following information for the
682 % specified font and text:
683 %
684 % character width
685 % character height
686 % ascender
687 % descender
688 % text width
689 % text height
690 % maximum horizontal advance
691 % bounds: x1
692 % bounds: y1
693 % bounds: x2
694 % bounds: y2
695 % origin: x
696 % origin: y
697 % underline position
698 % underline thickness
699 %
700 % This method is like GetTypeMetrics() but it returns the maximum text width
701 % and height for multiple lines of text.
702 %
703 % The format of the GetMultilineTypeMetrics method is:
704 %
705 % MagickBooleanType GetMultilineTypeMetrics(Image *image,
706 % const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
707 %
708 % A description of each parameter follows:
709 %
710 % o image: the image.
711 %
712 % o draw_info: the draw info.
713 %
714 % o metrics: Return the font metrics in this structure.
715 %
716 % o exception: return any errors or warnings in this structure.
717 %
718 */
720  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
721 {
722  char
723  **textlist;
724 
725  double
726  height;
727 
728  DrawInfo
729  *annotate_info;
730 
732  status;
733 
735  size;
736 
737  ssize_t
738  i;
739 
740  size_t
741  count;
742 
743  TypeMetric
744  extent;
745 
746  assert(image != (Image *) NULL);
747  assert(image->signature == MagickCoreSignature);
748  if (image->debug != MagickFalse)
749  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
750  assert(draw_info != (DrawInfo *) NULL);
751  assert(draw_info->text != (char *) NULL);
752  assert(draw_info->signature == MagickCoreSignature);
753  if (*draw_info->text == '\0')
754  return(MagickFalse);
755  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
756  annotate_info->text=DestroyString(annotate_info->text);
757  /*
758  Convert newlines to multiple lines of text.
759  */
760  textlist=StringToStrings(draw_info->text,&count);
761  if (textlist == (char **) NULL)
762  return(MagickFalse);
763  annotate_info->render=MagickFalse;
764  annotate_info->direction=UndefinedDirection;
765  (void) memset(metrics,0,sizeof(*metrics));
766  (void) memset(&extent,0,sizeof(extent));
767  /*
768  Find the widest of the text lines.
769  */
770  annotate_info->text=textlist[0];
771  status=GetTypeMetrics(image,annotate_info,&extent,exception);
772  *metrics=extent;
773  height=(count*(size_t) (metrics->ascent-metrics->descent+
774  0.5)+(count-1)*draw_info->interline_spacing);
775  size=(MagickSizeType) fabs(height);
777  {
779  "WidthOrHeightExceedsLimit","`%s'",image->filename);
780  status=MagickFalse;
781  }
782  else
783  {
784  for (i=1; i < (ssize_t) count; i++)
785  {
786  annotate_info->text=textlist[i];
787  status=GetTypeMetrics(image,annotate_info,&extent,exception);
788  if (status == MagickFalse)
789  break;
790  if (extent.width > metrics->width)
791  *metrics=extent;
792  size=(MagickSizeType) fabs(extent.width);
794  {
796  "WidthOrHeightExceedsLimit","`%s'",image->filename);
797  status=MagickFalse;
798  break;
799  }
800  }
801  metrics->height=(double) height;
802  }
803  /*
804  Relinquish resources.
805  */
806  annotate_info->text=(char *) NULL;
807  annotate_info=DestroyDrawInfo(annotate_info);
808  for (i=0; i < (ssize_t) count; i++)
809  textlist[i]=DestroyString(textlist[i]);
810  textlist=(char **) RelinquishMagickMemory(textlist);
811  return(status);
812 }
813 
814 /*
815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 % %
817 % %
818 % %
819 % G e t T y p e M e t r i c s %
820 % %
821 % %
822 % %
823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 %
825 % GetTypeMetrics() returns the following information for the specified font
826 % and text:
827 %
828 % character width
829 % character height
830 % ascender
831 % descender
832 % text width
833 % text height
834 % maximum horizontal advance
835 % bounds: x1
836 % bounds: y1
837 % bounds: x2
838 % bounds: y2
839 % origin: x
840 % origin: y
841 % underline position
842 % underline thickness
843 %
844 % The format of the GetTypeMetrics method is:
845 %
846 % MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
847 % TypeMetric *metrics,ExceptionInfo *exception)
848 %
849 % A description of each parameter follows:
850 %
851 % o image: the image.
852 %
853 % o draw_info: the draw info.
854 %
855 % o metrics: Return the font metrics in this structure.
856 %
857 % o exception: return any errors or warnings in this structure.
858 %
859 */
861  const DrawInfo *draw_info,TypeMetric *metrics,ExceptionInfo *exception)
862 {
863  DrawInfo
864  *annotate_info;
865 
867  status;
868 
869  PointInfo
870  offset;
871 
872  assert(image != (Image *) NULL);
873  assert(image->signature == MagickCoreSignature);
874  if (image->debug != MagickFalse)
875  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
876  assert(draw_info != (DrawInfo *) NULL);
877  assert(draw_info->text != (char *) NULL);
878  assert(draw_info->signature == MagickCoreSignature);
879  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
880  annotate_info->render=MagickFalse;
881  annotate_info->direction=UndefinedDirection;
882  (void) memset(metrics,0,sizeof(*metrics));
883  offset.x=0.0;
884  offset.y=0.0;
885  status=RenderType(image,annotate_info,&offset,metrics,exception);
886  if (image->debug != MagickFalse)
887  (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
888  "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
889  "bounds: %g,%g %g,%g; origin: %g,%g; pixels per em: %g,%g; "
890  "underline position: %g; underline thickness: %g",annotate_info->text,
891  metrics->width,metrics->height,metrics->ascent,metrics->descent,
892  metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
893  metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
894  metrics->pixels_per_em.x,metrics->pixels_per_em.y,
895  metrics->underline_position,metrics->underline_thickness);
896  annotate_info=DestroyDrawInfo(annotate_info);
897  return(status);
898 }
899 
900 /*
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % %
903 % %
904 % %
905 + R e n d e r T y p e %
906 % %
907 % %
908 % %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 %
911 % RenderType() renders text on the image. It also returns the bounding box of
912 % the text relative to the image.
913 %
914 % The format of the RenderType method is:
915 %
916 % MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
917 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
918 %
919 % A description of each parameter follows:
920 %
921 % o image: the image.
922 %
923 % o draw_info: the draw info.
924 %
925 % o offset: (x,y) location of text relative to image.
926 %
927 % o metrics: bounding box of text.
928 %
929 % o exception: return any errors or warnings in this structure.
930 %
931 */
932 static MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
933  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
934 {
935  const char
936  *font;
937 
938  const TypeInfo
939  *type_info;
940 
941  DrawInfo
942  *annotate_info;
943 
945  *sans_exception;
946 
948  status;
949 
950  type_info=(const TypeInfo *) NULL;
951  if (draw_info->font != (char *) NULL)
952  {
953  if (*draw_info->font == '@')
954  {
955  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
956  metrics,exception);
957  return(status);
958  }
959  if (*draw_info->font == '-')
960  return(RenderX11(image,draw_info,offset,metrics,exception));
961  if (*draw_info->font == '^')
962  return(RenderPostscript(image,draw_info,offset,metrics,exception));
963  if (IsPathAccessible(draw_info->font) != MagickFalse)
964  {
965  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
966  metrics,exception);
967  return(status);
968  }
969  type_info=GetTypeInfo(draw_info->font,exception);
970  if (type_info == (const TypeInfo *) NULL)
972  "UnableToReadFont","`%s'",draw_info->font);
973  }
974  if ((type_info == (const TypeInfo *) NULL) &&
975  (draw_info->family != (const char *) NULL))
976  {
977  if (strchr(draw_info->family,',') == (char *) NULL)
978  type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
979  draw_info->stretch,draw_info->weight,exception);
980  if (type_info == (const TypeInfo *) NULL)
981  {
982  char
983  **family;
984 
985  int
986  number_families;
987 
988  ssize_t
989  i;
990 
991  /*
992  Parse font family list.
993  */
994  family=StringToArgv(draw_info->family,&number_families);
995  for (i=1; i < (ssize_t) number_families; i++)
996  {
997  type_info=GetTypeInfoByFamily(family[i],draw_info->style,
998  draw_info->stretch,draw_info->weight,exception);
999  if ((type_info != (const TypeInfo *) NULL) &&
1000  (LocaleCompare(family[i],type_info->family) == 0))
1001  break;
1002  }
1003  for (i=0; i < (ssize_t) number_families; i++)
1004  family[i]=DestroyString(family[i]);
1005  family=(char **) RelinquishMagickMemory(family);
1006  if (type_info == (const TypeInfo *) NULL)
1008  "UnableToReadFont","`%s'",draw_info->family);
1009  }
1010  }
1011  font=GetPolicyValue("system:font");
1012  if ((font != (const char *) NULL) && (IsPathAccessible(font) != MagickFalse))
1013  {
1014  /*
1015  Render with default system font.
1016  */
1017  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1018  annotate_info->font=ConstantString(font);
1019  status=RenderFreetype(image,annotate_info,annotate_info->encoding,offset,
1020  metrics,exception);
1021  annotate_info=DestroyDrawInfo(annotate_info);
1022  return(status);
1023  }
1024  sans_exception=AcquireExceptionInfo();
1025  if (type_info == (const TypeInfo *) NULL)
1026  type_info=GetTypeInfoByFamily("Open Sans",draw_info->style,
1027  draw_info->stretch,draw_info->weight,sans_exception);
1028  if (type_info == (const TypeInfo *) NULL)
1029  type_info=GetTypeInfoByFamily("Sans Serif",draw_info->style,
1030  draw_info->stretch,draw_info->weight,sans_exception);
1031  if (type_info == (const TypeInfo *) NULL)
1032  type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
1033  draw_info->stretch,draw_info->weight,sans_exception);
1034  if (type_info == (const TypeInfo *) NULL)
1035  type_info=GetTypeInfo("*",sans_exception);
1036  sans_exception=DestroyExceptionInfo(sans_exception);
1037  if (type_info == (const TypeInfo *) NULL)
1038  {
1039  status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics,
1040  exception);
1041  return(status);
1042  }
1043  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1044  annotate_info->face=type_info->face;
1045  if (type_info->metrics != (char *) NULL)
1046  (void) CloneString(&annotate_info->metrics,type_info->metrics);
1047  if (type_info->glyphs != (char *) NULL)
1048  (void) CloneString(&annotate_info->font,type_info->glyphs);
1049  status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics,
1050  exception);
1051  annotate_info=DestroyDrawInfo(annotate_info);
1052  return(status);
1053 }
1054 
1055 /*
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 % %
1058 % %
1059 % %
1060 + R e n d e r F r e e t y p e %
1061 % %
1062 % %
1063 % %
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065 %
1066 % RenderFreetype() renders text on the image with a Truetype font. It also
1067 % returns the bounding box of the text relative to the image.
1068 %
1069 % The format of the RenderFreetype method is:
1070 %
1071 % MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
1072 % const char *encoding,const PointInfo *offset,TypeMetric *metrics,
1073 % ExceptionInfo *exception)
1074 %
1075 % A description of each parameter follows:
1076 %
1077 % o image: the image.
1078 %
1079 % o draw_info: the draw info.
1080 %
1081 % o encoding: the font encoding.
1082 %
1083 % o offset: (x,y) location of text relative to image.
1084 %
1085 % o metrics: bounding box of text.
1086 %
1087 % o exception: return any errors or warnings in this structure.
1088 %
1089 */
1090 
1091 #if defined(MAGICKCORE_FREETYPE_DELEGATE)
1092 
1093 static size_t ComplexTextLayout(const Image *image,const DrawInfo *draw_info,
1094  const char *text,const size_t length,const FT_Face face,const FT_Int32 flags,
1095  GraphemeInfo **grapheme,ExceptionInfo *exception)
1096 {
1097 #if defined(MAGICKCORE_RAQM_DELEGATE)
1098  const char
1099  *features;
1100 
1101  raqm_t
1102  *rq;
1103 
1104  raqm_glyph_t
1105  *glyphs;
1106 
1107  ssize_t
1108  i;
1109 
1110  size_t
1111  extent;
1112 
1113  extent=0;
1114  rq=raqm_create();
1115  if (rq == (raqm_t *) NULL)
1116  goto cleanup;
1117  if (raqm_set_text_utf8(rq,text,length) == 0)
1118  goto cleanup;
1119  if (raqm_set_par_direction(rq,(raqm_direction_t) draw_info->direction) == 0)
1120  goto cleanup;
1121  if (raqm_set_freetype_face(rq,face) == 0)
1122  goto cleanup;
1123  features=GetImageProperty(image,"type:features",exception);
1124  if (features != (const char *) NULL)
1125  {
1126  char
1127  breaker,
1128  quote,
1129  *token;
1130 
1131  int
1132  next,
1133  status_token;
1134 
1135  TokenInfo
1136  *token_info;
1137 
1138  next=0;
1139  token_info=AcquireTokenInfo();
1140  token=AcquireString("");
1141  status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
1142  &breaker,&next,&quote);
1143  while (status_token == 0)
1144  {
1145  raqm_add_font_feature(rq,token,strlen(token));
1146  status_token=Tokenizer(token_info,0,token,50,features,"",",","",'\0',
1147  &breaker,&next,&quote);
1148  }
1149  token_info=DestroyTokenInfo(token_info);
1150  token=DestroyString(token);
1151  }
1152  if (raqm_layout(rq) == 0)
1153  goto cleanup;
1154  glyphs=raqm_get_glyphs(rq,&extent);
1155  if (glyphs == (raqm_glyph_t *) NULL)
1156  {
1157  extent=0;
1158  goto cleanup;
1159  }
1160  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(extent,sizeof(**grapheme));
1161  if (*grapheme == (GraphemeInfo *) NULL)
1162  {
1163  extent=0;
1164  goto cleanup;
1165  }
1166  for (i=0; i < (ssize_t) extent; i++)
1167  {
1168  (*grapheme)[i].index=glyphs[i].index;
1169  (*grapheme)[i].x_offset=glyphs[i].x_offset;
1170  (*grapheme)[i].x_advance=glyphs[i].x_advance;
1171  (*grapheme)[i].y_offset=glyphs[i].y_offset;
1172  (*grapheme)[i].cluster=glyphs[i].cluster;
1173  }
1174 
1175 cleanup:
1176  raqm_destroy(rq);
1177  return(extent);
1178 #else
1179  const char
1180  *p;
1181 
1182  FT_Error
1183  ft_status;
1184 
1185  ssize_t
1186  i;
1187 
1188  ssize_t
1189  last_glyph;
1190 
1191  /*
1192  Simple layout for bi-directional text (right-to-left or left-to-right).
1193  */
1194  magick_unreferenced(image);
1195  magick_unreferenced(exception);
1196  *grapheme=(GraphemeInfo *) AcquireQuantumMemory(length+1,sizeof(**grapheme));
1197  if (*grapheme == (GraphemeInfo *) NULL)
1198  return(0);
1199  last_glyph=0;
1200  p=text;
1201  for (i=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p), i++)
1202  {
1203  (*grapheme)[i].index=(ssize_t) FT_Get_Char_Index(face,GetUTFCode(p));
1204  (*grapheme)[i].x_offset=0;
1205  (*grapheme)[i].y_offset=0;
1206  if (((*grapheme)[i].index != 0) && (last_glyph != 0))
1207  {
1208  if (FT_HAS_KERNING(face))
1209  {
1210  FT_Vector
1211  kerning;
1212 
1213  ft_status=FT_Get_Kerning(face,(FT_UInt) last_glyph,(FT_UInt)
1214  (*grapheme)[i].index,ft_kerning_default,&kerning);
1215  if (ft_status == 0)
1216  (*grapheme)[i-1].x_advance+=(FT_Pos) ((draw_info->direction ==
1217  RightToLeftDirection ? -1.0 : 1.0)*kerning.x);
1218  }
1219  }
1220  ft_status=FT_Load_Glyph(face,(FT_UInt) (*grapheme)[i].index,flags);
1221  (*grapheme)[i].x_advance=face->glyph->advance.x;
1222  (*grapheme)[i].cluster=p-text;
1223  last_glyph=(*grapheme)[i].index;
1224  }
1225  return((size_t) i);
1226 #endif
1227 }
1228 
1229 static inline MagickBooleanType IsEmptyOutline(FT_Outline outline)
1230 {
1231  return((outline.n_points == 0) || (outline.n_contours <= 0) ? MagickTrue :
1232  MagickFalse);
1233 }
1234 
1235 static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
1236  DrawInfo *draw_info)
1237 {
1238  AffineMatrix
1239  affine;
1240 
1241  char
1242  path[MagickPathExtent];
1243 
1244  affine=draw_info->affine;
1245  (void) FormatLocaleString(path,MagickPathExtent,"C%g,%g %g,%g %g,%g",
1246  affine.tx+p->x/64.0,affine.ty-p->y/64.0,affine.tx+q->x/64.0,affine.ty-
1247  q->y/64.0,affine.tx+to->x/64.0,affine.ty-to->y/64.0);
1248  (void) ConcatenateString(&draw_info->primitive,path);
1249  return(0);
1250 }
1251 
1252 static int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
1253 {
1254  AffineMatrix
1255  affine;
1256 
1257  char
1258  path[MagickPathExtent];
1259 
1260  affine=draw_info->affine;
1261  (void) FormatLocaleString(path,MagickPathExtent,"L%g,%g",affine.tx+to->x/64.0,
1262  affine.ty-to->y/64.0);
1263  (void) ConcatenateString(&draw_info->primitive,path);
1264  return(0);
1265 }
1266 
1267 static int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
1268 {
1269  AffineMatrix
1270  affine;
1271 
1272  char
1273  path[MagickPathExtent];
1274 
1275  affine=draw_info->affine;
1276  (void) FormatLocaleString(path,MagickPathExtent,"M%g,%g",affine.tx+to->x/64.0,
1277  affine.ty-to->y/64.0);
1278  (void) ConcatenateString(&draw_info->primitive,path);
1279  return(0);
1280 }
1281 
1282 static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
1283  DrawInfo *draw_info)
1284 {
1285  AffineMatrix
1286  affine;
1287 
1288  char
1289  path[MagickPathExtent];
1290 
1291  affine=draw_info->affine;
1292  (void) FormatLocaleString(path,MagickPathExtent,"Q%g,%g %g,%g",affine.tx+
1293  control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,affine.ty-
1294  to->y/64.0);
1295  (void) ConcatenateString(&draw_info->primitive,path);
1296  return(0);
1297 }
1298 
1299 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
1300  const char *encoding,const PointInfo *offset,TypeMetric *metrics,
1301  ExceptionInfo *exception)
1302 {
1303 #if !defined(FT_OPEN_PATHNAME)
1304 #define FT_OPEN_PATHNAME ft_open_pathname
1305 #endif
1306 
1307  typedef struct _GlyphInfo
1308  {
1309  FT_UInt
1310  id;
1311 
1312  FT_Vector
1313  origin;
1314 
1315  FT_Glyph
1316  image;
1317  } GlyphInfo;
1318 
1319  const char
1320  *value;
1321 
1322  DrawInfo
1323  *annotate_info;
1324 
1325  FT_BBox
1326  bounds;
1327 
1328  FT_BitmapGlyph
1329  bitmap;
1330 
1331  FT_Encoding
1332  encoding_type;
1333 
1334  FT_Error
1335  ft_status;
1336 
1337  FT_Face
1338  face;
1339 
1340  FT_Int32
1341  flags;
1342 
1343  FT_Library
1344  library;
1345 
1346  FT_Matrix
1347  affine;
1348 
1349  FT_Open_Args
1350  args;
1351 
1352  FT_UInt
1353  first_glyph_id,
1354  last_glyph_id,
1355  missing_glyph_id;
1356 
1357  FT_Vector
1358  origin;
1359 
1360  GlyphInfo
1361  glyph;
1362 
1363  GraphemeInfo
1364  *grapheme;
1365 
1367  status;
1368 
1369  PointInfo
1370  point,
1371  resolution;
1372 
1373  char
1374  *p;
1375 
1376  ssize_t
1377  i;
1378 
1379  size_t
1380  length;
1381 
1382  ssize_t
1383  code,
1384  last_character,
1385  y;
1386 
1387  static FT_Outline_Funcs
1388  OutlineMethods =
1389  {
1390  (FT_Outline_MoveTo_Func) TraceMoveTo,
1391  (FT_Outline_LineTo_Func) TraceLineTo,
1392  (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
1393  (FT_Outline_CubicTo_Func) TraceCubicBezier,
1394  0, 0
1395  };
1396 
1397  unsigned char
1398  *utf8;
1399 
1400  /*
1401  Initialize Truetype library.
1402  */
1403  ft_status=FT_Init_FreeType(&library);
1404  if (ft_status != 0)
1405  ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
1406  image->filename);
1407  args.flags=FT_OPEN_PATHNAME;
1408  if (draw_info->font == (char *) NULL)
1409  args.pathname=ConstantString("helvetica");
1410  else
1411  if (*draw_info->font != '@')
1412  args.pathname=ConstantString(draw_info->font);
1413  else
1414  args.pathname=ConstantString(draw_info->font+1);
1415  face=(FT_Face) NULL;
1416  ft_status=FT_Open_Face(library,&args,(long) draw_info->face,&face);
1417  if (ft_status != 0)
1418  {
1419  (void) FT_Done_FreeType(library);
1420  (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
1421  "UnableToReadFont","`%s'",args.pathname);
1422  args.pathname=DestroyString(args.pathname);
1423  return(MagickFalse);
1424  }
1425  args.pathname=DestroyString(args.pathname);
1426  if ((draw_info->metrics != (char *) NULL) &&
1427  (IsPathAccessible(draw_info->metrics) != MagickFalse))
1428  (void) FT_Attach_File(face,draw_info->metrics);
1429  encoding_type=FT_ENCODING_UNICODE;
1430  ft_status=FT_Select_Charmap(face,encoding_type);
1431  if ((ft_status != 0) && (face->num_charmaps != 0))
1432  ft_status=FT_Set_Charmap(face,face->charmaps[0]);
1433  if (encoding != (const char *) NULL)
1434  {
1435  if (LocaleCompare(encoding,"AdobeCustom") == 0)
1436  encoding_type=FT_ENCODING_ADOBE_CUSTOM;
1437  if (LocaleCompare(encoding,"AdobeExpert") == 0)
1438  encoding_type=FT_ENCODING_ADOBE_EXPERT;
1439  if (LocaleCompare(encoding,"AdobeStandard") == 0)
1440  encoding_type=FT_ENCODING_ADOBE_STANDARD;
1441  if (LocaleCompare(encoding,"AppleRoman") == 0)
1442  encoding_type=FT_ENCODING_APPLE_ROMAN;
1443  if (LocaleCompare(encoding,"BIG5") == 0)
1444  encoding_type=FT_ENCODING_BIG5;
1445 #if defined(FT_ENCODING_PRC)
1446  if (LocaleCompare(encoding,"GB2312") == 0)
1447  encoding_type=FT_ENCODING_PRC;
1448 #endif
1449 #if defined(FT_ENCODING_JOHAB)
1450  if (LocaleCompare(encoding,"Johab") == 0)
1451  encoding_type=FT_ENCODING_JOHAB;
1452 #endif
1453 #if defined(FT_ENCODING_ADOBE_LATIN_1)
1454  if (LocaleCompare(encoding,"Latin-1") == 0)
1455  encoding_type=FT_ENCODING_ADOBE_LATIN_1;
1456 #endif
1457 #if defined(FT_ENCODING_ADOBE_LATIN_2)
1458  if (LocaleCompare(encoding,"Latin-2") == 0)
1459  encoding_type=FT_ENCODING_OLD_LATIN_2;
1460 #endif
1461  if (LocaleCompare(encoding,"None") == 0)
1462  encoding_type=FT_ENCODING_NONE;
1463  if (LocaleCompare(encoding,"SJIScode") == 0)
1464  encoding_type=FT_ENCODING_SJIS;
1465  if (LocaleCompare(encoding,"Symbol") == 0)
1466  encoding_type=FT_ENCODING_MS_SYMBOL;
1467  if (LocaleCompare(encoding,"Unicode") == 0)
1468  encoding_type=FT_ENCODING_UNICODE;
1469  if (LocaleCompare(encoding,"Wansung") == 0)
1470  encoding_type=FT_ENCODING_WANSUNG;
1471  ft_status=FT_Select_Charmap(face,encoding_type);
1472  if (ft_status != 0)
1473  {
1474  (void) FT_Done_Face(face);
1475  (void) FT_Done_FreeType(library);
1476  ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
1477  }
1478  }
1479  /*
1480  Set text size.
1481  */
1482  resolution.x=DefaultResolution;
1483  resolution.y=DefaultResolution;
1484  if (draw_info->density != (char *) NULL)
1485  {
1486  GeometryInfo
1487  geometry_info;
1488 
1490  geometry_flags;
1491 
1492  geometry_flags=ParseGeometry(draw_info->density,&geometry_info);
1493  resolution.x=geometry_info.rho;
1494  resolution.y=geometry_info.sigma;
1495  if ((geometry_flags & SigmaValue) == 0)
1496  resolution.y=resolution.x;
1497  }
1498  ft_status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
1499  (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
1500  (FT_UInt) resolution.y);
1501  if (ft_status != 0)
1502  {
1503  (void) FT_Done_Face(face);
1504  (void) FT_Done_FreeType(library);
1505  ThrowBinaryException(TypeError,"UnableToReadFont",draw_info->font);
1506  }
1507  metrics->pixels_per_em.x=face->size->metrics.x_ppem;
1508  metrics->pixels_per_em.y=face->size->metrics.y_ppem;
1509  metrics->ascent=(double) face->size->metrics.ascender/64.0;
1510  metrics->descent=(double) face->size->metrics.descender/64.0;
1511  metrics->width=0;
1512  metrics->origin.x=0;
1513  metrics->origin.y=0;
1514  metrics->height=(double) face->size->metrics.height/64.0;
1515  metrics->max_advance=0.0;
1516  if (face->size->metrics.max_advance > MagickEpsilon)
1517  metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
1518  metrics->bounds.x1=0.0;
1519  metrics->bounds.y1=metrics->descent;
1520  metrics->bounds.x2=metrics->ascent+metrics->descent;
1521  metrics->bounds.y2=metrics->ascent+metrics->descent;
1522  metrics->underline_position=face->underline_position*
1523  (metrics->pixels_per_em.x*PerceptibleReciprocal(face->units_per_EM));
1524  metrics->underline_thickness=face->underline_thickness*
1525  (metrics->pixels_per_em.x*PerceptibleReciprocal(face->units_per_EM));
1526  first_glyph_id=0;
1527  FT_Get_First_Char(face,&first_glyph_id);
1528  if ((draw_info->text == (char *) NULL) || (*draw_info->text == '\0') ||
1529  (first_glyph_id == 0))
1530  {
1531  (void) FT_Done_Face(face);
1532  (void) FT_Done_FreeType(library);
1533  return(MagickTrue);
1534  }
1535  /*
1536  Compute bounding box.
1537  */
1538  if (image->debug != MagickFalse)
1539  (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
1540  "font-encoding %s; text-encoding %s; pointsize %g",
1541  draw_info->font != (char *) NULL ? draw_info->font : "none",
1542  encoding != (char *) NULL ? encoding : "none",
1543  draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
1544  draw_info->pointsize);
1545  flags=FT_LOAD_DEFAULT;
1546  if (draw_info->render == MagickFalse)
1547  flags=FT_LOAD_NO_BITMAP;
1548  if (draw_info->text_antialias == MagickFalse)
1549  flags|=FT_LOAD_RENDER | FT_LOAD_TARGET_MONO;
1550  else
1551  {
1552 #if defined(FT_LOAD_TARGET_LIGHT)
1553  flags|=FT_LOAD_TARGET_LIGHT;
1554 #elif defined(FT_LOAD_TARGET_LCD)
1555  flags|=FT_LOAD_TARGET_LCD;
1556 #endif
1557  }
1558  value=GetImageProperty(image,"type:hinting",exception);
1559  if ((value != (const char *) NULL) && (LocaleCompare(value,"off") == 0))
1560  flags|=FT_LOAD_NO_HINTING;
1561  glyph.id=0;
1562  glyph.image=(FT_Glyph) NULL;
1563  last_glyph_id=0;
1564  origin.x=0;
1565  origin.y=0;
1566  affine.xx=65536L;
1567  affine.yx=0L;
1568  affine.xy=0L;
1569  affine.yy=65536L;
1570  if (draw_info->render != MagickFalse)
1571  {
1572  affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
1573  affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
1574  affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
1575  affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
1576  }
1577  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
1578  if (annotate_info->dash_pattern != (double *) NULL)
1579  annotate_info->dash_pattern[0]=0.0;
1580  (void) CloneString(&annotate_info->primitive,"path '");
1581  status=MagickTrue;
1582  if (draw_info->render != MagickFalse)
1583  {
1584  if (image->storage_class != DirectClass)
1585  (void) SetImageStorageClass(image,DirectClass,exception);
1586  if (image->alpha_trait == UndefinedPixelTrait)
1587  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1588  }
1589  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
1590  if (GetUTFCode(p) < 0)
1591  break;
1592  utf8=(unsigned char *) NULL;
1593  if (GetUTFCode(p) == 0)
1594  p=draw_info->text;
1595  else
1596  {
1597  utf8=ConvertLatin1ToUTF8((unsigned char *) draw_info->text);
1598  if (utf8 != (unsigned char *) NULL)
1599  p=(char *) utf8;
1600  }
1601  grapheme=(GraphemeInfo *) NULL;
1602  length=ComplexTextLayout(image,draw_info,p,strlen(p),face,flags,&grapheme,
1603  exception);
1604  missing_glyph_id=FT_Get_Char_Index(face,' ');
1605  code=0;
1606  last_character=(ssize_t) length-1;
1607  for (i=0; i < (ssize_t) length; i++)
1608  {
1609  FT_Outline
1610  outline;
1611 
1612  /*
1613  Render UTF-8 sequence.
1614  */
1615  glyph.id=(FT_UInt) grapheme[i].index;
1616  if (glyph.id == 0)
1617  glyph.id=missing_glyph_id;
1618  if ((glyph.id != 0) && (last_glyph_id != 0))
1619  origin.x+=(FT_Pos) (64.0*draw_info->kerning);
1620  glyph.origin=origin;
1621  glyph.origin.x+=(FT_Pos) grapheme[i].x_offset;
1622  glyph.origin.y+=(FT_Pos) grapheme[i].y_offset;
1623  if (glyph.image != (FT_Glyph) NULL)
1624  {
1625  FT_Done_Glyph(glyph.image);
1626  glyph.image=(FT_Glyph) NULL;
1627  }
1628  ft_status=FT_Load_Glyph(face,glyph.id,flags);
1629  if (ft_status != 0)
1630  continue;
1631  ft_status=FT_Get_Glyph(face->glyph,&glyph.image);
1632  if (ft_status != 0)
1633  continue;
1634  outline=((FT_OutlineGlyph) glyph.image)->outline;
1635  if ((glyph.image->format != FT_GLYPH_FORMAT_OUTLINE) &&
1636  (IsEmptyOutline(outline) == MagickFalse))
1637  continue;
1638  ft_status=FT_Outline_Get_BBox(&outline,&bounds);
1639  if (ft_status != 0)
1640  continue;
1641  if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
1642  if (bounds.xMin != 0)
1643  metrics->bounds.x1=(double) bounds.xMin;
1644  if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
1645  if (bounds.yMin != 0)
1646  metrics->bounds.y1=(double) bounds.yMin;
1647  if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
1648  if (bounds.xMax != 0)
1649  metrics->bounds.x2=(double) bounds.xMax;
1650  if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
1651  if (bounds.yMax != 0)
1652  metrics->bounds.y2=(double) bounds.yMax;
1653  if (((draw_info->stroke.alpha != TransparentAlpha) ||
1654  (draw_info->stroke_pattern != (Image *) NULL)) &&
1655  ((status != MagickFalse) && (draw_info->render != MagickFalse)))
1656  {
1657  /*
1658  Trace the glyph.
1659  */
1660  annotate_info->affine.tx=glyph.origin.x/64.0;
1661  annotate_info->affine.ty=(-glyph.origin.y/64.0);
1662  if (IsEmptyOutline(outline) == MagickFalse)
1663  ft_status=FT_Outline_Decompose(&outline,&OutlineMethods,
1664  annotate_info);
1665  }
1666  FT_Vector_Transform(&glyph.origin,&affine);
1667  (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
1668  ft_status=FT_Glyph_To_Bitmap(&glyph.image,FT_RENDER_MODE_NORMAL,
1669  (FT_Vector *) NULL,MagickTrue);
1670  if (ft_status != 0)
1671  continue;
1672  bitmap=(FT_BitmapGlyph) glyph.image;
1673  point.x=offset->x+bitmap->left;
1674  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
1675  point.x+=(origin.x/64.0);
1676  point.y=offset->y-bitmap->top;
1677  if (draw_info->render != MagickFalse)
1678  {
1679  CacheView
1680  *image_view;
1681 
1683  transparent_fill;
1684 
1685  unsigned char
1686  *r;
1687 
1688  /*
1689  Rasterize the glyph.
1690  */
1691  transparent_fill=((draw_info->fill.alpha == TransparentAlpha) &&
1692  (draw_info->fill_pattern == (Image *) NULL) &&
1693  (draw_info->stroke.alpha == TransparentAlpha) &&
1694  (draw_info->stroke_pattern == (Image *) NULL)) ? MagickTrue :
1695  MagickFalse;
1696  image_view=AcquireAuthenticCacheView(image,exception);
1697  r=bitmap->bitmap.buffer;
1698  for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++)
1699  {
1700  double
1701  fill_opacity;
1702 
1704  active,
1705  sync;
1706 
1707  PixelInfo
1708  fill_color;
1709 
1710  Quantum
1711  *magick_restrict q;
1712 
1713  ssize_t
1714  x;
1715 
1716  ssize_t
1717  n,
1718  x_offset,
1719  y_offset;
1720 
1721  if (status == MagickFalse)
1722  continue;
1723  x_offset=CastDoubleToLong(ceil(point.x-0.5));
1724  y_offset=CastDoubleToLong(ceil(point.y+y-0.5));
1725  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
1726  continue;
1727  q=(Quantum *) NULL;
1728  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
1729  active=MagickFalse;
1730  else
1731  {
1732  q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
1733  bitmap->bitmap.width,1,exception);
1734  active=q != (Quantum *) NULL ? MagickTrue : MagickFalse;
1735  }
1736  n=y*bitmap->bitmap.pitch;
1737  for (x=0; x < (ssize_t) bitmap->bitmap.width; x++, n++)
1738  {
1739  x_offset=CastDoubleToLong(ceil(point.x+x-0.5));
1740  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
1741  {
1742  if (q != (Quantum *) NULL)
1743  q+=GetPixelChannels(image);
1744  continue;
1745  }
1746  fill_opacity=1.0;
1747  if (bitmap->bitmap.buffer != (unsigned char *) NULL)
1748  {
1749  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_grays)
1750  fill_opacity=(double) (r[n])/(bitmap->bitmap.num_grays-1);
1751  else
1752  if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
1753  fill_opacity=((r[(x >> 3)+y*bitmap->bitmap.pitch] &
1754  (1 << (~x & 0x07)))) == 0 ? 0.0 : 1.0;
1755  }
1756  if (draw_info->text_antialias == MagickFalse)
1757  fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
1758  if (active == MagickFalse)
1759  q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
1760  exception);
1761  if (q == (Quantum *) NULL)
1762  continue;
1763  if (transparent_fill == MagickFalse)
1764  {
1765  GetPixelInfo(image,&fill_color);
1766  GetFillColor(draw_info,x_offset,y_offset,&fill_color,exception);
1767  fill_opacity=fill_opacity*fill_color.alpha;
1768  CompositePixelOver(image,&fill_color,fill_opacity,q,
1769  GetPixelAlpha(image,q),q);
1770  }
1771  else
1772  {
1773  double
1774  Sa,
1775  Da;
1776 
1777  Da=1.0-(QuantumScale*GetPixelAlpha(image,q));
1778  Sa=fill_opacity;
1779  fill_opacity=(1.0-RoundToUnity(Sa+Da-Sa*Da))*QuantumRange;
1780  SetPixelAlpha(image,fill_opacity,q);
1781  }
1782  if (active == MagickFalse)
1783  {
1784  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1785  if (sync == MagickFalse)
1786  status=MagickFalse;
1787  }
1788  q+=GetPixelChannels(image);
1789  }
1790  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1791  if (sync == MagickFalse)
1792  status=MagickFalse;
1793  }
1794  image_view=DestroyCacheView(image_view);
1795  if (((draw_info->stroke.alpha != TransparentAlpha) ||
1796  (draw_info->stroke_pattern != (Image *) NULL)) &&
1797  (status != MagickFalse))
1798  {
1799  /*
1800  Draw text stroke.
1801  */
1802  annotate_info->linejoin=RoundJoin;
1803  annotate_info->affine.tx=offset->x;
1804  annotate_info->affine.ty=offset->y;
1805  (void) ConcatenateString(&annotate_info->primitive,"'");
1806  if (strlen(annotate_info->primitive) > 7)
1807  (void) DrawImage(image,annotate_info,exception);
1808  (void) CloneString(&annotate_info->primitive,"path '");
1809  }
1810  }
1811  if ((fabs(draw_info->interword_spacing) >= MagickEpsilon) &&
1812  (IsUTFSpace(GetUTFCode(p+grapheme[i].cluster)) != MagickFalse) &&
1813  (IsUTFSpace(code) == MagickFalse))
1814  origin.x+=(FT_Pos) (64.0*draw_info->interword_spacing);
1815  else
1816  if (i == last_character)
1817  origin.x+=MagickMax((FT_Pos) grapheme[i].x_advance,bounds.xMax);
1818  else
1819  origin.x+=(FT_Pos) grapheme[i].x_advance;
1820  metrics->origin.x=(double) origin.x;
1821  metrics->origin.y=(double) origin.y;
1822  if (metrics->origin.x > metrics->width)
1823  metrics->width=metrics->origin.x;
1824  last_glyph_id=glyph.id;
1825  code=GetUTFCode(p+grapheme[i].cluster);
1826  }
1827  if (grapheme != (GraphemeInfo *) NULL)
1828  grapheme=(GraphemeInfo *) RelinquishMagickMemory(grapheme);
1829  if (utf8 != (unsigned char *) NULL)
1830  utf8=(unsigned char *) RelinquishMagickMemory(utf8);
1831  if (glyph.image != (FT_Glyph) NULL)
1832  {
1833  FT_Done_Glyph(glyph.image);
1834  glyph.image=(FT_Glyph) NULL;
1835  }
1836  /*
1837  Determine font metrics.
1838  */
1839  metrics->bounds.x1/=64.0;
1840  metrics->bounds.y1/=64.0;
1841  metrics->bounds.x2/=64.0;
1842  metrics->bounds.y2/=64.0;
1843  metrics->origin.x/=64.0;
1844  metrics->origin.y/=64.0;
1845  metrics->width=ceil(metrics->width/64.0);
1846  /*
1847  Relinquish resources.
1848  */
1849  annotate_info=DestroyDrawInfo(annotate_info);
1850  (void) FT_Done_Face(face);
1851  (void) FT_Done_FreeType(library);
1852  return(status);
1853 }
1854 #else
1855 static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
1856  const char *magick_unused(encoding),const PointInfo *offset,
1857  TypeMetric *metrics,ExceptionInfo *exception)
1858 {
1859  (void) ThrowMagickException(exception,GetMagickModule(),
1860  MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (Freetype)",
1861  draw_info->font != (char *) NULL ? draw_info->font : "none");
1862  return(RenderPostscript(image,draw_info,offset,metrics,exception));
1863 }
1864 #endif
1865 
1866 /*
1867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1868 % %
1869 % %
1870 % %
1871 + R e n d e r P o s t s c r i p t %
1872 % %
1873 % %
1874 % %
1875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1876 %
1877 % RenderPostscript() renders text on the image with a Postscript font. It
1878 % also returns the bounding box of the text relative to the image.
1879 %
1880 % The format of the RenderPostscript method is:
1881 %
1882 % MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
1883 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
1884 %
1885 % A description of each parameter follows:
1886 %
1887 % o image: the image.
1888 %
1889 % o draw_info: the draw info.
1890 %
1891 % o offset: (x,y) location of text relative to image.
1892 %
1893 % o metrics: bounding box of text.
1894 %
1895 % o exception: return any errors or warnings in this structure.
1896 %
1897 */
1898 
1899 static char *EscapeParenthesis(const char *source)
1900 {
1901  char
1902  *destination;
1903 
1904  char
1905  *q;
1906 
1907  const char
1908  *p;
1909 
1910  size_t
1911  length;
1912 
1913  assert(source != (const char *) NULL);
1914  length=0;
1915  for (p=source; *p != '\0'; p++)
1916  {
1917  if ((*p == '\\') || (*p == '(') || (*p == ')'))
1918  {
1919  if (~length < 1)
1920  ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
1921  length++;
1922  }
1923  length++;
1924  }
1925  destination=(char *) NULL;
1926  if (~length >= (MagickPathExtent-1))
1927  destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
1928  sizeof(*destination));
1929  if (destination == (char *) NULL)
1930  ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
1931  *destination='\0';
1932  q=destination;
1933  for (p=source; *p != '\0'; p++)
1934  {
1935  if ((*p == '\\') || (*p == '(') || (*p == ')'))
1936  *q++='\\';
1937  *q++=(*p);
1938  }
1939  *q='\0';
1940  return(destination);
1941 }
1942 
1944  const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics,
1945  ExceptionInfo *exception)
1946 {
1947  char
1948  filename[MagickPathExtent],
1949  geometry[MagickPathExtent],
1950  *text;
1951 
1952  FILE
1953  *file;
1954 
1955  Image
1956  *annotate_image;
1957 
1958  ImageInfo
1959  *annotate_info;
1960 
1961  int
1962  unique_file;
1963 
1965  identity;
1966 
1967  PointInfo
1968  extent,
1969  point,
1970  resolution;
1971 
1972  ssize_t
1973  i;
1974 
1975  size_t
1976  length;
1977 
1978  ssize_t
1979  y;
1980 
1981  /*
1982  Render label with a Postscript font.
1983  */
1984  if (image->debug != MagickFalse)
1986  "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
1987  draw_info->font : "none",draw_info->pointsize);
1988  file=(FILE *) NULL;
1989  unique_file=AcquireUniqueFileResource(filename);
1990  if (unique_file != -1)
1991  file=fdopen(unique_file,"wb");
1992  if ((unique_file == -1) || (file == (FILE *) NULL))
1993  {
1994  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",filename);
1995  return(MagickFalse);
1996  }
1997  (void) FormatLocaleFile(file,"%%!PS-Adobe-3.0\n");
1998  (void) FormatLocaleFile(file,"/ReencodeType\n");
1999  (void) FormatLocaleFile(file,"{\n");
2000  (void) FormatLocaleFile(file," findfont dup length\n");
2001  (void) FormatLocaleFile(file,
2002  " dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
2003  (void) FormatLocaleFile(file,
2004  " /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
2005  (void) FormatLocaleFile(file,"} bind def\n");
2006  /*
2007  Sample to compute bounding box.
2008  */
2009  identity=(fabs(draw_info->affine.sx-draw_info->affine.sy) < MagickEpsilon) &&
2010  (fabs(draw_info->affine.rx) < MagickEpsilon) &&
2011  (fabs(draw_info->affine.ry) < MagickEpsilon) ? MagickTrue : MagickFalse;
2012  extent.x=0.0;
2013  extent.y=0.0;
2014  length=strlen(draw_info->text);
2015  for (i=0; i <= (ssize_t) (length+2); i++)
2016  {
2017  point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
2018  draw_info->affine.ry*2.0*draw_info->pointsize);
2019  point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
2020  draw_info->affine.sy*2.0*draw_info->pointsize);
2021  if (point.x > extent.x)
2022  extent.x=point.x;
2023  if (point.y > extent.y)
2024  extent.y=point.y;
2025  }
2026  (void) FormatLocaleFile(file,"%g %g moveto\n",identity != MagickFalse ? 0.0 :
2027  extent.x/2.0,extent.y/2.0);
2028  (void) FormatLocaleFile(file,"%g %g scale\n",draw_info->pointsize,
2029  draw_info->pointsize);
2030  if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
2031  (strchr(draw_info->font,'/') != (char *) NULL))
2032  (void) FormatLocaleFile(file,
2033  "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
2034  else
2035  (void) FormatLocaleFile(file,
2036  "/%s-ISO dup /%s ReencodeType findfont setfont\n",draw_info->font,
2037  draw_info->font);
2038  (void) FormatLocaleFile(file,"[%g %g %g %g 0 0] concat\n",
2039  draw_info->affine.sx,-draw_info->affine.rx,-draw_info->affine.ry,
2040  draw_info->affine.sy);
2041  text=EscapeParenthesis(draw_info->text);
2042  if (identity == MagickFalse)
2043  (void) FormatLocaleFile(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",
2044  text);
2045  (void) FormatLocaleFile(file,"(%s) show\n",text);
2046  text=DestroyString(text);
2047  (void) FormatLocaleFile(file,"showpage\n");
2048  (void) fclose(file);
2049  (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0!",
2050  floor(extent.x+0.5),floor(extent.y+0.5));
2051  annotate_info=AcquireImageInfo();
2052  (void) FormatLocaleString(annotate_info->filename,MagickPathExtent,"ps:%s",
2053  filename);
2054  (void) CloneString(&annotate_info->page,geometry);
2055  if (draw_info->density != (char *) NULL)
2056  (void) CloneString(&annotate_info->density,draw_info->density);
2057  annotate_info->antialias=draw_info->text_antialias;
2058  annotate_image=ReadImage(annotate_info,exception);
2059  CatchException(exception);
2060  annotate_info=DestroyImageInfo(annotate_info);
2061  (void) RelinquishUniqueFileResource(filename);
2062  if (annotate_image == (Image *) NULL)
2063  return(MagickFalse);
2064  (void) NegateImage(annotate_image,MagickFalse,exception);
2065  resolution.x=DefaultResolution;
2066  resolution.y=DefaultResolution;
2067  if (draw_info->density != (char *) NULL)
2068  {
2069  GeometryInfo
2070  geometry_info;
2071 
2073  flags;
2074 
2075  flags=ParseGeometry(draw_info->density,&geometry_info);
2076  resolution.x=geometry_info.rho;
2077  resolution.y=geometry_info.sigma;
2078  if ((flags & SigmaValue) == 0)
2079  resolution.y=resolution.x;
2080  }
2081  if (identity == MagickFalse)
2082  (void) TransformImage(&annotate_image,"0x0",(char *) NULL,exception);
2083  else
2084  {
2086  crop_info;
2087 
2088  crop_info=GetImageBoundingBox(annotate_image,exception);
2089  crop_info.height=(size_t) ((resolution.y/DefaultResolution)*
2090  ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
2091  crop_info.y=CastDoubleToLong(ceil((resolution.y/DefaultResolution)*
2092  extent.y/8.0-0.5));
2093  (void) FormatLocaleString(geometry,MagickPathExtent,
2094  "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
2095  crop_info.height,(double) crop_info.x,(double) crop_info.y);
2096  (void) TransformImage(&annotate_image,geometry,(char *) NULL,exception);
2097  }
2098  metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
2099  ExpandAffine(&draw_info->affine)*draw_info->pointsize;
2100  metrics->pixels_per_em.y=metrics->pixels_per_em.x;
2101  metrics->ascent=metrics->pixels_per_em.x;
2102  metrics->descent=metrics->pixels_per_em.y/-5.0;
2103  metrics->width=(double) annotate_image->columns/
2104  ExpandAffine(&draw_info->affine);
2105  metrics->height=1.152*metrics->pixels_per_em.x;
2106  metrics->max_advance=metrics->pixels_per_em.x;
2107  metrics->bounds.x1=0.0;
2108  metrics->bounds.y1=metrics->descent;
2109  metrics->bounds.x2=metrics->ascent+metrics->descent;
2110  metrics->bounds.y2=metrics->ascent+metrics->descent;
2111  metrics->underline_position=(-2.0);
2112  metrics->underline_thickness=1.0;
2113  if (draw_info->render == MagickFalse)
2114  {
2115  annotate_image=DestroyImage(annotate_image);
2116  return(MagickTrue);
2117  }
2118  if (draw_info->fill.alpha != TransparentAlpha)
2119  {
2120  CacheView
2121  *annotate_view;
2122 
2124  sync;
2125 
2126  PixelInfo
2127  fill_color;
2128 
2129  /*
2130  Render fill color.
2131  */
2132  if (image->alpha_trait == UndefinedPixelTrait)
2133  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2134  if (annotate_image->alpha_trait == UndefinedPixelTrait)
2135  (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel,
2136  exception);
2137  fill_color=draw_info->fill;
2138  annotate_view=AcquireAuthenticCacheView(annotate_image,exception);
2139  for (y=0; y < (ssize_t) annotate_image->rows; y++)
2140  {
2141  ssize_t
2142  x;
2143 
2144  Quantum
2145  *magick_restrict q;
2146 
2147  q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
2148  1,exception);
2149  if (q == (Quantum *) NULL)
2150  break;
2151  for (x=0; x < (ssize_t) annotate_image->columns; x++)
2152  {
2153  GetFillColor(draw_info,x,y,&fill_color,exception);
2154  SetPixelAlpha(annotate_image,ClampToQuantum((((double) QuantumScale*
2155  GetPixelIntensity(annotate_image,q)*fill_color.alpha))),q);
2156  SetPixelRed(annotate_image,fill_color.red,q);
2157  SetPixelGreen(annotate_image,fill_color.green,q);
2158  SetPixelBlue(annotate_image,fill_color.blue,q);
2159  q+=GetPixelChannels(annotate_image);
2160  }
2161  sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
2162  if (sync == MagickFalse)
2163  break;
2164  }
2165  annotate_view=DestroyCacheView(annotate_view);
2166  (void) CompositeImage(image,annotate_image,OverCompositeOp,MagickTrue,
2167  (ssize_t) ceil(offset->x-0.5),(ssize_t) ceil(offset->y-(metrics->ascent+
2168  metrics->descent)-0.5),exception);
2169  }
2170  annotate_image=DestroyImage(annotate_image);
2171  return(MagickTrue);
2172 }
2173 
2174 /*
2175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176 % %
2177 % %
2178 % %
2179 + R e n d e r X 1 1 %
2180 % %
2181 % %
2182 % %
2183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 %
2185 % RenderX11() renders text on the image with an X11 font. It also returns the
2186 % bounding box of the text relative to the image.
2187 %
2188 % The format of the RenderX11 method is:
2189 %
2190 % MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
2191 % const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
2192 %
2193 % A description of each parameter follows:
2194 %
2195 % o image: the image.
2196 %
2197 % o draw_info: the draw info.
2198 %
2199 % o offset: (x,y) location of text relative to image.
2200 %
2201 % o metrics: bounding box of text.
2202 %
2203 % o exception: return any errors or warnings in this structure.
2204 %
2205 */
2206 static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
2207  const PointInfo *offset,TypeMetric *metrics,ExceptionInfo *exception)
2208 {
2210  status;
2211 
2212  if (annotate_semaphore == (SemaphoreInfo *) NULL)
2215  status=XRenderImage(image,draw_info,offset,metrics,exception);
2217  return(status);
2218 }
double psi
Definition: geometry.h:107
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:3906
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
PixelInfo undercolor
Definition: draw.h:214
MagickExport TokenInfo * DestroyTokenInfo(TokenInfo *token_info)
Definition: token.c:129
#define TransparentAlpha
Definition: image.h:26
char * primitive
Definition: draw.h:204
double x2
Definition: image.h:107
double rx
Definition: geometry.h:96
MagickExport MagickBooleanType QueryColorname(const Image *magick_unused(image), const PixelInfo *color, const ComplianceType compliance, char *name, ExceptionInfo *exception)
Definition: color.c:2660
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:327
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:276
double interline_spacing
Definition: draw.h:312
static int GetUTFCode(const char *magick_restrict text)
#define ThrowFatalException(severity, tag)
PixelInfo stroke
Definition: draw.h:214
double ty
Definition: geometry.h:96
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:107
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:1725
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:193
static MagickBooleanType IsUTFSpace(int code)
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
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:467
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:719
#define DefaultResolution
Definition: image-private.h:27
static MagickBooleanType RenderPostscript(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:1943
size_t y_offset
Definition: annotate.c:118
MagickRealType alpha
Definition: pixel.h:193
Definition: draw.h:34
#define MagickEpsilon
Definition: magick-type.h:118
double sigma
Definition: geometry.h:107
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:528
AffineMatrix affine
Definition: draw.h:211
size_t width
Definition: geometry.h:131
MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type, const MagickSizeType size)
Definition: resource.c:188
#define ThrowBinaryException(severity, tag, context)
Definition: log.h:52
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
Definition: image.h:151
double tx
Definition: geometry.h:96
double x
Definition: geometry.h:124
MagickExport TokenInfo * AcquireTokenInfo(void)
Definition: token.c:96
#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:299
static MagickBooleanType RenderType(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:932
double stroke_width
Definition: draw.h:224
MagickExport double ExpandAffine(const AffineMatrix *affine)
Definition: gem.c:1459
MagickExport ssize_t FormatMagickCaption(Image *image, DrawInfo *draw_info, const MagickBooleanType split, TypeMetric *metrics, char **caption, ExceptionInfo *exception)
Definition: annotate.c:591
Image * stroke_pattern
Definition: draw.h:220
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:372
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:974
MagickBooleanType
Definition: magick-type.h:173
unsigned int MagickStatusType
Definition: magick-type.h:129
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:1583
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
PointInfo origin
Definition: draw.h:384
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
char * metrics
Definition: draw.h:255
size_t face
Definition: draw.h:261
double y
Definition: geometry.h:124
MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
Definition: resource.c:1098
#define magick_unused(x)
RectangleInfo page
Definition: image.h:212
MagickPrivate MagickBooleanType XRenderImage(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: xwindow.c:9976
size_t x_advance
Definition: annotate.c:118
char * family
Definition: draw.h:255
size_t MagickSizeType
Definition: magick-type.h:138
#define MagickPathExtent
double ry
Definition: geometry.h:96
char * glyphs
Definition: type.h:71
MagickExport MagickBooleanType DrawImage(Image *image, const DrawInfo *draw_info, ExceptionInfo *exception)
Definition: draw.c:4470
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:193
PointInfo pixels_per_em
Definition: draw.h:369
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:429
static MagickBooleanType RenderX11(Image *, const DrawInfo *, const PointInfo *, TypeMetric *, ExceptionInfo *)
Definition: annotate.c:2206
double sx
Definition: geometry.h:96
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:1660
MagickExport MagickBooleanType IsPathAccessible(const char *path)
Definition: utility.c:1477
char * density
Definition: draw.h:279
size_t signature
Definition: image.h:354
#define QuantumScale
Definition: magick-type.h:123
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:322
ssize_t x
Definition: geometry.h:135
StretchType stretch
Definition: draw.h:267
MagickExport DrawInfo * CloneDrawInfo(const ImageInfo *image_info, const DrawInfo *draw_info)
Definition: draw.c:269
size_t height
Definition: geometry.h:131
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:2603
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:36
static size_t GetPixelChannels(const Image *magick_restrict image)
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1403
static ssize_t CastDoubleToLong(const double value)
Definition: image-private.h:53
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:96
double underline_thickness
Definition: draw.h:372
MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image, const DrawInfo *draw_info, TypeMetric *metrics, ExceptionInfo *exception)
Definition: annotate.c:719
char * density
Definition: image.h:413
SegmentInfo bounds
Definition: draw.h:381
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1239
size_t signature
Definition: draw.h:323
MagickExport MagickBooleanType GetTypeMetrics(Image *image, const DrawInfo *draw_info, TypeMetric *metrics, ExceptionInfo *exception)
Definition: annotate.c:860
char * geometry
Definition: draw.h:204
unsigned short Quantum
Definition: magick-type.h:90
double xi
Definition: geometry.h:107
MagickExport RectangleInfo GetImageBoundingBox(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:389
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1402
MagickExport DrawInfo * DestroyDrawInfo(DrawInfo *draw_info)
Definition: draw.c:966
MagickExport char * DestroyString(char *string)
Definition: string.c:776
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:2217
AlignType align
Definition: draw.h:282
double underline_position
Definition: draw.h:372
static char * EscapeParenthesis(const char *source)
Definition: annotate.c:1899
MagickBooleanType text_antialias
Definition: draw.h:230
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:855
size_t x_offset
Definition: annotate.c:118
MagickExport char * GetPolicyValue(const char *name)
Definition: policy.c:530
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:1691
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:193
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:250
MagickExport char ** StringToStrings(const char *text, size_t *count)
Definition: string.c:2283
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:1100
ssize_t y
Definition: geometry.h:135
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:1975
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:1168
MagickExport char * ConstantString(const char *source)
Definition: string.c:666
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:91
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:839
static void CompositePixelOver(const Image *image, const PixelInfo *p, const double alpha, const Quantum *q, const double beta, Quantum *composite)
MagickBooleanType debug
Definition: image.h:334
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:2034