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