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