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-2009 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 MagickExport void GetMontageInfo(const ImageInfo *image_info,
00214   MontageInfo *montage_info)
00215 {
00216   assert(image_info != (const ImageInfo *) NULL);
00217   assert(image_info->signature == MagickSignature);
00218   if (image_info->debug != MagickFalse)
00219     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00220       image_info->filename);
00221   assert(montage_info != (MontageInfo *) NULL);
00222   (void) ResetMagickMemory(montage_info,0,sizeof(*montage_info));
00223   (void) CopyMagickString(montage_info->filename,image_info->filename,
00224     MaxTextExtent);
00225   montage_info->geometry=AcquireString(DefaultTileGeometry);
00226   if (image_info->font != (char *) NULL)
00227     montage_info->font=AcquireString(image_info->font);
00228   montage_info->gravity=CenterGravity;
00229   montage_info->pointsize=image_info->pointsize;
00230   montage_info->fill.opacity=OpaqueOpacity;
00231   montage_info->stroke.opacity=(Quantum) TransparentOpacity;
00232   montage_info->background_color=image_info->background_color;
00233   montage_info->border_color=image_info->border_color;
00234   montage_info->matte_color=image_info->matte_color;
00235   montage_info->debug=IsEventLogging();
00236   montage_info->signature=MagickSignature;
00237 }
00238 
00239 /*
00240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00241 %                                                                             %
00242 %                                                                             %
00243 %                                                                             %
00244 %   M o n t a g e I m a g e L i s t                                           %
00245 %                                                                             %
00246 %                                                                             %
00247 %                                                                             %
00248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00249 %
00250 %  MontageImageList() is a layout manager that lets you tile one or more
00251 %  thumbnails across an image canvas.
00252 %
00253 %  The format of the MontageImageList method is:
00254 %
00255 %      Image *MontageImageList(const ImageInfo *image_info,
00256 %        const MontageInfo *montage_info,Image *images,
00257 %        ExceptionInfo *exception)
00258 %
00259 %  A description of each parameter follows:
00260 %
00261 %    o image_info: the image info.
00262 %
00263 %    o montage_info: Specifies a pointer to a MontageInfo structure.
00264 %
00265 %    o images: Specifies a pointer to an array of Image structures.
00266 %
00267 %    o exception: return any errors or warnings in this structure.
00268 %
00269 */
00270 
00271 static void GetMontageGeometry(char *geometry,const unsigned long number_images,
00272   long *x_offset,long *y_offset,unsigned long *tiles_per_column,
00273   unsigned long *tiles_per_row)
00274 {
00275   *tiles_per_column=0;
00276   *tiles_per_row=0;
00277   (void) GetGeometry(geometry,x_offset,y_offset,tiles_per_row,tiles_per_column);
00278   if ((*tiles_per_column == 0) && (*tiles_per_row == 0))
00279     *tiles_per_column=(unsigned long) sqrt((double) number_images);
00280   if (*tiles_per_column == 0)
00281     *tiles_per_column=(unsigned long)
00282       ceil((double) number_images/(*tiles_per_row));
00283   if (*tiles_per_row == 0)
00284     *tiles_per_row=(unsigned long)
00285       ceil((double) number_images/(*tiles_per_column));
00286 }
00287 
00288 static inline long MagickMax(const long x,const long y)
00289 {
00290   if (x > y)
00291     return(x);
00292   return(y);
00293 }
00294 
00295 static inline long MagickMin(const long x,const long y)
00296 {
00297   if (x < y)
00298     return(x);
00299   return(y);
00300 }
00301 
00302 #if defined(__cplusplus) || defined(c_plusplus)
00303 extern "C" {
00304 #endif
00305 
00306 static int SceneCompare(const void *x,const void *y)
00307 {
00308   Image
00309     **image_1,
00310     **image_2;
00311 
00312   image_1=(Image **) x;
00313   image_2=(Image **) y;
00314   return((int) ((*image_1)->scene-(*image_2)->scene));
00315 }
00316 
00317 #if defined(__cplusplus) || defined(c_plusplus)
00318 }
00319 #endif
00320 
00321 MagickExport Image *MontageImages(const Image *images,
00322   const MontageInfo *montage_info,ExceptionInfo *exception)
00323 {
00324   Image
00325     *montage_image;
00326 
00327   ImageInfo
00328     *image_info;
00329 
00330   image_info=AcquireImageInfo();
00331   montage_image=MontageImageList(image_info,montage_info,images,exception);
00332   image_info=DestroyImageInfo(image_info);
00333   return(montage_image);
00334 }
00335 
00336 MagickExport Image *MontageImageList(const ImageInfo *image_info,
00337   const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception)
00338 {
00339 #define MontageImageTag  "Montage/Image"
00340 #define TileImageTag  "Tile/Image"
00341 
00342   char
00343     tile_geometry[MaxTextExtent],
00344     *title;
00345 
00346   const char
00347     *value;
00348 
00349   DrawInfo
00350     *draw_info;
00351 
00352   FrameInfo
00353     frame_info;
00354 
00355   Image
00356     *image,
00357     **image_list,
00358     **master_list,
00359     *montage,
00360     *texture,
00361     *tile_image,
00362     *thumbnail;
00363 
00364   ImageInfo
00365     *clone_info;
00366 
00367   long
00368     tile,
00369     x,
00370     x_offset,
00371     y,
00372     y_offset;
00373 
00374   MagickBooleanType
00375     concatenate,
00376     proceed,
00377     status;
00378 
00379   MagickOffsetType
00380     tiles;
00381 
00382   MagickStatusType
00383     flags;
00384 
00385   MagickProgressMonitor
00386     progress_monitor;
00387 
00388   register long
00389     i;
00390 
00391   RectangleInfo
00392     bounds,
00393     geometry,
00394     extract_info;
00395 
00396   size_t
00397     extent;
00398 
00399   TypeMetric
00400     metrics;
00401 
00402   unsigned long
00403     bevel_width,
00404     border_width,
00405     height,
00406     images_per_page,
00407     max_height,
00408     number_images,
00409     number_lines,
00410     sans,
00411     tiles_per_column,
00412     tiles_per_page,
00413     tiles_per_row,
00414     title_offset,
00415     total_tiles,
00416     width;
00417 
00418   /*
00419     Create image tiles.
00420   */
00421   assert(images != (Image *) NULL);
00422   assert(images->signature == MagickSignature);
00423   if (images->debug != MagickFalse)
00424     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00425   assert(montage_info != (MontageInfo *) NULL);
00426   assert(montage_info->signature == MagickSignature);
00427   assert(exception != (ExceptionInfo *) NULL);
00428   assert(exception->signature == MagickSignature);
00429   number_images=GetImageListLength(images);
00430   master_list=ImageListToArray(images,exception);
00431   image_list=master_list;
00432   image=image_list[0];
00433   if (master_list == (Image **) NULL)
00434     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00435   thumbnail=NewImageList();
00436   for (i=0; i < (long) number_images; i++)
00437   {
00438     image=CloneImage(image_list[i],0,0,MagickTrue,exception);
00439     if (image == (Image *) NULL)
00440       break;
00441     (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
00442     progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
00443       image->client_data);
00444     flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception);
00445     thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
00446     if (thumbnail == (Image *) NULL)
00447       break;
00448     image_list[i]=thumbnail;
00449     (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
00450     proceed=SetImageProgress(image,TileImageTag,i,number_images);
00451     if (proceed == MagickFalse)
00452       break;
00453     image=DestroyImage(image);
00454   }
00455   if (i < (long) number_images)
00456     {
00457       if (thumbnail == (Image *) NULL)
00458         i--;
00459       for (tile=0; (long) tile <= i; tile++)
00460         if (image_list[tile] != (Image *) NULL)
00461           image_list[tile]=DestroyImage(image_list[tile]);
00462       master_list=(Image **) RelinquishMagickMemory(master_list);
00463       return((Image *) NULL);
00464     }
00465   /*
00466     Sort image list by increasing tile number.
00467   */
00468   for (i=0; i < (long) number_images; i++)
00469     if (image_list[i]->scene == 0)
00470       break;
00471   if (i == (long) number_images)
00472     qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
00473       SceneCompare);
00474   /*
00475     Determine tiles per row and column.
00476   */
00477   tiles_per_column=(unsigned long) sqrt((double) number_images);
00478   tiles_per_row=(unsigned long) ceil((double) number_images/tiles_per_column);
00479   x_offset=0;
00480   y_offset=0;
00481   if (montage_info->tile != (char *) NULL)
00482     GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00483       &tiles_per_column,&tiles_per_row);
00484   /*
00485     Determine tile sizes.
00486   */
00487   concatenate=MagickFalse;
00488   SetGeometry(image_list[0],&extract_info);
00489   extract_info.x=(long) montage_info->border_width;
00490   extract_info.y=(long) montage_info->border_width;
00491   if (montage_info->geometry != (char *) NULL)
00492     {
00493       /*
00494         Initialize tile geometry.
00495       */
00496       flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y,
00497         &extract_info.width,&extract_info.height);
00498       if ((extract_info.x == 0) && (extract_info.y == 0))
00499         concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ?
00500           MagickTrue : MagickFalse;
00501     }
00502   border_width=montage_info->border_width;
00503   bevel_width=0;
00504   if (montage_info->frame != (char *) NULL)
00505     {
00506       char
00507         absolute_geometry[MaxTextExtent];
00508 
00509       (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info));
00510       frame_info.width=extract_info.width;
00511       frame_info.height=extract_info.height;
00512       (void) FormatMagickString(absolute_geometry,MaxTextExtent,"%s!",
00513         montage_info->frame);
00514       flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel,
00515         &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
00516       if ((flags & HeightValue) == 0)
00517         frame_info.height=frame_info.width;
00518       if ((flags & XiValue) == 0)
00519         frame_info.outer_bevel=(long) frame_info.width/2;
00520       if ((flags & PsiValue) == 0)
00521         frame_info.inner_bevel=frame_info.outer_bevel;
00522       frame_info.x=(long) frame_info.width;
00523       frame_info.y=(long) frame_info.height;
00524       bevel_width=(unsigned long) MagickMax(frame_info.inner_bevel,
00525         frame_info.outer_bevel);
00526       border_width=(unsigned long) MagickMax((long) frame_info.width,
00527         (long) frame_info.height);
00528     }
00529   for (i=0; i < (long) number_images; i++)
00530   {
00531     if (image_list[i]->columns > extract_info.width)
00532       extract_info.width=image_list[i]->columns;
00533     if (image_list[i]->rows > extract_info.height)
00534       extract_info.height=image_list[i]->rows;
00535   }
00536   /*
00537     Initialize draw attributes.
00538   */
00539   clone_info=CloneImageInfo(image_info);
00540   clone_info->background_color=montage_info->background_color;
00541   clone_info->border_color=montage_info->border_color;
00542   draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL);
00543   if (montage_info->font != (char *) NULL)
00544     (void) CloneString(&draw_info->font,montage_info->font);
00545   if (montage_info->pointsize != 0.0)
00546     draw_info->pointsize=montage_info->pointsize;
00547   draw_info->gravity=CenterGravity;
00548   draw_info->stroke=montage_info->stroke;
00549   draw_info->fill=montage_info->fill;
00550   draw_info->text=AcquireString("");
00551   (void) GetTypeMetrics(image_list[0],draw_info,&metrics);
00552   texture=NewImageList();
00553   if (montage_info->texture != (char *) NULL)
00554     {
00555       (void) CopyMagickString(clone_info->filename,montage_info->texture,
00556         MaxTextExtent);
00557       texture=ReadImage(clone_info,exception);
00558     }
00559   /*
00560     Determine the number of lines in an next label.
00561   */
00562   title=InterpretImageProperties(clone_info,image_list[0],montage_info->title);
00563   title_offset=0;
00564   if (montage_info->title != (char *) NULL)
00565     title_offset=(unsigned long) (2*(metrics.ascent-metrics.descent)*
00566       MultilineCensus(title)+2*extract_info.y);
00567   number_lines=0;
00568   for (i=0; i < (long) number_images; i++)
00569   {
00570     value=GetImageProperty(image_list[i],"label");
00571     if (value == (const char *) NULL)
00572       continue;
00573     if (MultilineCensus(value) > number_lines)
00574       number_lines=MultilineCensus(value);
00575   }
00576   /*
00577     Allocate next structure.
00578   */
00579   tile_image=AcquireImage(NULL);
00580   montage=AcquireImage(clone_info);
00581   montage->scene=0;
00582   images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
00583   tiles=0;
00584   total_tiles=(unsigned long) number_images;
00585   for (i=0; i < (long) images_per_page; i++)
00586   {
00587     /*
00588       Determine bounding box.
00589     */
00590     tiles_per_page=tiles_per_row*tiles_per_column;
00591     x_offset=0;
00592     y_offset=0;
00593     if (montage_info->tile != (char *) NULL)
00594       GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00595         &sans,&sans);
00596     tiles_per_page=tiles_per_row*tiles_per_column;
00597     y_offset+=(long) title_offset;
00598     max_height=0;
00599     bounds.width=0;
00600     bounds.height=0;
00601     width=0;
00602     for (tile=0; tile < (long) tiles_per_page; tile++)
00603     {
00604       if (tile < (long) number_images)
00605         {
00606           width=concatenate != MagickFalse ? image_list[tile]->columns :
00607             extract_info.width;
00608           if (image_list[tile]->rows > max_height)
00609             max_height=image_list[tile]->rows;
00610         }
00611       x_offset+=width+(extract_info.x+border_width)*2;
00612       if (x_offset > (long) bounds.width)
00613         bounds.width=(unsigned long) x_offset;
00614       if (((tile+1) == (long) tiles_per_page) ||
00615           (((tile+1) % tiles_per_row) == 0))
00616         {
00617           x_offset=0;
00618           if (montage_info->tile != (char *) NULL)
00619             GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y,
00620               &sans,&sans);
00621           height=concatenate != MagickFalse ? max_height : extract_info.height;
00622           y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+
00623             (metrics.ascent-metrics.descent+4)*number_lines+
00624             (montage_info->shadow != MagickFalse ? 4 : 0));
00625           if (y_offset > (long) bounds.height)
00626             bounds.height=(unsigned long) y_offset;
00627           max_height=0;
00628         }
00629     }
00630     if (montage_info->shadow != MagickFalse)
00631       bounds.width+=4;
00632     /*
00633       Initialize montage image.
00634     */
00635     (void) CopyMagickString(montage->filename,montage_info->filename,
00636       MaxTextExtent);
00637     montage->columns=bounds.width;
00638     montage->rows=bounds.height;
00639     (void) SetImageBackgroundColor(montage);
00640     /*
00641       Set montage geometry.
00642     */
00643     montage->montage=AcquireString((char *) NULL);
00644     tile=0;
00645     extent=1;
00646     while (tile < MagickMin((long) tiles_per_page,(long) number_images))
00647     {
00648       extent+=strlen(image_list[tile]->filename)+1;
00649       tile++;
00650     }
00651     montage->directory=(char *) AcquireQuantumMemory(extent,
00652       sizeof(*montage->directory));
00653     if ((montage->montage == (char *) NULL) ||
00654         (montage->directory == (char *) NULL))
00655       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00656     x_offset=0;
00657     y_offset=0;
00658     if (montage_info->tile != (char *) NULL)
00659       GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00660         &sans,&sans);
00661     y_offset+=(long) title_offset;
00662     (void) FormatMagickString(montage->montage,MaxTextExtent,"%ldx%ld%+ld%+ld",
00663       (long) (extract_info.width+(extract_info.x+border_width)*2),
00664       (long) (extract_info.height+(extract_info.y+border_width)*2+
00665       (metrics.ascent-metrics.descent+4)*number_lines+
00666       (montage_info->shadow != MagickFalse ? 4 : 0)),x_offset,y_offset);
00667     *montage->directory='\0';
00668     tile=0;
00669     while (tile < MagickMin((long) tiles_per_page,(long) number_images))
00670     {
00671       (void) ConcatenateMagickString(montage->directory,
00672         image_list[tile]->filename,extent);
00673       (void) ConcatenateMagickString(montage->directory,"\n",extent);
00674       tile++;
00675     }
00676     progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor)
00677       NULL,montage->client_data);
00678     if (texture != (Image *) NULL)
00679       (void) TextureImage(montage,texture);
00680     if (montage_info->title != (char *) NULL)
00681       {
00682         char
00683           geometry[MaxTextExtent];
00684 
00685         DrawInfo
00686           *clone_info;
00687 
00688         TypeMetric
00689           metrics;
00690 
00691         /*
00692           Annotate composite image with title.
00693         */
00694         clone_info=CloneDrawInfo(image_info,draw_info);
00695         clone_info->gravity=CenterGravity;
00696         clone_info->pointsize*=2.0;
00697         (void) GetTypeMetrics(image_list[0],clone_info,&metrics);
00698         (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld",
00699           montage->columns,(unsigned long) (metrics.ascent-metrics.descent),
00700           0L,(long) extract_info.y+4);
00701         (void) CloneString(&clone_info->geometry,geometry);
00702         (void) CloneString(&clone_info->text,title);
00703         (void) AnnotateImage(montage,clone_info);
00704         clone_info=DestroyDrawInfo(clone_info);
00705       }
00706     (void) SetImageProgressMonitor(montage,progress_monitor,
00707       montage->client_data);
00708     /*
00709       Copy tile to the composite.
00710     */
00711     x_offset=0;
00712     y_offset=0;
00713     if (montage_info->tile != (char *) NULL)
00714       GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
00715         &sans,&sans);
00716     x_offset+=extract_info.x;
00717     y_offset+=(long) title_offset+extract_info.y;
00718     max_height=0;
00719     for (tile=0; tile < MagickMin((long) tiles_per_page,(long) number_images); tile++)
00720     {
00721       /*
00722         Copy this tile to the composite.
00723       */
00724       image=CloneImage(image_list[tile],0,0,MagickTrue,exception);
00725       progress_monitor=SetImageProgressMonitor(image,
00726         (MagickProgressMonitor) NULL,image->client_data);
00727       width=concatenate != MagickFalse ? image->columns : extract_info.width;
00728       if (image->rows > max_height)
00729         max_height=image->rows;
00730       height=concatenate != MagickFalse ? max_height : extract_info.height;
00731       if (border_width != 0)
00732         {
00733           Image
00734             *border_image;
00735 
00736           RectangleInfo
00737             border_info;
00738 
00739           /*
00740             Put a border around the image.
00741           */
00742           border_info.width=border_width;
00743           border_info.height=border_width;
00744           if (montage_info->frame != (char *) NULL)
00745             {
00746               border_info.width=(width-image->columns+1)/2;
00747               border_info.height=(height-image->rows+1)/2;
00748             }
00749           border_image=BorderImage(image,&border_info,exception);
00750           if (border_image != (Image *) NULL)
00751             {
00752               image=DestroyImage(image);
00753               image=border_image;
00754             }
00755           if ((montage_info->frame != (char *) NULL) &&
00756               (image->compose == DstOutCompositeOp))
00757             (void) NegateImageChannel(image,OpacityChannel,MagickFalse);
00758         }
00759       /*
00760         Gravitate as specified by the tile gravity.
00761       */
00762       tile_image->columns=width;
00763       tile_image->rows=height;
00764       tile_image->gravity=montage_info->gravity;
00765       if (image->gravity != UndefinedGravity)
00766         tile_image->gravity=image->gravity;
00767       (void) FormatMagickString(tile_geometry,MaxTextExtent,"%lux%lu+0+0",
00768         image->columns,image->rows);
00769       flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception);
00770       x=(long) (geometry.x+border_width);
00771       y=(long) (geometry.y+border_width);
00772       if ((montage_info->frame != (char *) NULL) && (bevel_width != 0))
00773         {
00774           FrameInfo
00775             extract_info;
00776 
00777           Image
00778             *frame_image;
00779 
00780           /*
00781             Put an ornamental border around this tile.
00782           */
00783           extract_info=frame_info;
00784           extract_info.width=width+2*frame_info.width;
00785           extract_info.height=height+2*frame_info.height;
00786           value=GetImageProperty(image,"label");
00787           if (value != (const char *) NULL)
00788             extract_info.height+=(unsigned long) ((metrics.ascent-
00789               metrics.descent+4)*MultilineCensus(value));
00790           frame_image=FrameImage(image,&extract_info,exception);
00791           if (frame_image != (Image *) NULL)
00792             {
00793               image=DestroyImage(image);
00794               image=frame_image;
00795             }
00796           x=0;
00797           y=0;
00798         }
00799       if (LocaleCompare(image->magick,"NULL") != 0)
00800         {
00801           /*
00802             Composite background with tile.
00803           */
00804           if (montage_info->shadow != MagickFalse)
00805             {
00806               Image
00807                 *shadow_image;
00808 
00809               /*
00810                 Shadow image.
00811               */
00812               (void) QueryColorDatabase("#000000",&image->background_color,
00813                 exception);
00814               shadow_image=ShadowImage(image,80.0,2.0,5,5,exception);
00815               if (shadow_image != (Image *) NULL)
00816                 {
00817                   InheritException(&shadow_image->exception,exception);
00818                   (void) CompositeImage(shadow_image,OverCompositeOp,image,0,0);
00819                   image=DestroyImage(image);
00820                   image=shadow_image;
00821                 }
00822           }
00823           (void) CompositeImage(montage,OverCompositeOp,image,x_offset+x,
00824             y_offset+y);
00825           value=GetImageProperty(image,"label");
00826           if (value != (const char *) NULL)
00827             {
00828               char
00829                 geometry[MaxTextExtent];
00830 
00831               /*
00832                 Annotate composite tile with label.
00833               */
00834               (void) FormatMagickString(geometry,MaxTextExtent,
00835                 "%lux%lu%+ld%+ld",(montage_info->frame ? image->columns :
00836                 width)-2*border_width,(unsigned long) (metrics.ascent-
00837                 metrics.descent+4)*MultilineCensus(value),x_offset+
00838                 border_width,(montage_info->frame ? y_offset+height+
00839                 border_width+4 : y_offset+extract_info.height+border_width+
00840                 (montage_info->shadow != MagickFalse ? 4 : 0)));
00841               (void) CloneString(&draw_info->geometry,geometry);
00842               (void) CloneString(&draw_info->text,value);
00843               (void) AnnotateImage(montage,draw_info);
00844             }
00845         }
00846       x_offset+=width+(extract_info.x+border_width)*2;
00847       if (((tile+1) == (long) tiles_per_page) ||
00848           (((tile+1) % tiles_per_row) == 0))
00849         {
00850           x_offset=extract_info.x;
00851           y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+
00852             (metrics.ascent-metrics.descent+4)*number_lines+
00853             (montage_info->shadow != MagickFalse ? 4 : 0));
00854           max_height=0;
00855         }
00856       if ((images->progress_monitor != (MagickProgressMonitor) NULL) &&
00857           (QuantumTick(tiles,total_tiles) != MagickFalse))
00858         {
00859           status=images->progress_monitor(MontageImageTag,tiles,total_tiles,
00860             images->client_data);
00861           if (status == MagickFalse)
00862             break;
00863         }
00864       image_list[tile]=DestroyImage(image_list[tile]);
00865       image=DestroyImage(image);
00866       tiles++;
00867     }
00868     if ((i+1) < (long) images_per_page)
00869       {
00870         /*
00871           Allocate next image structure.
00872         */
00873         AcquireNextImage(clone_info,montage);
00874         if (GetNextImageInList(montage) == (Image *) NULL)
00875           {
00876             montage=DestroyImageList(montage);
00877             return((Image *) NULL);
00878           }
00879         montage=GetNextImageInList(montage);
00880         image_list+=tiles_per_page;
00881         number_images-=tiles_per_page;
00882       }
00883   }
00884   tile_image=DestroyImage(tile_image);
00885   if (texture != (Image *) NULL)
00886     texture=DestroyImage(texture);
00887   master_list=(Image **) RelinquishMagickMemory(master_list);
00888   draw_info=DestroyDrawInfo(draw_info);
00889   clone_info=DestroyImageInfo(clone_info);
00890   while (GetPreviousImageInList(montage) != (Image *) NULL)
00891     montage=GetPreviousImageInList(montage);
00892   return(montage);
00893 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1