MagickCore  7.0.7
Convert, Edit, Or Compose Bitmap Images
montage.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M OOO N N TTTTT AAA GGGG EEEEE %
7 % MM MM O O NN N T A A G E %
8 % M M M O O N N N T AAAAA G GG EEE %
9 % M M O O N NN T A A G G E %
10 % M M OOO N N T A A GGG EEEEE %
11 % %
12 % %
13 % MagickCore Methods to Create Image Thumbnails %
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 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/client.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/composite.h"
48 #include "MagickCore/constitute.h"
49 #include "MagickCore/decorate.h"
50 #include "MagickCore/draw.h"
51 #include "MagickCore/effect.h"
52 #include "MagickCore/enhance.h"
53 #include "MagickCore/exception.h"
55 #include "MagickCore/fx.h"
56 #include "MagickCore/gem.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/memory_.h"
63 #include "MagickCore/monitor.h"
65 #include "MagickCore/montage.h"
66 #include "MagickCore/option.h"
67 #include "MagickCore/pixel.h"
68 #include "MagickCore/quantize.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/resize.h"
71 #include "MagickCore/resource_.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/utility.h"
75 #include "MagickCore/version.h"
76 
77 /*
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % %
80 % %
81 % %
82 % C l o n e M o n t a g e I n f o %
83 % %
84 % %
85 % %
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 %
88 % CloneMontageInfo() makes a copy of the given montage info structure. If
89 % NULL is specified, a new image info structure is created initialized to
90 % default values.
91 %
92 % The format of the CloneMontageInfo method is:
93 %
94 % MontageInfo *CloneMontageInfo(const ImageInfo *image_info,
95 % const MontageInfo *montage_info)
96 %
97 % A description of each parameter follows:
98 %
99 % o image_info: the image info.
100 %
101 % o montage_info: the montage info.
102 %
103 */
105  const MontageInfo *montage_info)
106 {
108  *clone_info;
109 
110  clone_info=(MontageInfo *) AcquireCriticalMemory(sizeof(*clone_info));
111  GetMontageInfo(image_info,clone_info);
112  if (montage_info == (MontageInfo *) NULL)
113  return(clone_info);
114  if (montage_info->geometry != (char *) NULL)
115  clone_info->geometry=AcquireString(montage_info->geometry);
116  if (montage_info->tile != (char *) NULL)
117  clone_info->tile=AcquireString(montage_info->tile);
118  if (montage_info->title != (char *) NULL)
119  clone_info->title=AcquireString(montage_info->title);
120  if (montage_info->frame != (char *) NULL)
121  clone_info->frame=AcquireString(montage_info->frame);
122  if (montage_info->texture != (char *) NULL)
123  clone_info->texture=AcquireString(montage_info->texture);
124  if (montage_info->font != (char *) NULL)
125  clone_info->font=AcquireString(montage_info->font);
126  clone_info->pointsize=montage_info->pointsize;
127  clone_info->border_width=montage_info->border_width;
128  clone_info->shadow=montage_info->shadow;
129  clone_info->fill=montage_info->fill;
130  clone_info->stroke=montage_info->stroke;
131  clone_info->matte_color=montage_info->matte_color;
132  clone_info->background_color=montage_info->background_color;
133  clone_info->border_color=montage_info->border_color;
134  clone_info->gravity=montage_info->gravity;
135  (void) CopyMagickString(clone_info->filename,montage_info->filename,
137  clone_info->debug=IsEventLogging();
138  return(clone_info);
139 }
140 
141 /*
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 % %
144 % %
145 % %
146 % D e s t r o y M o n t a g e I n f o %
147 % %
148 % %
149 % %
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151 %
152 % DestroyMontageInfo() deallocates memory associated with montage_info.
153 %
154 % The format of the DestroyMontageInfo method is:
155 %
156 % MontageInfo *DestroyMontageInfo(MontageInfo *montage_info)
157 %
158 % A description of each parameter follows:
159 %
160 % o montage_info: Specifies a pointer to an MontageInfo structure.
161 %
162 %
163 */
165 {
166  if (montage_info->debug != MagickFalse)
167  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
168  assert(montage_info != (MontageInfo *) NULL);
169  assert(montage_info->signature == MagickCoreSignature);
170  if (montage_info->geometry != (char *) NULL)
171  montage_info->geometry=(char *)
172  RelinquishMagickMemory(montage_info->geometry);
173  if (montage_info->tile != (char *) NULL)
174  montage_info->tile=DestroyString(montage_info->tile);
175  if (montage_info->title != (char *) NULL)
176  montage_info->title=DestroyString(montage_info->title);
177  if (montage_info->frame != (char *) NULL)
178  montage_info->frame=DestroyString(montage_info->frame);
179  if (montage_info->texture != (char *) NULL)
180  montage_info->texture=(char *) RelinquishMagickMemory(
181  montage_info->texture);
182  if (montage_info->font != (char *) NULL)
183  montage_info->font=DestroyString(montage_info->font);
184  montage_info->signature=(~MagickCoreSignature);
185  montage_info=(MontageInfo *) RelinquishMagickMemory(montage_info);
186  return(montage_info);
187 }
188 
189 /*
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 % %
192 % %
193 % %
194 % G e t M o n t a g e I n f o %
195 % %
196 % %
197 % %
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 %
200 % GetMontageInfo() initializes montage_info to default values.
201 %
202 % The format of the GetMontageInfo method is:
203 %
204 % void GetMontageInfo(const ImageInfo *image_info,
205 % MontageInfo *montage_info)
206 %
207 % A description of each parameter follows:
208 %
209 % o image_info: a structure of type ImageInfo.
210 %
211 % o montage_info: Specifies a pointer to a MontageInfo structure.
212 %
213 */
214 MagickExport void GetMontageInfo(const ImageInfo *image_info,
215  MontageInfo *montage_info)
216 {
217  assert(image_info != (const ImageInfo *) NULL);
218  assert(image_info->signature == MagickCoreSignature);
219  if (image_info->debug != MagickFalse)
221  image_info->filename);
222  assert(montage_info != (MontageInfo *) NULL);
223  (void) ResetMagickMemory(montage_info,0,sizeof(*montage_info));
224  (void) CopyMagickString(montage_info->filename,image_info->filename,
227  if (image_info->font != (char *) NULL)
228  montage_info->font=AcquireString(image_info->font);
229  montage_info->gravity=CenterGravity;
230  montage_info->pointsize=image_info->pointsize;
231  montage_info->fill.alpha=OpaqueAlpha;
232  montage_info->stroke.alpha=(Quantum) TransparentAlpha;
233  montage_info->matte_color=image_info->matte_color;
234  montage_info->background_color=image_info->background_color;
235  montage_info->border_color=image_info->border_color;
236  montage_info->debug=IsEventLogging();
237  montage_info->signature=MagickCoreSignature;
238 }
239 
240 /*
241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % %
243 % %
244 % %
245 % M o n t a g e I m a g e L i s t %
246 % %
247 % %
248 % %
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 %
251 % MontageImageList() is a layout manager that lets you tile one or more
252 % thumbnails across an image canvas.
253 %
254 % The format of the MontageImageList method is:
255 %
256 % Image *MontageImageList(const ImageInfo *image_info,
257 % const MontageInfo *montage_info,Image *images,
258 % ExceptionInfo *exception)
259 %
260 % A description of each parameter follows:
261 %
262 % o image_info: the image info.
263 %
264 % o montage_info: Specifies a pointer to a MontageInfo structure.
265 %
266 % o images: Specifies a pointer to an array of Image structures.
267 %
268 % o exception: return any errors or warnings in this structure.
269 %
270 */
271 
272 static void GetMontageGeometry(char *geometry,const size_t number_images,
273  ssize_t *x_offset,ssize_t *y_offset,size_t *tiles_per_column,
274  size_t *tiles_per_row)
275 {
276  *tiles_per_column=0;
277  *tiles_per_row=0;
278  (void) GetGeometry(geometry,x_offset,y_offset,tiles_per_row,tiles_per_column);
279  if ((*tiles_per_column == 0) && (*tiles_per_row == 0))
280  *tiles_per_column=(size_t) sqrt((double) number_images);
281  if ((*tiles_per_column == 0) && (*tiles_per_row != 0))
282  *tiles_per_column=(size_t) ceil((double) number_images/(*tiles_per_row));
283  if ((*tiles_per_row == 0) && (*tiles_per_column != 0))
284  *tiles_per_row=(size_t) ceil((double) number_images/(*tiles_per_column));
285 }
286 
287 #if defined(__cplusplus) || defined(c_plusplus)
288 extern "C" {
289 #endif
290 
291 static int SceneCompare(const void *x,const void *y)
292 {
293  Image
294  **image_1,
295  **image_2;
296 
297  image_1=(Image **) x;
298  image_2=(Image **) y;
299  return((int) ((*image_1)->scene-(*image_2)->scene));
300 }
301 
302 #if defined(__cplusplus) || defined(c_plusplus)
303 }
304 #endif
305 
307  const MontageInfo *montage_info,ExceptionInfo *exception)
308 {
309  Image
310  *montage_image;
311 
312  ImageInfo
313  *image_info;
314 
315  image_info=AcquireImageInfo();
316  montage_image=MontageImageList(image_info,montage_info,images,exception);
317  image_info=DestroyImageInfo(image_info);
318  return(montage_image);
319 }
320 
322  const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception)
323 {
324 #define MontageImageTag "Montage/Image"
325 #define TileImageTag "Tile/Image"
326 
327  char
328  tile_geometry[MagickPathExtent],
329  *title;
330 
331  const char
332  *value;
333 
334  DrawInfo
335  *draw_info;
336 
337  FrameInfo
338  frame_info;
339 
340  Image
341  *image,
342  **image_list,
343  **master_list,
344  *montage,
345  *texture,
346  *tile_image,
347  *thumbnail;
348 
349  ImageInfo
350  *clone_info;
351 
353  concatenate,
354  proceed,
355  status;
356 
358  tiles;
359 
361  progress_monitor;
362 
364  flags;
365 
366  register ssize_t
367  i;
368 
370  bounds,
371  geometry,
372  extract_info;
373 
374  size_t
375  bevel_width,
376  border_width,
377  extent,
378  height,
379  images_per_page,
380  max_height,
381  number_images,
382  number_lines,
383  sans,
384  tiles_per_column,
385  tiles_per_page,
386  tiles_per_row,
387  title_offset,
388  total_tiles,
389  width;
390 
391  ssize_t
392  tile,
393  x,
394  x_offset,
395  y,
396  y_offset;
397 
398  TypeMetric
399  metrics;
400 
401  /*
402  Create image tiles.
403  */
404  assert(images != (Image *) NULL);
405  assert(images->signature == MagickCoreSignature);
406  if (images->debug != MagickFalse)
407  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
408  assert(montage_info != (MontageInfo *) NULL);
409  assert(montage_info->signature == MagickCoreSignature);
410  assert(exception != (ExceptionInfo *) NULL);
411  assert(exception->signature == MagickCoreSignature);
412  number_images=GetImageListLength(images);
413  master_list=ImageListToArray(images,exception);
414  image_list=master_list;
415  image=image_list[0];
416  if (master_list == (Image **) NULL)
417  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
418  thumbnail=NewImageList();
419  for (i=0; i < (ssize_t) number_images; i++)
420  {
421  image=CloneImage(image_list[i],0,0,MagickTrue,exception);
422  if (image == (Image *) NULL)
423  break;
424  (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
425  progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
426  image->client_data);
427  flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception);
428  thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
429  if (thumbnail == (Image *) NULL)
430  break;
431  image_list[i]=thumbnail;
432  (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
434  number_images);
435  if (proceed == MagickFalse)
436  break;
437  image=DestroyImage(image);
438  }
439  if (i < (ssize_t) number_images)
440  {
441  if (thumbnail == (Image *) NULL)
442  i--;
443  for (tile=0; (ssize_t) tile <= i; tile++)
444  if (image_list[tile] != (Image *) NULL)
445  image_list[tile]=DestroyImage(image_list[tile]);
446  master_list=(Image **) RelinquishMagickMemory(master_list);
447  return((Image *) NULL);
448  }
449  /*
450  Sort image list by increasing tile number.
451  */
452  for (i=0; i < (ssize_t) number_images; i++)
453  if (image_list[i]->scene == 0)
454  break;
455  if (i == (ssize_t) number_images)
456  qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
457  SceneCompare);
458  /*
459  Determine tiles per row and column.
460  */
461  tiles_per_column=(size_t) sqrt((double) number_images);
462  tiles_per_row=(size_t) ceil((double) number_images/tiles_per_column);
463  x_offset=0;
464  y_offset=0;
465  if (montage_info->tile != (char *) NULL)
466  GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
467  &tiles_per_column,&tiles_per_row);
468  /*
469  Determine tile sizes.
470  */
471  concatenate=MagickFalse;
472  SetGeometry(image_list[0],&extract_info);
473  extract_info.x=(ssize_t) montage_info->border_width;
474  extract_info.y=(ssize_t) montage_info->border_width;
475  if (montage_info->geometry != (char *) NULL)
476  {
477  /*
478  Initialize tile geometry.
479  */
480  flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y,
481  &extract_info.width,&extract_info.height);
482  concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ?
484  }
485  border_width=montage_info->border_width;
486  bevel_width=0;
487  (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info));
488  if (montage_info->frame != (char *) NULL)
489  {
490  char
491  absolute_geometry[MagickPathExtent];
492 
493  frame_info.width=extract_info.width;
494  frame_info.height=extract_info.height;
495  (void) FormatLocaleString(absolute_geometry,MagickPathExtent,"%s!",
496  montage_info->frame);
497  flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel,
498  &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
499  if ((flags & HeightValue) == 0)
500  frame_info.height=frame_info.width;
501  if ((flags & XiValue) == 0)
502  frame_info.outer_bevel=(ssize_t) frame_info.width/2;
503  if ((flags & PsiValue) == 0)
504  frame_info.inner_bevel=frame_info.outer_bevel;
505  frame_info.x=(ssize_t) frame_info.width;
506  frame_info.y=(ssize_t) frame_info.height;
507  bevel_width=(size_t) MagickMax(frame_info.inner_bevel,
508  frame_info.outer_bevel);
509  border_width=(size_t) MagickMax((ssize_t) frame_info.width,
510  (ssize_t) frame_info.height);
511  }
512  for (i=0; i < (ssize_t) number_images; i++)
513  {
514  if (image_list[i]->columns > extract_info.width)
515  extract_info.width=image_list[i]->columns;
516  if (image_list[i]->rows > extract_info.height)
517  extract_info.height=image_list[i]->rows;
518  }
519  /*
520  Initialize draw attributes.
521  */
522  clone_info=CloneImageInfo(image_info);
523  clone_info->background_color=montage_info->background_color;
524  clone_info->border_color=montage_info->border_color;
525  draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL);
526  if (montage_info->font != (char *) NULL)
527  (void) CloneString(&draw_info->font,montage_info->font);
528  if (montage_info->pointsize != 0.0)
529  draw_info->pointsize=montage_info->pointsize;
530  draw_info->gravity=CenterGravity;
531  draw_info->stroke=montage_info->stroke;
532  draw_info->fill=montage_info->fill;
533  draw_info->text=AcquireString("");
534  (void) GetTypeMetrics(image_list[0],draw_info,&metrics,exception);
535  texture=NewImageList();
536  if (montage_info->texture != (char *) NULL)
537  {
538  (void) CopyMagickString(clone_info->filename,montage_info->texture,
540  texture=ReadImage(clone_info,exception);
541  }
542  /*
543  Determine the number of lines in an next label.
544  */
545  title=InterpretImageProperties(clone_info,image_list[0],montage_info->title,
546  exception);
547  title_offset=0;
548  if (montage_info->title != (char *) NULL)
549  title_offset=(size_t) (2*(metrics.ascent-metrics.descent)*
550  MultilineCensus(title)+2*extract_info.y);
551  number_lines=0;
552  for (i=0; i < (ssize_t) number_images; i++)
553  {
554  value=GetImageProperty(image_list[i],"label",exception);
555  if (value == (const char *) NULL)
556  continue;
557  if (MultilineCensus(value) > number_lines)
558  number_lines=MultilineCensus(value);
559  }
560  /*
561  Allocate next structure.
562  */
563  tile_image=AcquireImage((ImageInfo *) NULL,exception);
564  montage=AcquireImage(clone_info,exception);
565  montage->background_color=montage_info->background_color;
566  montage->scene=0;
567  images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
568  tiles=0;
569  total_tiles=(size_t) number_images;
570  for (i=0; i < (ssize_t) images_per_page; i++)
571  {
572  /*
573  Determine bounding box.
574  */
575  tiles_per_page=tiles_per_row*tiles_per_column;
576  x_offset=0;
577  y_offset=0;
578  if (montage_info->tile != (char *) NULL)
579  GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
580  &sans,&sans);
581  tiles_per_page=tiles_per_row*tiles_per_column;
582  y_offset+=(ssize_t) title_offset;
583  max_height=0;
584  bounds.width=0;
585  bounds.height=0;
586  width=0;
587  for (tile=0; tile < (ssize_t) tiles_per_page; tile++)
588  {
589  if (tile < (ssize_t) number_images)
590  {
591  width=concatenate != MagickFalse ? image_list[tile]->columns :
592  extract_info.width;
593  if (image_list[tile]->rows > max_height)
594  max_height=image_list[tile]->rows;
595  }
596  x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
597  if (x_offset > (ssize_t) bounds.width)
598  bounds.width=(size_t) x_offset;
599  if (((tile+1) == (ssize_t) tiles_per_page) ||
600  (((tile+1) % tiles_per_row) == 0))
601  {
602  x_offset=0;
603  if (montage_info->tile != (char *) NULL)
604  GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y,
605  &sans,&sans);
606  height=concatenate != MagickFalse ? max_height : extract_info.height;
607  y_offset+=(ssize_t) (height+(extract_info.y+(ssize_t) border_width)*2+
608  (metrics.ascent-metrics.descent+4)*number_lines+
609  (montage_info->shadow != MagickFalse ? 4 : 0));
610  if (y_offset > (ssize_t) bounds.height)
611  bounds.height=(size_t) y_offset;
612  max_height=0;
613  }
614  }
615  if (montage_info->shadow != MagickFalse)
616  bounds.width+=4;
617  /*
618  Initialize montage image.
619  */
620  (void) CopyMagickString(montage->filename,montage_info->filename,
622  montage->columns=(size_t) MagickMax((ssize_t) bounds.width,1);
623  montage->rows=(size_t) MagickMax((ssize_t) bounds.height,1);
624  (void) SetImageBackgroundColor(montage,exception);
625  /*
626  Set montage geometry.
627  */
628  montage->montage=AcquireString((char *) NULL);
629  tile=0;
630  extent=1;
631  while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
632  {
633  extent+=strlen(image_list[tile]->filename)+1;
634  tile++;
635  }
636  montage->directory=(char *) AcquireQuantumMemory(extent,
637  sizeof(*montage->directory));
638  if ((montage->montage == (char *) NULL) ||
639  (montage->directory == (char *) NULL))
640  {
641  if (montage->montage != (char *) NULL)
642  montage->montage=(char *) RelinquishMagickMemory(montage->montage);
643  if (montage->directory != (char *) NULL)
644  montage->directory=(char *) RelinquishMagickMemory(
645  montage->directory);
646  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
647  }
648  x_offset=0;
649  y_offset=0;
650  if (montage_info->tile != (char *) NULL)
651  GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
652  &sans,&sans);
653  y_offset+=(ssize_t) title_offset;
655  "%.20gx%.20g%+.20g%+.20g",(double) (extract_info.width+
656  (extract_info.x+border_width)*2),(double) (extract_info.height+
657  (extract_info.y+border_width)*2+(double) ((metrics.ascent-
658  metrics.descent+4)*number_lines+(montage_info->shadow != MagickFalse ? 4 :
659  0))),(double) x_offset,(double) y_offset);
660  *montage->directory='\0';
661  tile=0;
662  while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
663  {
664  (void) ConcatenateMagickString(montage->directory,
665  image_list[tile]->filename,extent);
666  (void) ConcatenateMagickString(montage->directory,"\n",extent);
667  tile++;
668  }
669  progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor)
670  NULL,montage->client_data);
671  if (texture != (Image *) NULL)
672  (void) TextureImage(montage,texture,exception);
673  if (montage_info->title != (char *) NULL)
674  {
675  DrawInfo
676  *draw_clone_info;
677 
678  TypeMetric
679  tile_metrics;
680 
681  /*
682  Annotate composite image with title.
683  */
684  draw_clone_info=CloneDrawInfo(image_info,draw_info);
685  draw_clone_info->gravity=CenterGravity;
686  draw_clone_info->pointsize*=2.0;
687  (void) GetTypeMetrics(image_list[0],draw_clone_info,&tile_metrics,
688  exception);
689  (void) FormatLocaleString(tile_geometry,MagickPathExtent,
690  "%.20gx%.20g%+.20g%+.20g",(double) montage->columns,(double)
691  (tile_metrics.ascent-tile_metrics.descent),0.0,
692  (double) extract_info.y+4);
693  (void) CloneString(&draw_clone_info->geometry,tile_geometry);
694  (void) CloneString(&draw_clone_info->text,title);
695  (void) AnnotateImage(montage,draw_clone_info,exception);
696  draw_clone_info=DestroyDrawInfo(draw_clone_info);
697  }
698  (void) SetImageProgressMonitor(montage,progress_monitor,
699  montage->client_data);
700  /*
701  Copy tile to the composite.
702  */
703  x_offset=0;
704  y_offset=0;
705  if (montage_info->tile != (char *) NULL)
706  GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
707  &sans,&sans);
708  x_offset+=extract_info.x;
709  y_offset+=(ssize_t) title_offset+extract_info.y;
710  max_height=0;
711  status=MagickTrue;
712  for (tile=0; tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images); tile++)
713  {
714  /*
715  Copy this tile to the composite.
716  */
717  image=CloneImage(image_list[tile],0,0,MagickTrue,exception);
718  if (image == (Image *) NULL)
719  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
720  progress_monitor=SetImageProgressMonitor(image,
721  (MagickProgressMonitor) NULL,image->client_data);
722  width=concatenate != MagickFalse ? image->columns : extract_info.width;
723  if (image->rows > max_height)
724  max_height=image->rows;
725  height=concatenate != MagickFalse ? max_height : extract_info.height;
726  if (border_width != 0)
727  {
728  Image
729  *border_image;
730 
732  border_info;
733 
734  /*
735  Put a border around the image.
736  */
737  border_info.width=border_width;
738  border_info.height=border_width;
739  if (montage_info->frame != (char *) NULL)
740  {
741  border_info.width=(width-image->columns+1)/2;
742  border_info.height=(height-image->rows+1)/2;
743  }
744  border_image=BorderImage(image,&border_info,image->compose,exception);
745  if (border_image != (Image *) NULL)
746  {
747  image=DestroyImage(image);
748  image=border_image;
749  }
750  if ((montage_info->frame != (char *) NULL) &&
751  (image->compose == DstOutCompositeOp))
752  {
753  (void) SetPixelChannelMask(image,AlphaChannel);
754  (void) NegateImage(image,MagickFalse,exception);
755  (void) SetPixelChannelMask(image,DefaultChannels);
756  }
757  }
758  /*
759  Gravitate as specified by the tile gravity.
760  */
761  tile_image->columns=width;
762  tile_image->rows=height;
763  tile_image->gravity=montage_info->gravity;
764  if (image->gravity != UndefinedGravity)
765  tile_image->gravity=image->gravity;
766  (void) FormatLocaleString(tile_geometry,MagickPathExtent,"%.20gx%.20g+0+0",
767  (double) image->columns,(double) image->rows);
768  flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception);
769  x=(ssize_t) (geometry.x+border_width);
770  y=(ssize_t) (geometry.y+border_width);
771  if ((montage_info->frame != (char *) NULL) && (bevel_width != 0))
772  {
773  FrameInfo
774  frame_clone;
775 
776  Image
777  *frame_image;
778 
779  /*
780  Put an ornamental border around this tile.
781  */
782  frame_clone=frame_info;
783  frame_clone.width=width+2*frame_info.width;
784  frame_clone.height=height+2*frame_info.height;
785  value=GetImageProperty(image,"label",exception);
786  if (value != (const char *) NULL)
787  frame_clone.height+=(size_t) ((metrics.ascent-metrics.descent+4)*
788  MultilineCensus(value));
789  frame_image=FrameImage(image,&frame_clone,image->compose,exception);
790  if (frame_image != (Image *) NULL)
791  {
792  image=DestroyImage(image);
793  image=frame_image;
794  }
795  x=0;
796  y=0;
797  }
798  if (LocaleCompare(image->magick,"NULL") != 0)
799  {
800  /*
801  Composite background with tile.
802  */
803  if (montage_info->shadow != MagickFalse)
804  {
805  Image
806  *shadow_image;
807 
808  /*
809  Shadow image.
810  */
811  (void) QueryColorCompliance("#0000",AllCompliance,
812  &image->background_color,exception);
813  shadow_image=ShadowImage(image,80.0,2.0,5,5,exception);
814  if (shadow_image != (Image *) NULL)
815  {
816  (void) CompositeImage(shadow_image,image,OverCompositeOp,
817  MagickTrue,0,0,exception);
818  image=DestroyImage(image);
819  image=shadow_image;
820  }
821  }
822  (void) CompositeImage(montage,image,image->compose,MagickTrue,
823  x_offset+x,y_offset+y,exception);
824  value=GetImageProperty(image,"label",exception);
825  if (value != (const char *) NULL)
826  {
827  /*
828  Annotate composite tile with label.
829  */
830  (void) FormatLocaleString(tile_geometry,MagickPathExtent,
831  "%.20gx%.20g%+.20g%+.20g",(double) ((montage_info->frame ?
832  image->columns : width)-2*border_width),(double)
833  (metrics.ascent-metrics.descent+4)*MultilineCensus(value),
834  (double) (x_offset+border_width),(double)
835  ((montage_info->frame ? y_offset+height+border_width+4 :
836  y_offset+extract_info.height+border_width+
837  (montage_info->shadow != MagickFalse ? 4 : 0))+bevel_width));
838  (void) CloneString(&draw_info->geometry,tile_geometry);
839  (void) CloneString(&draw_info->text,value);
840  (void) AnnotateImage(montage,draw_info,exception);
841  }
842  }
843  x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
844  if (((tile+1) == (ssize_t) tiles_per_page) ||
845  (((tile+1) % tiles_per_row) == 0))
846  {
847  x_offset=extract_info.x;
848  y_offset+=(ssize_t) (height+(extract_info.y+border_width)*2+
849  (metrics.ascent-metrics.descent+4)*number_lines+
850  (montage_info->shadow != MagickFalse ? 4 : 0));
851  max_height=0;
852  }
853  if (images->progress_monitor != (MagickProgressMonitor) NULL)
854  {
855  proceed=SetImageProgress(image,MontageImageTag,tiles,total_tiles);
856  if (proceed == MagickFalse)
857  status=MagickFalse;
858  }
859  image_list[tile]=DestroyImage(image_list[tile]);
860  image=DestroyImage(image);
861  tiles++;
862  }
863  (void) status;
864  if ((i+1) < (ssize_t) images_per_page)
865  {
866  /*
867  Allocate next image structure.
868  */
869  AcquireNextImage(clone_info,montage,exception);
870  if (GetNextImageInList(montage) == (Image *) NULL)
871  {
872  montage=DestroyImageList(montage);
873  return((Image *) NULL);
874  }
875  montage=GetNextImageInList(montage);
876  montage->background_color=montage_info->background_color;
877  image_list+=tiles_per_page;
878  number_images-=tiles_per_page;
879  }
880  }
881  tile_image=DestroyImage(tile_image);
882  if (texture != (Image *) NULL)
883  texture=DestroyImage(texture);
884  title=DestroyString(title);
885  master_list=(Image **) RelinquishMagickMemory(master_list);
886  draw_info=DestroyDrawInfo(draw_info);
887  clone_info=DestroyImageInfo(clone_info);
888  return(GetFirstImageInList(montage));
889 }
size_t rows
Definition: image.h:172
MagickExport MagickBooleanType TextureImage(Image *image, const Image *texture, ExceptionInfo *exception)
Definition: composite.c:2381
PixelInfo fill
Definition: draw.h:213
MagickExport MagickBooleanType NegateImage(Image *image, const MagickBooleanType grayscale, ExceptionInfo *exception)
Definition: enhance.c:3400
#define MontageImageTag
#define TransparentAlpha
Definition: image.h:26
size_t signature
Definition: image.h:479
static MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:341
MagickExport Image * FrameImage(const Image *image, const FrameInfo *frame_info, const CompositeOperator compose, ExceptionInfo *exception)
Definition: decorate.c:169
MagickExport Image * MontageImages(const Image *images, const MontageInfo *montage_info, ExceptionInfo *exception)
Definition: montage.c:306
MagickProgressMonitor progress_monitor
Definition: image.h:303
PixelInfo fill
Definition: montage.h:53
GravityType gravity
Definition: draw.h:284
#define TileImageTag
double pointsize
Definition: image.h:411
char * geometry
Definition: montage.h:36
char * tile
Definition: montage.h:36
PixelInfo stroke
Definition: draw.h:213
size_t signature
Definition: exception.h:123
MagickExport const char DefaultTileGeometry[]
Definition: image.c:112
MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry, RectangleInfo *region_info)
Definition: geometry.c:686
PixelInfo stroke
Definition: montage.h:53
MagickExport size_t ConcatenateMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:410
MagickBooleanType debug
Definition: image.h:476
char * font
Definition: image.h:404
#define OpaqueAlpha
Definition: image.h:25
MagickExport MagickStatusType ParseMetaGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:1286
ssize_t outer_bevel
Definition: decorate.h:34
double pointsize
Definition: draw.h:275
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:473
MagickExport void GetMontageInfo(const ImageInfo *image_info, MontageInfo *montage_info)
Definition: montage.c:214
char magick[MagickPathExtent]
Definition: image.h:319
double pointsize
Definition: montage.h:44
size_t border_width
Definition: montage.h:47
MagickRealType alpha
Definition: pixel.h:188
char * montage
Definition: image.h:201
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:539
size_t width
Definition: geometry.h:129
PixelInfo background_color
Definition: montage.h:53
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:127
MagickExport Image * ThumbnailImage(const Image *image, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: resize.c:3669
Definition: image.h:151
GravityType gravity
Definition: montage.h:60
char * frame
Definition: montage.h:36
static void GetMontageGeometry(char *geometry, const size_t number_images, ssize_t *x_offset, ssize_t *y_offset, size_t *tiles_per_column, size_t *tiles_per_row)
Definition: montage.c:272
#define MagickCoreSignature
char * font
Definition: montage.h:36
MagickExport Image * GetFirstImageInList(const Image *images)
Definition: list.c:541
MagickExport size_t MultilineCensus(const char *label)
Definition: utility.c:1769
MagickExport Image * MontageImageList(const ImageInfo *image_info, const MontageInfo *montage_info, const Image *images, ExceptionInfo *exception)
Definition: montage.c:321
MagickBooleanType
Definition: magick-type.h:156
PixelInfo matte_color
Definition: image.h:485
MagickExport Image * NewImageList(void)
Definition: list.c:916
size_t scene
Definition: image.h:240
unsigned int MagickStatusType
Definition: magick-type.h:119
MagickExport char * AcquireString(const char *source)
Definition: string.c:124
MagickExport MagickBooleanType AnnotateImage(Image *image, const DrawInfo *draw_info, ExceptionInfo *exception)
Definition: annotate.c:272
PixelInfo matte_color
Definition: montage.h:72
MagickExport void * ResetMagickMemory(void *memory, int byte, const size_t size)
Definition: memory.c:1164
char filename[MagickPathExtent]
Definition: montage.h:63
double descent
Definition: draw.h:354
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:529
char filename[MagickPathExtent]
Definition: image.h:471
MagickBooleanType debug
Definition: montage.h:66
GravityType gravity
Definition: image.h:231
RectangleInfo page
Definition: image.h:212
#define MagickPathExtent
ssize_t y
Definition: decorate.h:34
MagickExport MagickBooleanType IsEventLogging(void)
Definition: log.c:716
MagickExport MagickBooleanType static void * AcquireCriticalMemory(const size_t size)
MagickExport void AcquireNextImage(const ImageInfo *image_info, Image *image, ExceptionInfo *exception)
Definition: image.c:382
MagickExport ChannelType SetPixelChannelMask(Image *image, const ChannelType channel_mask)
Definition: pixel.c:6259
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:358
size_t signature
Definition: montage.h:69
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 SetImageBackgroundColor(Image *image, ExceptionInfo *exception)
Definition: image.c:2308
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
MagickExport Image * AcquireImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: image.c:154
ssize_t x
Definition: geometry.h:133
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport DrawInfo * CloneDrawInfo(const ImageInfo *image_info, const DrawInfo *draw_info)
Definition: draw.c:242
size_t height
Definition: geometry.h:129
MagickExport MontageInfo * DestroyMontageInfo(MontageInfo *montage_info)
Definition: montage.c:164
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2215
MagickExport MagickProgressMonitor SetImageProgressMonitor(Image *image, const MagickProgressMonitor progress_monitor, void *client_data)
Definition: monitor.c:85
MagickExport size_t CopyMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:742
MagickExport Image * DestroyImageList(Image *images)
Definition: list.c:442
ssize_t x
Definition: decorate.h:34
static int SceneCompare(const void *x, const void *y)
Definition: montage.c:291
#define MagickMax(x, y)
Definition: image-private.h:26
PixelInfo border_color
Definition: montage.h:53
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1409
PixelInfo border_color
Definition: image.h:415
char filename[MagickPathExtent]
Definition: image.h:319
char * texture
Definition: montage.h:36
#define GetMagickModule()
Definition: log.h:28
MagickExport Image * ShadowImage(const Image *image, const double alpha, const double sigma, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: fx.c:4323
#define ThrowImageException(severity, tag)
MagickExport Image ** ImageListToArray(const Image *images, ExceptionInfo *exception)
Definition: list.c:825
MagickExport char * InterpretImageProperties(ImageInfo *image_info, Image *image, const char *embed_text, ExceptionInfo *exception)
Definition: property.c:3274
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1253
MagickExport MagickBooleanType GetTypeMetrics(Image *image, const DrawInfo *draw_info, TypeMetric *metrics, ExceptionInfo *exception)
Definition: annotate.c:881
char * geometry
Definition: draw.h:203
MagickExport MagickStatusType GetGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:96
ssize_t inner_bevel
Definition: decorate.h:34
unsigned short Quantum
Definition: magick-type.h:82
MagickExport Image * BorderImage(const Image *image, const RectangleInfo *border_info, const CompositeOperator compose, ExceptionInfo *exception)
Definition: decorate.c:103
MagickExport DrawInfo * DestroyDrawInfo(DrawInfo *draw_info)
Definition: draw.c:822
MagickExport MagickStatusType ParseGravityGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1180
MagickExport Image * GetNextImageInList(const Image *images)
Definition: list.c:752
MagickExport char * DestroyString(char *string)
Definition: string.c:810
size_t height
Definition: decorate.h:30
MagickExport const char * GetImageProperty(const Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:2185
MagickExport ImageInfo * CloneImageInfo(const ImageInfo *image_info)
Definition: image.c:942
char * directory
Definition: image.h:201
size_t width
Definition: decorate.h:30
#define MagickMin(x, y)
Definition: image-private.h:27
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1571
char * text
Definition: draw.h:254
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1038
char * title
Definition: montage.h:36
MagickBooleanType shadow
Definition: montage.h:50
double ascent
Definition: draw.h:354
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:270
CompositeOperator compose
Definition: image.h:234
#define MagickExport
ssize_t y
Definition: geometry.h:133
PixelInfo background_color
Definition: image.h:179
MagickExport size_t GetImageListLength(const Image *images)
Definition: list.c:680
char * font
Definition: draw.h:254
MagickExport MontageInfo * CloneMontageInfo(const ImageInfo *image_info, const MontageInfo *montage_info)
Definition: montage.c:104
void * client_data
Definition: image.h:306
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1182
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:799
PixelInfo background_color
Definition: image.h:415
MagickExport MagickStatusType ParseRegionGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1532
MagickBooleanType debug
Definition: image.h:334