montage.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               M   M   OOO   N   N  TTTTT   AAA    GGGG  EEEEE               %
00007 %               MM MM  O   O  NN  N    T    A   A  G      E                   %
00008 %               M M M  O   O  N N N    T    AAAAA  G  GG  EEE                 %
00009 %               M   M  O   O  N  NN    T    A   A  G   G  E                   %
00010 %               M   M   OOO   N   N    T    A   A   GGG   EEEEE               %
00011 %                                                                             %
00012 %                                                                             %
00013 %                MagickCore Methods to Create Image Thumbnails                %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
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 %   C l o n e M o n t a g e I n f o                                           %
00080 %                                                                             %
00081 %                                                                             %
00082 %                                                                             %
00083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00084 %
00085 %  CloneMontageInfo() makes a copy of the given montage info structure.  If
00086 %  NULL is specified, a new image info structure is created initialized to
00087 %  default values.
00088 %
00089 %  The format of the CloneMontageInfo method is:
00090 %
00091 %      MontageInfo *CloneMontageInfo(const ImageInfo *image_info,
00092 %        const MontageInfo *montage_info)
00093 %
00094 %  A description of each parameter follows:
00095 %
00096 %    o image_info: the image info.
00097 %
00098 %    o montage_info: the montage info.
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 %   D e s t r o y M o n t a g e I n f o                                       %
00146 %                                                                             %
00147 %                                                                             %
00148 %                                                                             %
00149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00150 %
00151 %  DestroyMontageInfo() deallocates memory associated with montage_info.
00152 %
00153 %  The format of the DestroyMontageInfo method is:
00154 %
00155 %      MontageInfo *DestroyMontageInfo(MontageInfo *montage_info)
00156 %
00157 %  A description of each parameter follows:
00158 %
00159 %    o montage_info: Specifies a pointer to an MontageInfo structure.
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 %   G e t M o n t a g e I n f o                                               %
00194 %                                                                             %
00195 %                                                                             %
00196 %                                                                             %
00197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00198 %
00199 %  GetMontageInfo() initializes montage_info to default values.
00200 %
00201 %  The format of the GetMontageInfo method is:
00202 %
00203 %      void GetMontageInfo(const ImageInfo *image_info,
00204 %        MontageInfo *montage_info)
00205 %
00206 %  A description of each parameter follows:
00207 %
00208 %    o image_info: a structure of type ImageInfo.
00209 %
00210 %    o montage_info: Specifies a pointer to a MontageInfo structure.
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 %   M o n t a g e I m a g e L i s t                                           %
00246 %                                                                             %
00247 %                                                                             %
00248 %                                                                             %
00249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00250 %
00251 %  MontageImageList() is a layout manager that lets you tile one or more
00252 %  thumbnails across an image canvas.
00253 %
00254 %  The format of the MontageImageList method is:
00255 %
00256 %      Image *MontageImageList(const ImageInfo *image_info,
00257 %        const MontageInfo *montage_info,Image *images,
00258 %        ExceptionInfo *exception)
00259 %
00260 %  A description of each parameter follows:
00261 %
00262 %    o image_info: the image info.
00263 %
00264 %    o montage_info: Specifies a pointer to a MontageInfo structure.
00265 %
00266 %    o images: Specifies a pointer to an array of Image structures.
00267 %
00268 %    o exception: return any errors or warnings in this structure.
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     Create image tiles.
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     Sort image list by increasing tile number.
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     Determine tiles per row and column.
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     Determine tile sizes.
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         Initialize tile geometry.
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     Initialize draw attributes.
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     Determine the number of lines in an next label.
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     Allocate next structure.
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       Determine bounding box.
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       Initialize montage image.
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       Set montage geometry.
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           Annotate composite image with title.
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       Copy tile to the composite.
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         Copy this tile to the composite.
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             Put a border around the image.
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         Gravitate as specified by the tile gravity.
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             Put an ornamental border around this tile.
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             Composite background with tile.
00799           */
00800           if (montage_info->shadow != MagickFalse)
00801             {
00802               Image
00803                 *shadow_image;
00804 
00805               /*
00806                 Shadow image.
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                 Annotate composite tile with label.
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           Allocate next image structure.
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 }

Generated on Sat Nov 22 23:45:16 2008 for MagickCore by  doxygen 1.5.7.1