00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "magick/studio.h"
00044 #include "magick/annotate.h"
00045 #include "magick/client.h"
00046 #include "magick/color.h"
00047 #include "magick/composite.h"
00048 #include "magick/constitute.h"
00049 #include "magick/decorate.h"
00050 #include "magick/draw.h"
00051 #include "magick/effect.h"
00052 #include "magick/enhance.h"
00053 #include "magick/exception.h"
00054 #include "magick/exception-private.h"
00055 #include "magick/fx.h"
00056 #include "magick/gem.h"
00057 #include "magick/geometry.h"
00058 #include "magick/image.h"
00059 #include "magick/image-private.h"
00060 #include "magick/list.h"
00061 #include "magick/memory_.h"
00062 #include "magick/monitor.h"
00063 #include "magick/monitor-private.h"
00064 #include "magick/montage.h"
00065 #include "magick/option.h"
00066 #include "magick/quantize.h"
00067 #include "magick/property.h"
00068 #include "magick/resize.h"
00069 #include "magick/resource_.h"
00070 #include "magick/string_.h"
00071 #include "magick/utility.h"
00072 #include "magick/version.h"
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 MagickExport MontageInfo *CloneMontageInfo(const ImageInfo *image_info,
00102 const MontageInfo *montage_info)
00103 {
00104 MontageInfo
00105 *clone_info;
00106
00107 clone_info=(MontageInfo *) AcquireMagickMemory(sizeof(*clone_info));
00108 if (clone_info == (MontageInfo *) NULL)
00109 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00110 GetMontageInfo(image_info,clone_info);
00111 if (montage_info == (MontageInfo *) NULL)
00112 return(clone_info);
00113 if (montage_info->geometry != (char *) NULL)
00114 clone_info->geometry=AcquireString(montage_info->geometry);
00115 if (montage_info->tile != (char *) NULL)
00116 clone_info->tile=AcquireString(montage_info->tile);
00117 if (montage_info->title != (char *) NULL)
00118 clone_info->title=AcquireString(montage_info->title);
00119 if (montage_info->frame != (char *) NULL)
00120 clone_info->frame=AcquireString(montage_info->frame);
00121 if (montage_info->texture != (char *) NULL)
00122 clone_info->texture=AcquireString(montage_info->texture);
00123 if (montage_info->font != (char *) NULL)
00124 clone_info->font=AcquireString(montage_info->font);
00125 clone_info->pointsize=montage_info->pointsize;
00126 clone_info->border_width=montage_info->border_width;
00127 clone_info->shadow=montage_info->shadow;
00128 clone_info->fill=montage_info->fill;
00129 clone_info->stroke=montage_info->stroke;
00130 clone_info->background_color=montage_info->background_color;
00131 clone_info->border_color=montage_info->border_color;
00132 clone_info->matte_color=montage_info->matte_color;
00133 clone_info->gravity=montage_info->gravity;
00134 (void) CopyMagickString(clone_info->filename,montage_info->filename,
00135 MaxTextExtent);
00136 clone_info->debug=IsEventLogging();
00137 return(clone_info);
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 MagickExport MontageInfo *DestroyMontageInfo(MontageInfo *montage_info)
00164 {
00165 if (montage_info->debug != MagickFalse)
00166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00167 assert(montage_info != (MontageInfo *) NULL);
00168 assert(montage_info->signature == MagickSignature);
00169 if (montage_info->geometry != (char *) NULL)
00170 montage_info->geometry=(char *)
00171 RelinquishMagickMemory(montage_info->geometry);
00172 if (montage_info->tile != (char *) NULL)
00173 montage_info->tile=DestroyString(montage_info->tile);
00174 if (montage_info->title != (char *) NULL)
00175 montage_info->title=DestroyString(montage_info->title);
00176 if (montage_info->frame != (char *) NULL)
00177 montage_info->frame=DestroyString(montage_info->frame);
00178 if (montage_info->texture != (char *) NULL)
00179 montage_info->texture=(char *) RelinquishMagickMemory(
00180 montage_info->texture);
00181 if (montage_info->font != (char *) NULL)
00182 montage_info->font=DestroyString(montage_info->font);
00183 montage_info->signature=(~MagickSignature);
00184 montage_info=(MontageInfo *) RelinquishMagickMemory(montage_info);
00185 return(montage_info);
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 MagickExport void GetMontageInfo(const ImageInfo *image_info,
00215 MontageInfo *montage_info)
00216 {
00217 assert(image_info != (const ImageInfo *) NULL);
00218 assert(image_info->signature == MagickSignature);
00219 if (image_info->debug != MagickFalse)
00220 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00221 image_info->filename);
00222 assert(montage_info != (MontageInfo *) NULL);
00223 (void) ResetMagickMemory(montage_info,0,sizeof(*montage_info));
00224 (void) CopyMagickString(montage_info->filename,image_info->filename,
00225 MaxTextExtent);
00226 montage_info->geometry=AcquireString(DefaultTileGeometry);
00227 if (image_info->font != (char *) NULL)
00228 montage_info->font=AcquireString(image_info->font);
00229 montage_info->gravity=CenterGravity;
00230 montage_info->pointsize=image_info->pointsize;
00231 montage_info->fill.opacity=OpaqueOpacity;
00232 montage_info->stroke.opacity=(Quantum) TransparentOpacity;
00233 montage_info->background_color=image_info->background_color;
00234 montage_info->border_color=image_info->border_color;
00235 montage_info->matte_color=image_info->matte_color;
00236 montage_info->debug=IsEventLogging();
00237 montage_info->signature=MagickSignature;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 static void GetMontageGeometry(char *geometry,const unsigned long number_images,
00273 long *x_offset,long *y_offset,unsigned long *tiles_per_column,
00274 unsigned long *tiles_per_row)
00275 {
00276 *tiles_per_column=0;
00277 *tiles_per_row=0;
00278 (void) GetGeometry(geometry,x_offset,y_offset,tiles_per_row,tiles_per_column);
00279 if ((*tiles_per_column == 0) && (*tiles_per_row == 0))
00280 *tiles_per_column=(unsigned long) sqrt((double) number_images);
00281 if (*tiles_per_column == 0)
00282 *tiles_per_column=(unsigned long)
00283 ceil((double) number_images/(*tiles_per_row));
00284 if (*tiles_per_row == 0)
00285 *tiles_per_row=(unsigned long)
00286 ceil((double) number_images/(*tiles_per_column));
00287 }
00288
00289 static inline long MagickMax(const long x,const long y)
00290 {
00291 if (x > y)
00292 return(x);
00293 return(y);
00294 }
00295
00296 static inline long MagickMin(const long x,const long y)
00297 {
00298 if (x < y)
00299 return(x);
00300 return(y);
00301 }
00302
00303 #if defined(__cplusplus) || defined(c_plusplus)
00304 extern "C" {
00305 #endif
00306
00307 static int SceneCompare(const void *x,const void *y)
00308 {
00309 Image
00310 **image_1,
00311 **image_2;
00312
00313 image_1=(Image **) x;
00314 image_2=(Image **) y;
00315 return((int) ((*image_1)->scene-(*image_2)->scene));
00316 }
00317
00318 #if defined(__cplusplus) || defined(c_plusplus)
00319 }
00320 #endif
00321
00322 MagickExport Image *MontageImages(const Image *images,
00323 const MontageInfo *montage_info,ExceptionInfo *exception)
00324 {
00325 Image
00326 *montage_image;
00327
00328 ImageInfo
00329 *image_info;
00330
00331 image_info=AcquireImageInfo();
00332 montage_image=MontageImageList(image_info,montage_info,images,exception);
00333 image_info=DestroyImageInfo(image_info);
00334 return(montage_image);
00335 }
00336
00337 MagickExport Image *MontageImageList(const ImageInfo *image_info,
00338 const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception)
00339 {
00340 #define MontageImageTag "Montage/Image"
00341 #define TileImageTag "Tile/Image"
00342
00343 char
00344 tile_geometry[MaxTextExtent],
00345 *title;
00346
00347 const char
00348 *value;
00349
00350 DrawInfo
00351 *draw_info;
00352
00353 FrameInfo
00354 frame_info;
00355
00356 Image
00357 *image,
00358 **image_list,
00359 **master_list,
00360 *montage,
00361 *texture,
00362 *tile_image,
00363 *thumbnail;
00364
00365 ImageInfo
00366 *clone_info;
00367
00368 long
00369 tile,
00370 x,
00371 x_offset,
00372 y,
00373 y_offset;
00374
00375 MagickBooleanType
00376 concatenate,
00377 proceed,
00378 status;
00379
00380 MagickOffsetType
00381 tiles;
00382
00383 MagickStatusType
00384 flags;
00385
00386 MagickProgressMonitor
00387 progress_monitor;
00388
00389 register long
00390 i;
00391
00392 RectangleInfo
00393 bounds,
00394 geometry,
00395 extract_info;
00396
00397 size_t
00398 extent;
00399
00400 TypeMetric
00401 metrics;
00402
00403 unsigned long
00404 bevel_width,
00405 border_width,
00406 height,
00407 images_per_page,
00408 max_height,
00409 number_images,
00410 number_lines,
00411 sans,
00412 tiles_per_column,
00413 tiles_per_page,
00414 tiles_per_row,
00415 title_offset,
00416 total_tiles,
00417 width;
00418
00419
00420
00421
00422 assert(images != (Image *) NULL);
00423 assert(images->signature == MagickSignature);
00424 if (images->debug != MagickFalse)
00425 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00426 assert(montage_info != (MontageInfo *) NULL);
00427 assert(montage_info->signature == MagickSignature);
00428 assert(exception != (ExceptionInfo *) NULL);
00429 assert(exception->signature == MagickSignature);
00430 number_images=GetImageListLength(images);
00431 master_list=ImageListToArray(images,exception);
00432 image_list=master_list;
00433 image=image_list[0];
00434 if (master_list == (Image **) NULL)
00435 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00436 thumbnail=NewImageList();
00437 for (i=0; i < (long) number_images; i++)
00438 {
00439 image=CloneImage(image_list[i],0,0,MagickTrue,exception);
00440 if (image == (Image *) NULL)
00441 break;
00442 (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
00443 progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
00444 image->client_data);
00445 flags=ParseSizeGeometry(image,montage_info->geometry,&geometry);
00446 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
00447 if (thumbnail == (Image *) NULL)
00448 break;
00449 image_list[i]=thumbnail;
00450 (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
00451 proceed=SetImageProgress(image,TileImageTag,i,number_images);
00452 if (proceed == MagickFalse)
00453 break;
00454 image=DestroyImage(image);
00455 }
00456 if (i < (long) number_images)
00457 {
00458 if (thumbnail == (Image *) NULL)
00459 i--;
00460 for (tile=0; (long) tile <= i; tile++)
00461 if (image_list[tile] != (Image *) NULL)
00462 image_list[tile]=DestroyImage(image_list[tile]);
00463 master_list=(Image **) RelinquishMagickMemory(master_list);
00464 return((Image *) NULL);
00465 }
00466
00467
00468
00469 for (i=0; i < (long) number_images; i++)
00470 if (image_list[i]->scene == 0)
00471 break;
00472 if (i == (long) number_images)
00473 qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
00474 SceneCompare);
00475
00476
00477
00478 tiles_per_column=(unsigned long) sqrt((double) number_images);
00479 tiles_per_row=(unsigned long) ceil((double) number_images/tiles_per_column);
00480 x_offset=0;
00481 y_offset=0;
00482 if (montage_info->tile != (char *) NULL)
00483 GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00484 &tiles_per_column,&tiles_per_row);
00485
00486
00487
00488 concatenate=MagickFalse;
00489 SetGeometry(image_list[0],&extract_info);
00490 extract_info.x=(long) montage_info->border_width;
00491 extract_info.y=(long) montage_info->border_width;
00492 if (montage_info->geometry != (char *) NULL)
00493 {
00494
00495
00496
00497 flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y,
00498 &extract_info.width,&extract_info.height);
00499 if ((extract_info.x == 0) && (extract_info.y == 0))
00500 concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ?
00501 MagickTrue : MagickFalse;
00502 }
00503 border_width=montage_info->border_width;
00504 bevel_width=0;
00505 if (montage_info->frame != (char *) NULL)
00506 {
00507 char
00508 absolute_geometry[MaxTextExtent];
00509
00510 (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info));
00511 frame_info.width=extract_info.width;
00512 frame_info.height=extract_info.height;
00513 (void) FormatMagickString(absolute_geometry,MaxTextExtent,"%s!",
00514 montage_info->frame);
00515 flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel,
00516 &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
00517 if ((flags & HeightValue) == 0)
00518 frame_info.height=frame_info.width;
00519 if ((flags & XiValue) == 0)
00520 frame_info.outer_bevel=(long) frame_info.width/2;
00521 if ((flags & PsiValue) == 0)
00522 frame_info.inner_bevel=frame_info.outer_bevel;
00523 frame_info.x=(long) frame_info.width;
00524 frame_info.y=(long) frame_info.height;
00525 bevel_width=(unsigned long) MagickMax(frame_info.inner_bevel,
00526 frame_info.outer_bevel);
00527 border_width=(unsigned long) MagickMax((long) frame_info.width,
00528 (long) frame_info.height);
00529 }
00530 for (i=0; i < (long) number_images; i++)
00531 {
00532 if (image_list[i]->columns > extract_info.width)
00533 extract_info.width=image_list[i]->columns;
00534 if (image_list[i]->rows > extract_info.height)
00535 extract_info.height=image_list[i]->rows;
00536 }
00537
00538
00539
00540 clone_info=CloneImageInfo(image_info);
00541 clone_info->background_color=montage_info->background_color;
00542 clone_info->border_color=montage_info->border_color;
00543 draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL);
00544 if (montage_info->font != (char *) NULL)
00545 (void) CloneString(&draw_info->font,montage_info->font);
00546 if (montage_info->pointsize != 0.0)
00547 draw_info->pointsize=montage_info->pointsize;
00548 draw_info->gravity=CenterGravity;
00549 draw_info->stroke=montage_info->stroke;
00550 draw_info->fill=montage_info->fill;
00551 draw_info->text=AcquireString("");
00552 (void) GetTypeMetrics(image_list[0],draw_info,&metrics);
00553 texture=NewImageList();
00554 if (montage_info->texture != (char *) NULL)
00555 {
00556 (void) CopyMagickString(clone_info->filename,montage_info->texture,
00557 MaxTextExtent);
00558 texture=ReadImage(clone_info,exception);
00559 }
00560
00561
00562
00563 title=InterpretImageProperties(clone_info,image_list[0],montage_info->title);
00564 title_offset=0;
00565 if (montage_info->title != (char *) NULL)
00566 title_offset=(unsigned long) (2*(metrics.ascent-metrics.descent)*
00567 MultilineCensus(title)+2*extract_info.y);
00568 number_lines=0;
00569 for (i=0; i < (long) number_images; i++)
00570 {
00571 value=GetImageProperty(image_list[i],"label");
00572 if (value == (const char *) NULL)
00573 continue;
00574 if (MultilineCensus(value) > number_lines)
00575 number_lines=MultilineCensus(value);
00576 }
00577
00578
00579
00580 tile_image=AcquireImage(NULL);
00581 montage=AcquireImage(clone_info);
00582 montage->scene=0;
00583 images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
00584 tiles=0;
00585 total_tiles=(unsigned long) number_images;
00586 for (i=0; i < (long) images_per_page; i++)
00587 {
00588
00589
00590
00591 tiles_per_page=tiles_per_row*tiles_per_column;
00592 x_offset=0;
00593 y_offset=0;
00594 if (montage_info->tile != (char *) NULL)
00595 GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00596 &sans,&sans);
00597 tiles_per_page=tiles_per_row*tiles_per_column;
00598 y_offset+=(long) title_offset;
00599 max_height=0;
00600 bounds.width=0;
00601 bounds.height=0;
00602 width=0;
00603 for (tile=0; tile < (long) tiles_per_page; tile++)
00604 {
00605 if (tile < (long) number_images)
00606 {
00607 width=concatenate != MagickFalse ? image_list[tile]->columns :
00608 extract_info.width;
00609 if (image_list[tile]->rows > max_height)
00610 max_height=image_list[tile]->rows;
00611 }
00612 x_offset+=width+(extract_info.x+border_width)*2;
00613 if (x_offset > (long) bounds.width)
00614 bounds.width=(unsigned long) x_offset;
00615 if (((tile+1) == (long) tiles_per_page) ||
00616 (((tile+1) % tiles_per_row) == 0))
00617 {
00618 x_offset=0;
00619 if (montage_info->tile != (char *) NULL)
00620 GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y,
00621 &sans,&sans);
00622 height=concatenate != MagickFalse ? max_height : extract_info.height;
00623 y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+
00624 (metrics.ascent-metrics.descent+4)*number_lines+
00625 (montage_info->shadow != MagickFalse ? 4 : 0));
00626 if (y_offset > (long) bounds.height)
00627 bounds.height=(unsigned long) y_offset;
00628 max_height=0;
00629 }
00630 }
00631 if (montage_info->shadow != MagickFalse)
00632 bounds.width+=4;
00633
00634
00635
00636 (void) CopyMagickString(montage->filename,montage_info->filename,
00637 MaxTextExtent);
00638 montage->columns=bounds.width;
00639 montage->rows=bounds.height;
00640 (void) SetImageBackgroundColor(montage);
00641
00642
00643
00644 montage->montage=AcquireString((char *) NULL);
00645 tile=0;
00646 extent=1;
00647 while (tile < MagickMin((long) tiles_per_page,(long) number_images))
00648 {
00649 extent+=strlen(image_list[tile]->filename)+1;
00650 tile++;
00651 }
00652 montage->directory=(char *) AcquireQuantumMemory(extent,
00653 sizeof(*montage->directory));
00654 if ((montage->montage == (char *) NULL) ||
00655 (montage->directory == (char *) NULL))
00656 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00657 x_offset=0;
00658 y_offset=0;
00659 if (montage_info->tile != (char *) NULL)
00660 GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00661 &sans,&sans);
00662 y_offset+=(long) title_offset;
00663 (void) FormatMagickString(montage->montage,MaxTextExtent,"%ldx%ld%+ld%+ld",
00664 (long) (extract_info.width+(extract_info.x+border_width)*2),
00665 (long) (extract_info.height+(extract_info.y+border_width)*2+
00666 (metrics.ascent-metrics.descent+4)*number_lines+
00667 (montage_info->shadow != MagickFalse ? 4 : 0)),x_offset,y_offset);
00668 *montage->directory='\0';
00669 tile=0;
00670 while (tile < MagickMin((long) tiles_per_page,(long) number_images))
00671 {
00672 (void) ConcatenateMagickString(montage->directory,
00673 image_list[tile]->filename,extent);
00674 (void) ConcatenateMagickString(montage->directory,"\n",extent);
00675 tile++;
00676 }
00677 progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor)
00678 NULL,montage->client_data);
00679 if (texture != (Image *) NULL)
00680 (void) TextureImage(montage,texture);
00681 if (montage_info->title != (char *) NULL)
00682 {
00683 char
00684 geometry[MaxTextExtent];
00685
00686 DrawInfo
00687 *clone_info;
00688
00689
00690
00691
00692 clone_info=CloneDrawInfo(image_info,draw_info);
00693 (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
00694 montage->columns,(unsigned long) (2*(metrics.ascent-metrics.descent)),
00695 0L,(long) (extract_info.y+4));
00696 (void) CloneString(&clone_info->geometry,geometry);
00697 (void) CloneString(&clone_info->text,title);
00698 clone_info->pointsize*=2.0;
00699 (void) AnnotateImage(montage,clone_info);
00700 clone_info=DestroyDrawInfo(clone_info);
00701 }
00702 (void) SetImageProgressMonitor(montage,progress_monitor,
00703 montage->client_data);
00704
00705
00706
00707 x_offset=0;
00708 y_offset=0;
00709 if (montage_info->tile != (char *) NULL)
00710 GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00711 &sans,&sans);
00712 x_offset+=extract_info.x;
00713 y_offset+=(long) title_offset+extract_info.y;
00714 max_height=0;
00715 for (tile=0; tile < MagickMin((long) tiles_per_page,(long) number_images); tile++)
00716 {
00717
00718
00719
00720 image=CloneImage(image_list[tile],0,0,MagickTrue,exception);
00721 progress_monitor=SetImageProgressMonitor(image,
00722 (MagickProgressMonitor) NULL,image->client_data);
00723 width=concatenate != MagickFalse ? image->columns : extract_info.width;
00724 if (image->rows > max_height)
00725 max_height=image->rows;
00726 height=concatenate != MagickFalse ? max_height : extract_info.height;
00727 if (border_width != 0)
00728 {
00729 Image
00730 *border_image;
00731
00732 RectangleInfo
00733 border_info;
00734
00735
00736
00737
00738 border_info.width=border_width;
00739 border_info.height=border_width;
00740 if (montage_info->frame != (char *) NULL)
00741 {
00742 border_info.width=(width-image->columns+1)/2;
00743 border_info.height=(height-image->rows+1)/2;
00744 }
00745 border_image=BorderImage(image,&border_info,exception);
00746 if (border_image != (Image *) NULL)
00747 {
00748 image=DestroyImage(image);
00749 image=border_image;
00750 }
00751 if ((montage_info->frame != (char *) NULL) &&
00752 (image->compose == DstOutCompositeOp))
00753 (void) NegateImageChannel(image,OpacityChannel,MagickFalse);
00754 }
00755
00756
00757
00758 tile_image->columns=width;
00759 tile_image->rows=height;
00760 tile_image->gravity=montage_info->gravity;
00761 if (image->gravity != UndefinedGravity)
00762 tile_image->gravity=image->gravity;
00763 (void) FormatMagickString(tile_geometry,MaxTextExtent,"%lux%lu+0+0",
00764 image->columns,image->rows);
00765 flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry);
00766 x=(long) (geometry.x+border_width);
00767 y=(long) (geometry.y+border_width);
00768 if ((montage_info->frame != (char *) NULL) && (bevel_width != 0))
00769 {
00770 FrameInfo
00771 extract_info;
00772
00773 Image
00774 *frame_image;
00775
00776
00777
00778
00779 extract_info=frame_info;
00780 extract_info.width=width+2*frame_info.width;
00781 extract_info.height=height+2*frame_info.height;
00782 value=GetImageProperty(image,"label");
00783 if (value != (const char *) NULL)
00784 extract_info.height+=(unsigned long) ((metrics.ascent-
00785 metrics.descent+4)*MultilineCensus(value));
00786 frame_image=FrameImage(image,&extract_info,exception);
00787 if (frame_image != (Image *) NULL)
00788 {
00789 image=DestroyImage(image);
00790 image=frame_image;
00791 }
00792 x=0;
00793 y=0;
00794 }
00795 if (LocaleCompare(image->magick,"NULL") != 0)
00796 {
00797
00798
00799
00800 if (montage_info->shadow != MagickFalse)
00801 {
00802 Image
00803 *shadow_image;
00804
00805
00806
00807
00808 (void) QueryColorDatabase("#000000",&image->background_color,
00809 exception);
00810 shadow_image=ShadowImage(image,80.0,2.0,5,5,exception);
00811 if (shadow_image != (Image *) NULL)
00812 {
00813 InheritException(&shadow_image->exception,exception);
00814 (void) CompositeImage(shadow_image,OverCompositeOp,image,0,0);
00815 image=DestroyImage(image);
00816 image=shadow_image;
00817 }
00818 }
00819 (void) CompositeImage(montage,OverCompositeOp,image,x_offset+x,
00820 y_offset+y);
00821 value=GetImageProperty(image,"label");
00822 if (value != (const char *) NULL)
00823 {
00824 char
00825 geometry[MaxTextExtent];
00826
00827
00828
00829
00830 (void) FormatMagickString(geometry,MaxTextExtent,
00831 "%lux%lu%+ld%+ld",(montage_info->frame ? image->columns :
00832 width)-2*border_width,(unsigned long) (metrics.ascent-
00833 metrics.descent+4)*MultilineCensus(value),x_offset+
00834 border_width,(montage_info->frame ? y_offset+height+
00835 border_width+4 : y_offset+extract_info.height+border_width+
00836 (montage_info->shadow != MagickFalse ? 4 : 0)));
00837 (void) CloneString(&draw_info->geometry,geometry);
00838 (void) CloneString(&draw_info->text,value);
00839 (void) AnnotateImage(montage,draw_info);
00840 }
00841 }
00842 x_offset+=width+(extract_info.x+border_width)*2;
00843 if (((tile+1) == (long) tiles_per_page) ||
00844 (((tile+1) % tiles_per_row) == 0))
00845 {
00846 x_offset=extract_info.x;
00847 y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+
00848 (metrics.ascent-metrics.descent+4)*number_lines+
00849 (montage_info->shadow != MagickFalse ? 4 : 0));
00850 max_height=0;
00851 }
00852 if ((images->progress_monitor != (MagickProgressMonitor) NULL) &&
00853 (QuantumTick(tiles,total_tiles) != MagickFalse))
00854 {
00855 status=images->progress_monitor(MontageImageTag,tiles,total_tiles,
00856 images->client_data);
00857 if (status == MagickFalse)
00858 break;
00859 }
00860 image_list[tile]=DestroyImage(image_list[tile]);
00861 image=DestroyImage(image);
00862 tiles++;
00863 }
00864 if ((i+1) < (long) images_per_page)
00865 {
00866
00867
00868
00869 AcquireNextImage(clone_info,montage);
00870 if (GetNextImageInList(montage) == (Image *) NULL)
00871 {
00872 montage=DestroyImageList(montage);
00873 return((Image *) NULL);
00874 }
00875 montage=GetNextImageInList(montage);
00876 image_list+=tiles_per_page;
00877 number_images-=tiles_per_page;
00878 }
00879 }
00880 tile_image=DestroyImage(tile_image);
00881 if (texture != (Image *) NULL)
00882 texture=DestroyImage(texture);
00883 master_list=(Image **) RelinquishMagickMemory(master_list);
00884 draw_info=DestroyDrawInfo(draw_info);
00885 clone_info=DestroyImageInfo(clone_info);
00886 while (GetPreviousImageInList(montage) != (Image *) NULL)
00887 montage=GetPreviousImageInList(montage);
00888 return(montage);
00889 }