image.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                     IIIII  M   M   AAA    GGGG  EEEEE                       %
00007 %                       I    MM MM  A   A  G      E                           %
00008 %                       I    M M M  AAAAA  G  GG  EEE                         %
00009 %                       I    M   M  A   A  G   G  E                           %
00010 %                     IIIII  M   M  A   A   GGGG  EEEEE                       %
00011 %                                                                             %
00012 %                                                                             %
00013 %                           MagickCore Image Methods                          %
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/animate.h"
00045 #include "magick/artifact.h"
00046 #include "magick/blob.h"
00047 #include "magick/blob-private.h"
00048 #include "magick/cache.h"
00049 #include "magick/cache-private.h"
00050 #include "magick/cache-view.h"
00051 #include "magick/client.h"
00052 #include "magick/color.h"
00053 #include "magick/color-private.h"
00054 #include "magick/colorspace.h"
00055 #include "magick/colorspace-private.h"
00056 #include "magick/composite.h"
00057 #include "magick/composite-private.h"
00058 #include "magick/compress.h"
00059 #include "magick/constitute.h"
00060 #include "magick/deprecate.h"
00061 #include "magick/display.h"
00062 #include "magick/draw.h"
00063 #include "magick/enhance.h"
00064 #include "magick/exception.h"
00065 #include "magick/exception-private.h"
00066 #include "magick/gem.h"
00067 #include "magick/geometry.h"
00068 #include "magick/list.h"
00069 #include "magick/image-private.h"
00070 #include "magick/magic.h"
00071 #include "magick/magick.h"
00072 #include "magick/memory_.h"
00073 #include "magick/module.h"
00074 #include "magick/monitor.h"
00075 #include "magick/monitor-private.h"
00076 #include "magick/option.h"
00077 #include "magick/paint.h"
00078 #include "magick/pixel-private.h"
00079 #include "magick/profile.h"
00080 #include "magick/property.h"
00081 #include "magick/quantize.h"
00082 #include "magick/random_.h"
00083 #include "magick/segment.h"
00084 #include "magick/semaphore.h"
00085 #include "magick/signature-private.h"
00086 #include "magick/statistic.h"
00087 #include "magick/string_.h"
00088 #include "magick/threshold.h"
00089 #include "magick/timer.h"
00090 #include "magick/utility.h"
00091 #include "magick/version.h"
00092 #include "magick/xwindow-private.h"
00093 
00094 /*
00095   Constant declaration.
00096 */
00097 const char
00098   *BackgroundColor = "#ffffff",  /* white */
00099   *BorderColor = "#dfdfdf",  /* gray */
00100   *DefaultTileFrame = "15x15+3+3",
00101   *DefaultTileGeometry = "120x120+4+3>",
00102   *DefaultTileLabel = "%f\n%wx%h\n%b",
00103   *ForegroundColor = "#000",  /* black */
00104   *LoadImageTag = "Load/Image",
00105   *LoadImagesTag = "Load/Images",
00106   *MatteColor = "#bdbdbd",  /* gray */
00107   *PSDensityGeometry = "72.0x72.0",
00108   *PSPageGeometry = "612x792",
00109   *SaveImageTag = "Save/Image",
00110   *SaveImagesTag = "Save/Images",
00111   *TransparentColor = "#00000000";  /* transparent black */
00112 
00113 const double
00114   DefaultResolution = 72.0;
00115 
00116 /*
00117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00118 %                                                                             %
00119 %                                                                             %
00120 %                                                                             %
00121 %   A c q u i r e I m a g e                                                   %
00122 %                                                                             %
00123 %                                                                             %
00124 %                                                                             %
00125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00126 %
00127 %  AcquireImage() returns a pointer to an image structure initialized to
00128 %  default values.
00129 %
00130 %  The format of the AcquireImage method is:
00131 %
00132 %      Image *AcquireImage(const ImageInfo *image_info)
00133 %
00134 %  A description of each parameter follows:
00135 %
00136 %    o image_info: Many of the image default values are set from this
00137 %      structure.  For example, filename, compression, depth, background color,
00138 %      and others.
00139 %
00140 */
00141 MagickExport Image *AcquireImage(const ImageInfo *image_info)
00142 {
00143   const char
00144     *option;
00145 
00146   Image
00147     *image;
00148 
00149   MagickStatusType
00150     flags;
00151 
00152   /*
00153     Allocate image structure.
00154   */
00155   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00156   image=(Image *) AcquireMagickMemory(sizeof(*image));
00157   if (image == (Image *) NULL)
00158     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00159   (void) ResetMagickMemory(image,0,sizeof(*image));
00160   /*
00161     Initialize Image structure.
00162   */
00163   (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
00164   image->storage_class=DirectClass;
00165   image->depth=MAGICKCORE_QUANTUM_DEPTH;
00166   image->colorspace=RGBColorspace;
00167   image->interlace=NoInterlace;
00168   image->ticks_per_second=UndefinedTicksPerSecond;
00169   image->compose=OverCompositeOp;
00170   image->blur=1.0;
00171   GetExceptionInfo(&image->exception);
00172   (void) QueryColorDatabase(BackgroundColor,&image->background_color,
00173     &image->exception);
00174   (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
00175   (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
00176   (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
00177     &image->exception);
00178   image->x_resolution=DefaultResolution;
00179   image->y_resolution=DefaultResolution;
00180   image->units=PixelsPerInchResolution;
00181   GetTimerInfo(&image->timer);
00182   (void) GetCacheInfo(&image->cache);
00183   image->blob=CloneBlobInfo((BlobInfo *) NULL);
00184   image->debug=IsEventLogging();
00185   image->reference_count=1;
00186   image->semaphore=AllocateSemaphoreInfo();
00187   image->signature=MagickSignature;
00188   if (image_info == (ImageInfo *) NULL)
00189     return(image);
00190   /*
00191     Transfer image info.
00192   */
00193   SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
00194     MagickFalse);
00195   (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
00196   (void) CopyMagickString(image->magick_filename,image_info->filename,
00197     MaxTextExtent);
00198   (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
00199   if (image_info->size != (char *) NULL)
00200     {
00201       (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
00202       image->columns=image->extract_info.width;
00203       image->rows=image->extract_info.height;
00204       image->offset=image->extract_info.x;
00205       image->extract_info.x=0;
00206       image->extract_info.y=0;
00207     }
00208   if (image_info->extract != (char *) NULL)
00209     {
00210       RectangleInfo
00211         geometry;
00212 
00213       flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
00214       if (((flags & XValue) != 0) || ((flags & YValue) != 0))
00215         {
00216           image->extract_info=geometry;
00217           Swap(image->columns,image->extract_info.width);
00218           Swap(image->rows,image->extract_info.height);
00219         }
00220     }
00221   image->compression=image_info->compression;
00222   image->quality=image_info->quality;
00223   image->endian=image_info->endian;
00224   image->interlace=image_info->interlace;
00225   image->units=image_info->units;
00226   if (image_info->density != (char *) NULL)
00227     {
00228       GeometryInfo
00229         geometry_info;
00230 
00231       flags=ParseGeometry(image_info->density,&geometry_info);
00232       image->x_resolution=geometry_info.rho;
00233       image->y_resolution=geometry_info.sigma;
00234       if ((flags & SigmaValue) == 0)
00235         image->y_resolution=image->x_resolution;
00236     }
00237   if (image_info->page != (char *) NULL)
00238     {
00239       char
00240         *geometry;
00241 
00242       image->page=image->extract_info;
00243       geometry=GetPageGeometry(image_info->page);
00244       (void) ParseAbsoluteGeometry(geometry,&image->page);
00245       geometry=DestroyString(geometry);
00246     }
00247   if (image_info->depth != 0)
00248     image->depth=image_info->depth;
00249   image->dither=image_info->dither;
00250   image->background_color=image_info->background_color;
00251   image->border_color=image_info->border_color;
00252   image->matte_color=image_info->matte_color;
00253   image->transparent_color=image_info->transparent_color;
00254   option=GetImageOption(image_info,"tile-offset");
00255   if (option != (const char *) NULL)
00256     {
00257       char
00258         *geometry;
00259 
00260       geometry=GetPageGeometry(option);
00261       flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
00262       geometry=DestroyString(geometry);
00263     }
00264   image->progress_monitor=image_info->progress_monitor;
00265   image->client_data=image_info->client_data;
00266   if (image_info->cache != (void *) NULL)
00267     CloneCacheMethods(image->cache,image_info->cache);
00268   (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
00269   return(image);
00270 }
00271 
00272 /*
00273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00274 %                                                                             %
00275 %                                                                             %
00276 %                                                                             %
00277 %   A c q u i r e I m a g e C o l o r m a p                                   %
00278 %                                                                             %
00279 %                                                                             %
00280 %                                                                             %
00281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00282 %
00283 %  AcquireImageColormap() allocates an image colormap and initializes
00284 %  it to a linear gray colorspace.  If the image already has a colormap,
00285 %  it is replaced.  AcquireImageColormap() returns MagickTrue if successful,
00286 %  otherwise MagickFalse if there is not enough memory.
00287 %
00288 %  The format of the AcquireImageColormap method is:
00289 %
00290 %      MagickBooleanType AcquireImageColormap(Image *image,
00291 %        const unsigned long colors)
00292 %
00293 %  A description of each parameter follows:
00294 %
00295 %    o image: the image.
00296 %
00297 %    o colors: the number of colors in the image colormap.
00298 %
00299 */
00300 
00301 static inline unsigned long MagickMax(const unsigned long x,
00302   const unsigned long y)
00303 {
00304   if (x > y)
00305     return(x);
00306   return(y);
00307 }
00308 
00309 static inline unsigned long MagickMin(const unsigned long x,
00310   const unsigned long y)
00311 {
00312   if (x < y)
00313     return(x);
00314   return(y);
00315 }
00316 
00317 MagickExport MagickBooleanType AcquireImageColormap(Image *image,
00318   const unsigned long colors)
00319 {
00320   register long
00321     i;
00322 
00323   size_t
00324     length;
00325 
00326   /*
00327     Allocate image colormap.
00328   */
00329   assert(image != (Image *) NULL);
00330   assert(image->signature == MagickSignature);
00331   if (image->debug != MagickFalse)
00332     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00333   image->colors=MagickMin(colors,MaxColormapSize);
00334   length=(size_t) colors;
00335   if (image->colormap == (PixelPacket *) NULL)
00336     image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
00337       sizeof(*image->colormap));
00338   else
00339     image->colormap=(PixelPacket *) ResizeQuantumMemory(image->colormap,length,
00340       sizeof(*image->colormap));
00341   if (image->colormap == (PixelPacket *) NULL)
00342     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00343       image->filename);
00344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00345   #pragma omp parallel for
00346 #endif
00347   for (i=0; i < (long) image->colors; i++)
00348   {
00349     unsigned long
00350       pixel;
00351 
00352     pixel=(unsigned long) (i*(QuantumRange/MagickMax(colors-1,1)));
00353     image->colormap[i].red=(Quantum) pixel;
00354     image->colormap[i].green=(Quantum) pixel;
00355     image->colormap[i].blue=(Quantum) pixel;
00356     image->colormap[i].opacity=OpaqueOpacity;
00357   }
00358   return(SetImageStorageClass(image,PseudoClass));
00359 }
00360 
00361 /*
00362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00363 %                                                                             %
00364 %                                                                             %
00365 %                                                                             %
00366 %   A c q u i r e I m a g e I n f o                                           %
00367 %                                                                             %
00368 %                                                                             %
00369 %                                                                             %
00370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00371 %
00372 %  AcquireImageInfo() allocates the ImageInfo structure.
00373 %
00374 %  The format of the AcquireImageInfo method is:
00375 %
00376 %      ImageInfo *AcquireImageInfo(void)
00377 %
00378 */
00379 MagickExport ImageInfo *AcquireImageInfo(void)
00380 {
00381   ImageInfo
00382     *image_info;
00383 
00384   image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
00385   if (image_info == (ImageInfo *) NULL)
00386     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00387   GetImageInfo(image_info);
00388   return(image_info);
00389 }
00390 
00391 /*
00392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00393 %                                                                             %
00394 %                                                                             %
00395 %                                                                             %
00396 %   A c q u i r e N e x t I m a g e                                           %
00397 %                                                                             %
00398 %                                                                             %
00399 %                                                                             %
00400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00401 %
00402 %  AcquireNextImage() initializes the next image in a sequence to
00403 %  default values.  The next member of image points to the newly allocated
00404 %  image.  If there is a memory shortage, next is assigned NULL.
00405 %
00406 %  The format of the AcquireNextImage method is:
00407 %
00408 %      void AcquireNextImage(const ImageInfo *image_info,Image *image)
00409 %
00410 %  A description of each parameter follows:
00411 %
00412 %    o image_info: Many of the image default values are set from this
00413 %      structure.  For example, filename, compression, depth, background color,
00414 %      and others.
00415 %
00416 %    o image: the image.
00417 %
00418 */
00419 MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
00420 {
00421   /*
00422     Allocate image structure.
00423   */
00424   assert(image != (Image *) NULL);
00425   assert(image->signature == MagickSignature);
00426   if (image->debug != MagickFalse)
00427     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00428   image->next=AcquireImage(image_info);
00429   if (GetNextImageInList(image) == (Image *) NULL)
00430     return;
00431   (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
00432     MaxTextExtent);
00433   if (image_info != (ImageInfo *) NULL)
00434     (void) CopyMagickString(GetNextImageInList(image)->filename,
00435       image_info->filename,MaxTextExtent);
00436   DestroyBlob(GetNextImageInList(image));
00437   image->next->blob=ReferenceBlob(image->blob);
00438   image->next->endian=image->endian;
00439   image->next->scene=image->scene+1;
00440   image->next->previous=image;
00441 }
00442 
00443 /*
00444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00445 %                                                                             %
00446 %                                                                             %
00447 %                                                                             %
00448 %     A p p e n d I m a g e s                                                 %
00449 %                                                                             %
00450 %                                                                             %
00451 %                                                                             %
00452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00453 %
00454 %  AppendImages() takes all images from the current image pointer to the end
00455 %  of the image list and appends them to each other top-to-bottom if the
00456 %  stack parameter is true, otherwise left-to-right.
00457 %
00458 %  The format of the AppendImage method is:
00459 %
00460 %      Image *AppendImages(const Image *image,const MagickBooleanType stack,
00461 %        ExceptionInfo *exception)
00462 %
00463 %  A description of each parameter follows:
00464 %
00465 %    o image: the image sequence.
00466 %
00467 %    o stack: A value other than 0 stacks the images top-to-bottom.
00468 %
00469 %    o exception: return any errors or warnings in this structure.
00470 %
00471 */
00472 MagickExport Image *AppendImages(const Image *image,
00473   const MagickBooleanType stack,ExceptionInfo *exception)
00474 {
00475 #define AppendImageTag  "Append/Image"
00476 
00477   Image
00478     *append_image;
00479 
00480   long
00481     n,
00482     y;
00483 
00484   MagickBooleanType
00485     matte,
00486     proceed,
00487     status;
00488 
00489   register const Image
00490     *next;
00491 
00492   register long
00493     i;
00494 
00495   unsigned long
00496     height,
00497     number_images,
00498     width;
00499 
00500   ViewInfo
00501     **append_view,
00502     **image_view;
00503 
00504   /*
00505     Ensure the image have the same column width.
00506   */
00507   assert(image != (Image *) NULL);
00508   assert(image->signature == MagickSignature);
00509   if (image->debug != MagickFalse)
00510     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00511   assert(exception != (ExceptionInfo *) NULL);
00512   assert(exception->signature == MagickSignature);
00513   matte=image->matte;
00514   number_images=1;
00515   width=image->columns;
00516   height=image->rows;
00517   next=GetNextImageInList(image);
00518   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
00519   {
00520     if (next->matte != MagickFalse)
00521       matte=MagickTrue;
00522     number_images++;
00523     if (stack != MagickFalse)
00524       {
00525         if (next->columns > width)
00526           width=next->columns;
00527         height+=next->rows;
00528         continue;
00529       }
00530     width+=next->columns;
00531     if (next->rows > height)
00532       height=next->rows;
00533   }
00534   /*
00535     Initialize append next attributes.
00536   */
00537   append_image=CloneImage(image,width,height,MagickTrue,exception);
00538   if (append_image == (Image *) NULL)
00539     return((Image *) NULL);
00540   if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
00541     {
00542       InheritException(exception,&append_image->exception);
00543       append_image=DestroyImage(append_image);
00544       return((Image *) NULL);
00545     }
00546   append_image->matte=matte;
00547   (void) SetImageBackgroundColor(append_image);
00548   status=MagickTrue;
00549   i=0;
00550   append_view=AcquireCacheViewThreadSet(append_image);
00551   if (stack != MagickFalse)
00552     {
00553       /*
00554         Stack top-to-bottom.
00555       */
00556       for (n=0; n < (long) number_images; n++)
00557       {
00558         image_view=AcquireCacheViewThreadSet(image);
00559 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00560         #pragma omp parallel for schedule(dynamic,8) shared(status)
00561 #endif
00562         for (y=0; y < (long) image->rows; y++)
00563         {
00564           const IndexPacket
00565             *indexes;
00566 
00567           IndexPacket
00568             *append_indexes;
00569 
00570           MagickBooleanType
00571             sync;
00572 
00573           register const PixelPacket
00574             *p;
00575 
00576           register long
00577             id,
00578             x;
00579 
00580           register PixelPacket
00581             *q;
00582 
00583           if (status == MagickFalse)
00584             continue;
00585           id=GetCacheViewThreadId();
00586           p=GetCacheViewVirtualPixels(image_view[id],0,y,image->columns,1,
00587             exception);
00588           q=QueueCacheViewAuthenticPixels(append_view[id],0,i+y,
00589             append_image->columns,1,exception);
00590           if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00591             {
00592               status=MagickFalse;
00593               continue;
00594             }
00595           indexes=GetCacheViewVirtualIndexes(image_view[id]);
00596           append_indexes=GetCacheViewAuthenticIndexes(append_view[id]);
00597           for (x=0; x < (long) image->columns; x++)
00598           {
00599             q->red=p->red;
00600             q->green=p->green;
00601             q->blue=p->blue;
00602             q->opacity=p->opacity;
00603             if (append_image->colorspace == CMYKColorspace)
00604               append_indexes[x]=indexes[x];
00605             p++;
00606             q++;
00607           }
00608           sync=SyncCacheViewAuthenticPixels(append_view[id],exception);
00609           if (sync == MagickFalse)
00610             continue;
00611         }
00612         image_view=DestroyCacheViewThreadSet(image_view);
00613         proceed=SetImageProgress(image,AppendImageTag,n,number_images);
00614         if (proceed == MagickFalse)
00615           break;
00616         i+=image->rows;
00617         image=GetNextImageInList(image);
00618       }
00619       append_view=DestroyCacheViewThreadSet(append_view);
00620       if (status == MagickFalse)
00621         append_image=DestroyImage(append_image);
00622       return(append_image);
00623     }
00624   /*
00625     Stack left-to-right.
00626   */
00627   for (n=0; n < (long) number_images; n++)
00628   {
00629     image_view=AcquireCacheViewThreadSet(image);
00630 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00631     #pragma omp parallel for schedule(dynamic,8) shared(status)
00632 #endif
00633     for (y=0; y < (long) image->rows; y++)
00634     {
00635       const IndexPacket
00636         *indexes;
00637 
00638       IndexPacket
00639         *append_indexes;
00640 
00641       MagickBooleanType
00642         sync;
00643 
00644       register const PixelPacket
00645         *p;
00646 
00647       register long
00648         id,
00649         x;
00650 
00651       register PixelPacket
00652         *q;
00653 
00654       if (status == MagickFalse)
00655         continue;
00656       id=GetCacheViewThreadId();
00657       p=GetCacheViewVirtualPixels(image_view[id],0,y,image->columns,1,
00658         exception);
00659       q=QueueCacheViewAuthenticPixels(append_view[id],i,y,image->columns,1,
00660         exception);
00661       if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00662         {
00663           status=MagickFalse;
00664           continue;
00665         }
00666       indexes=GetCacheViewVirtualIndexes(image_view[id]);
00667       append_indexes=GetCacheViewAuthenticIndexes(append_view[id]);
00668       for (x=0; x < (long) image->columns; x++)
00669       {
00670         q->red=p->red;
00671         q->green=p->green;
00672         q->blue=p->blue;
00673         q->opacity=p->opacity;
00674         if (append_image->colorspace == CMYKColorspace)
00675           append_indexes[x]=indexes[x];
00676         p++;
00677         q++;
00678       }
00679       sync=SyncCacheViewAuthenticPixels(append_view[id],exception);
00680       if (sync == MagickFalse)
00681         continue;
00682     }
00683     image_view=DestroyCacheViewThreadSet(image_view);
00684     proceed=SetImageProgress(image,AppendImageTag,n,number_images);
00685     if (proceed == MagickFalse)
00686       break;
00687     i+=image->columns;
00688     image=GetNextImageInList(image);
00689   }
00690   append_view=DestroyCacheViewThreadSet(append_view);
00691   if (status == MagickFalse)
00692     append_image=DestroyImage(append_image);
00693   return(append_image);
00694 }
00695 
00696 /*
00697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00698 %                                                                             %
00699 %                                                                             %
00700 %                                                                             %
00701 %     A v e r a g e I m a g e s                                               %
00702 %                                                                             %
00703 %                                                                             %
00704 %                                                                             %
00705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00706 %
00707 %  AverageImages() takes a set of images and averages them together.  Each
00708 %  image in the set must have the same width and height.  AverageImages()
00709 %  returns a single image with each corresponding pixel component of each
00710 %  image averaged.   On failure, a NULL image is returned and exception
00711 %  describes the reason for the failure.
00712 %
00713 %  The format of the AverageImages method is:
00714 %
00715 %      Image *AverageImages(Image *image,ExceptionInfo *exception)
00716 %
00717 %  A description of each parameter follows:
00718 %
00719 %    o image: the image sequence.
00720 %
00721 %    o exception: return any errors or warnings in this structure.
00722 %
00723 */
00724 
00725 static MagickPixelPacket **DestroyPixelThreadSet(MagickPixelPacket **pixels)
00726 {
00727   register long
00728     i;
00729 
00730   assert(pixels != (MagickPixelPacket **) NULL);
00731   for (i=0; i < (long) GetCacheViewMaximumThreads(); i++)
00732     if (pixels[i] != (MagickPixelPacket *) NULL)
00733       pixels[i]=(MagickPixelPacket *) RelinquishMagickMemory(pixels[i]);
00734   return((MagickPixelPacket **) RelinquishMagickMemory(pixels));
00735 }
00736 
00737 static MagickPixelPacket **AcquirePixelThreadSet(const Image *image)
00738 {
00739   register long
00740     i,
00741     j;
00742 
00743   MagickPixelPacket
00744     **pixels;
00745 
00746   pixels=(MagickPixelPacket **) AcquireQuantumMemory(
00747     GetCacheViewMaximumThreads(),sizeof(*pixels));
00748   if (pixels == (MagickPixelPacket **) NULL)
00749     return((MagickPixelPacket **) NULL);
00750   (void) ResetMagickMemory(pixels,0,GetCacheViewMaximumThreads()*
00751     sizeof(*pixels));
00752   for (i=0; i < (long) GetCacheViewMaximumThreads(); i++)
00753   {
00754     pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(image->columns,
00755       sizeof(**pixels));
00756     if (pixels[i] == (MagickPixelPacket *) NULL)
00757       return(DestroyPixelThreadSet(pixels));
00758     for (j=0; j < (long) image->columns; j++)
00759       GetMagickPixelPacket(image,&pixels[i][j]);
00760   }
00761   return(pixels);
00762 }
00763 
00764 MagickExport Image *AverageImages(const Image *image,ExceptionInfo *exception)
00765 {
00766 #define AverageImageTag  "Average/Image"
00767 
00768   const Image
00769     *next;
00770 
00771   Image
00772     *average_image;
00773 
00774   long
00775     progress,
00776     y;
00777 
00778   MagickBooleanType
00779     status;
00780 
00781   MagickPixelPacket
00782     **average_pixel,
00783     zero;
00784 
00785   unsigned long
00786     number_images;
00787 
00788   ViewInfo
00789     **average_view;
00790 
00791   /*
00792     Ensure the image are the same size.
00793   */
00794   assert(image != (Image *) NULL);
00795   assert(image->signature == MagickSignature);
00796   if (image->debug != MagickFalse)
00797     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00798   assert(exception != (ExceptionInfo *) NULL);
00799   assert(exception->signature == MagickSignature);
00800   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
00801     if ((next->columns != image->columns) || (next->rows != image->rows))
00802       ThrowImageException(OptionError,"ImageWidthsOrHeightsDiffer");
00803   /*
00804     Initialize average next attributes.
00805   */
00806   average_image=CloneImage(image,image->columns,image->rows,MagickTrue,
00807     exception);
00808   if (average_image == (Image *) NULL)
00809     return((Image *) NULL);
00810   if (SetImageStorageClass(average_image,DirectClass) == MagickFalse)
00811     {
00812       InheritException(exception,&average_image->exception);
00813       average_image=DestroyImage(average_image);
00814       return((Image *) NULL);
00815     }
00816   average_pixel=AcquirePixelThreadSet(image);
00817   if (average_pixel == (MagickPixelPacket **) NULL)
00818     {
00819       average_image=DestroyImage(average_image);
00820       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00821     }
00822   /*
00823     Average image pixels.
00824   */
00825   status=MagickTrue;
00826   progress=0;
00827   GetMagickPixelPacket(image,&zero);
00828   number_images=GetImageListLength(image);
00829   average_view=AcquireCacheViewThreadSet(average_image);
00830 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00831   #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00832 #endif
00833   for (y=0; y < (long) average_image->rows; y++)
00834   {
00835     const Image
00836       *next;
00837 
00838     IndexPacket
00839       *average_indexes;
00840 
00841     MagickPixelPacket
00842       pixel;
00843 
00844     register long
00845       i,
00846       id,
00847       x;
00848 
00849     register PixelPacket
00850       *q;
00851 
00852     ViewInfo
00853       *image_view;
00854 
00855     if (status == MagickFalse)
00856       continue;
00857     id=GetCacheViewThreadId();
00858     q=QueueCacheViewAuthenticPixels(average_view[id],0,y,average_image->columns,
00859       1,exception);
00860     if (q == (PixelPacket *) NULL)
00861       {
00862         status=MagickFalse;
00863         continue;
00864       }
00865     pixel=zero;
00866     average_indexes=GetCacheViewAuthenticIndexes(average_view[id]);
00867     for (x=0; x < (long) average_image->columns; x++)
00868       average_pixel[id][x]=zero;
00869     next=image;
00870     for (i=0; i < (long) number_images; i++)
00871     {
00872       register const IndexPacket
00873         *indexes;
00874 
00875       register const PixelPacket
00876         *p;
00877 
00878       image_view=AcquireCacheView(next);
00879       p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
00880       if (p == (const PixelPacket *) NULL)
00881         {
00882           image_view=DestroyCacheView(image_view);
00883           break;
00884         }
00885       indexes=GetCacheViewVirtualIndexes(image_view);
00886       for (x=0; x < (long) next->columns; x++)
00887       {
00888         SetMagickPixelPacket(next,p,indexes+x,&pixel);
00889         average_pixel[id][x].red+=QuantumScale*pixel.red;
00890         average_pixel[id][x].green+=QuantumScale*pixel.green;
00891         average_pixel[id][x].blue+=QuantumScale*pixel.blue;
00892         average_pixel[id][x].opacity+=QuantumScale*pixel.opacity;
00893         if (average_image->colorspace == CMYKColorspace)
00894           average_pixel[id][x].index+=QuantumScale*pixel.index;
00895         p++;
00896       }
00897       image_view=DestroyCacheView(image_view);
00898       next=GetNextImageInList(next);
00899     }
00900     for (x=0; x < (long) average_image->columns; x++)
00901     {
00902       average_pixel[id][x].red=(MagickRealType) QuantumRange*
00903         average_pixel[id][x].red/number_images;
00904       average_pixel[id][x].green=(MagickRealType) QuantumRange*
00905         average_pixel[id][x].green/number_images;
00906       average_pixel[id][x].blue=(MagickRealType) QuantumRange*
00907         average_pixel[id][x].blue/number_images;
00908       average_pixel[id][x].opacity=(MagickRealType) QuantumRange*
00909         average_pixel[id][x].opacity/number_images;
00910       if (average_image->colorspace == CMYKColorspace)
00911         average_pixel[id][x].index=(MagickRealType) QuantumRange*
00912           average_pixel[id][x].index/number_images;
00913       SetPixelPacket(average_image,&average_pixel[id][x],q,average_indexes+x);
00914       q++;
00915     }
00916     if (SyncCacheViewAuthenticPixels(average_view[id],exception) == MagickFalse)
00917       status=MagickFalse;
00918     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00919       {
00920         MagickBooleanType
00921           proceed;
00922 
00923 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00924         #pragma omp critical
00925 #endif
00926         proceed=SetImageProgress(image,AverageImageTag,progress++,
00927           average_image->rows);
00928         if (proceed == MagickFalse)
00929           status=MagickFalse;
00930       }
00931   }
00932   average_view=DestroyCacheViewThreadSet(average_view);
00933   average_pixel=DestroyPixelThreadSet(average_pixel);
00934   if (status == MagickFalse)
00935     average_image=DestroyImage(average_image);
00936   return(average_image);
00937 }
00938 
00939 /*
00940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00941 %                                                                             %
00942 %                                                                             %
00943 %                                                                             %
00944 %   C a t c h I m a g e E x c e p t i o n                                     %
00945 %                                                                             %
00946 %                                                                             %
00947 %                                                                             %
00948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00949 %
00950 %  CatchImageException() returns if no exceptions are found in the image
00951 %  sequence, otherwise it determines the most severe exception and reports
00952 %  it as a warning or error depending on the severity.
00953 %
00954 %  The format of the CatchImageException method is:
00955 %
00956 %      ExceptionType CatchImageException(Image *image)
00957 %
00958 %  A description of each parameter follows:
00959 %
00960 %    o image: An image sequence.
00961 %
00962 */
00963 MagickExport ExceptionType CatchImageException(Image *image)
00964 {
00965   ExceptionInfo
00966     *exception;
00967 
00968   ExceptionType
00969     severity;
00970 
00971   assert(image != (const Image *) NULL);
00972   assert(image->signature == MagickSignature);
00973   if (image->debug != MagickFalse)
00974     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->