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