MagickCore  6.7.5
transform.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %       TTTTT  RRRR    AAA   N   N  SSSSS  FFFFF   OOO   RRRR   M   M         %
00007 %         T    R   R  A   A  NN  N  SS     F      O   O  R   R  MM MM         %
00008 %         T    RRRR   AAAAA  N N N   SSS   FFF    O   O  RRRR   M M M         %
00009 %         T    R R    A   A  N  NN     SS  F      O   O  R R    M   M         %
00010 %         T    R  R   A   A  N   N  SSSSS  F       OOO   R  R   M   M         %
00011 %                                                                             %
00012 %                                                                             %
00013 %                    MagickCore Image Transform Methods                       %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 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   Include declarations.
00041 */
00042 #include "MagickCore/studio.h"
00043 #include "MagickCore/attribute.h"
00044 #include "MagickCore/cache.h"
00045 #include "MagickCore/cache-view.h"
00046 #include "MagickCore/color.h"
00047 #include "MagickCore/color-private.h"
00048 #include "MagickCore/colorspace-private.h"
00049 #include "MagickCore/composite.h"
00050 #include "MagickCore/draw.h"
00051 #include "MagickCore/effect.h"
00052 #include "MagickCore/exception.h"
00053 #include "MagickCore/exception-private.h"
00054 #include "MagickCore/geometry.h"
00055 #include "MagickCore/image.h"
00056 #include "MagickCore/memory_.h"
00057 #include "MagickCore/layer.h"
00058 #include "MagickCore/list.h"
00059 #include "MagickCore/monitor.h"
00060 #include "MagickCore/monitor-private.h"
00061 #include "MagickCore/pixel-accessor.h"
00062 #include "MagickCore/resource_.h"
00063 #include "MagickCore/resize.h"
00064 #include "MagickCore/statistic.h"
00065 #include "MagickCore/string_.h"
00066 #include "MagickCore/thread-private.h"
00067 #include "MagickCore/transform.h"
00068 
00069 /*
00070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00071 %                                                                             %
00072 %                                                                             %
00073 %                                                                             %
00074 %   C h o p I m a g e                                                         %
00075 %                                                                             %
00076 %                                                                             %
00077 %                                                                             %
00078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00079 %
00080 %  ChopImage() removes a region of an image and collapses the image to occupy
00081 %  the removed portion.
00082 %
00083 %  The format of the ChopImage method is:
00084 %
00085 %      Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
00086 %        ExceptionInfo *exception)
00087 %
00088 %  A description of each parameter follows:
00089 %
00090 %    o image: the image.
00091 %
00092 %    o chop_info: Define the region of the image to chop.
00093 %
00094 %    o exception: return any errors or warnings in this structure.
00095 %
00096 */
00097 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
00098   ExceptionInfo *exception)
00099 {
00100 #define ChopImageTag  "Chop/Image"
00101 
00102   CacheView
00103     *chop_view,
00104     *image_view;
00105 
00106   Image
00107     *chop_image;
00108 
00109   MagickBooleanType
00110     status;
00111 
00112   MagickOffsetType
00113     progress;
00114 
00115   RectangleInfo
00116     extent;
00117 
00118   ssize_t
00119     y;
00120 
00121   /*
00122     Check chop geometry.
00123   */
00124   assert(image != (const Image *) NULL);
00125   assert(image->signature == MagickSignature);
00126   if (image->debug != MagickFalse)
00127     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00128   assert(exception != (ExceptionInfo *) NULL);
00129   assert(exception->signature == MagickSignature);
00130   assert(chop_info != (RectangleInfo *) NULL);
00131   if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
00132       ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
00133       (chop_info->x > (ssize_t) image->columns) ||
00134       (chop_info->y > (ssize_t) image->rows))
00135     ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
00136   extent=(*chop_info);
00137   if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
00138     extent.width=(size_t) ((ssize_t) image->columns-extent.x);
00139   if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
00140     extent.height=(size_t) ((ssize_t) image->rows-extent.y);
00141   if (extent.x < 0)
00142     {
00143       extent.width-=(size_t) (-extent.x);
00144       extent.x=0;
00145     }
00146   if (extent.y < 0)
00147     {
00148       extent.height-=(size_t) (-extent.y);
00149       extent.y=0;
00150     }
00151   chop_image=CloneImage(image,image->columns-extent.width,image->rows-
00152     extent.height,MagickTrue,exception);
00153   if (chop_image == (Image *) NULL)
00154     return((Image *) NULL);
00155   /*
00156     Extract chop image.
00157   */
00158   status=MagickTrue;
00159   progress=0;
00160   image_view=AcquireCacheView(image);
00161   chop_view=AcquireCacheView(chop_image);
00162 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00163   #pragma omp parallel for schedule(static) shared(progress,status)
00164 #endif
00165   for (y=0; y < (ssize_t) extent.y; y++)
00166   {
00167     register const Quantum
00168       *restrict p;
00169 
00170     register ssize_t
00171       x;
00172 
00173     register Quantum
00174       *restrict q;
00175 
00176     if (status == MagickFalse)
00177       continue;
00178     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00179     q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
00180       exception);
00181     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00182       {
00183         status=MagickFalse;
00184         continue;
00185       }
00186     for (x=0; x < (ssize_t) image->columns; x++)
00187     {
00188       if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
00189         {
00190           register ssize_t
00191             i;
00192 
00193           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00194           {
00195             PixelChannel
00196               channel;
00197 
00198             PixelTrait
00199               chop_traits,
00200               traits;
00201 
00202             channel=GetPixelChannelMapChannel(image,i);
00203             traits=GetPixelChannelMapTraits(image,channel);
00204             chop_traits=GetPixelChannelMapTraits(chop_image,channel);
00205             if ((traits == UndefinedPixelTrait) ||
00206                 (chop_traits == UndefinedPixelTrait))
00207               continue;
00208             SetPixelChannel(chop_image,channel,p[i],q);
00209           }
00210           q+=GetPixelChannels(chop_image);
00211         }
00212       p+=GetPixelChannels(image);
00213     }
00214     if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00215       status=MagickFalse;
00216     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00217       {
00218         MagickBooleanType
00219           proceed;
00220 
00221 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00222         #pragma omp critical (MagickCore_ChopImage)
00223 #endif
00224         proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
00225         if (proceed == MagickFalse)
00226           status=MagickFalse;
00227       }
00228   }
00229   /*
00230     Extract chop image.
00231   */
00232 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00233   #pragma omp parallel for schedule(static) shared(progress,status)
00234 #endif
00235   for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
00236   {
00237     register const Quantum
00238       *restrict p;
00239 
00240     register ssize_t
00241       x;
00242 
00243     register Quantum
00244       *restrict q;
00245 
00246     if (status == MagickFalse)
00247       continue;
00248     p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
00249       image->columns,1,exception);
00250     q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
00251       1,exception);
00252     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00253       {
00254         status=MagickFalse;
00255         continue;
00256       }
00257     for (x=0; x < (ssize_t) image->columns; x++)
00258     {
00259       if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
00260         {
00261           register ssize_t
00262             i;
00263 
00264           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00265           {
00266             PixelChannel
00267               channel;
00268 
00269             PixelTrait
00270               chop_traits,
00271               traits;
00272 
00273             channel=GetPixelChannelMapChannel(image,i);
00274             traits=GetPixelChannelMapTraits(image,channel);
00275             chop_traits=GetPixelChannelMapTraits(chop_image,channel);
00276             if ((traits == UndefinedPixelTrait) ||
00277                 (chop_traits == UndefinedPixelTrait))
00278               continue;
00279             SetPixelChannel(chop_image,channel,p[i],q);
00280           }
00281           p+=GetPixelChannels(chop_image);
00282           q+=GetPixelChannels(chop_image);
00283         }
00284       p+=GetPixelChannels(image);
00285     }
00286     if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00287       status=MagickFalse;
00288     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00289       {
00290         MagickBooleanType
00291           proceed;
00292 
00293 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00294         #pragma omp critical (MagickCore_ChopImage)
00295 #endif
00296         proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
00297         if (proceed == MagickFalse)
00298           status=MagickFalse;
00299       }
00300   }
00301   chop_view=DestroyCacheView(chop_view);
00302   image_view=DestroyCacheView(image_view);
00303   chop_image->type=image->type;
00304   return(chop_image);
00305 }
00306 
00307 /*
00308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00309 %                                                                             %
00310 %                                                                             %
00311 %                                                                             %
00312 +     C o n s o l i d a t e C M Y K I m a g e                                 %
00313 %                                                                             %
00314 %                                                                             %
00315 %                                                                             %
00316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00317 %
00318 %  ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
00319 %  single image.
00320 %
00321 %  The format of the ConsolidateCMYKImage method is:
00322 %
00323 %      Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
00324 %
00325 %  A description of each parameter follows:
00326 %
00327 %    o image: the image sequence.
00328 %
00329 %    o exception: return any errors or warnings in this structure.
00330 %
00331 */
00332 MagickExport Image *ConsolidateCMYKImages(const Image *images,
00333   ExceptionInfo *exception)
00334 {
00335   CacheView
00336     *cmyk_view,
00337     *image_view;
00338 
00339   Image
00340     *cmyk_image,
00341     *cmyk_images;
00342 
00343   register ssize_t
00344     j;
00345 
00346   ssize_t
00347     y;
00348 
00349   /*
00350     Consolidate separate C, M, Y, and K planes into a single image.
00351   */
00352   assert(images != (Image *) NULL);
00353   assert(images->signature == MagickSignature);
00354   if (images->debug != MagickFalse)
00355     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00356   assert(exception != (ExceptionInfo *) NULL);
00357   assert(exception->signature == MagickSignature);
00358   cmyk_images=NewImageList();
00359   for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
00360   {
00361     register ssize_t
00362       i;
00363 
00364     cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
00365       exception);
00366     if (cmyk_image == (Image *) NULL)
00367       break;
00368     if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
00369       break;
00370     (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
00371     for (i=0; i < 4; i++)
00372     {
00373       image_view=AcquireCacheView(images);
00374       cmyk_view=AcquireCacheView(cmyk_image);
00375       for (y=0; y < (ssize_t) images->rows; y++)
00376       {
00377         register const Quantum
00378           *restrict p;
00379 
00380         register ssize_t
00381           x;
00382 
00383         register Quantum
00384           *restrict q;
00385 
00386         p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
00387         q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
00388           exception);
00389         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00390           break;
00391         for (x=0; x < (ssize_t) images->columns; x++)
00392         {
00393           Quantum
00394             pixel;
00395 
00396           pixel=QuantumRange-GetPixelIntensity(images,p);
00397           switch (i)
00398           {
00399             case 0: SetPixelCyan(cmyk_image,pixel,q);  break;
00400             case 1: SetPixelMagenta(cmyk_image,pixel,q);  break;
00401             case 2: SetPixelYellow(cmyk_image,pixel,q);  break;
00402             case 3: SetPixelBlack(cmyk_image,pixel,q);  break;
00403             default: break;
00404           }
00405           p+=GetPixelChannels(images);
00406           q+=GetPixelChannels(cmyk_image);
00407         }
00408         if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
00409           break;
00410       }
00411       cmyk_view=DestroyCacheView(cmyk_view);
00412       image_view=DestroyCacheView(image_view);
00413       images=GetNextImageInList(images);
00414       if (images == (Image *) NULL)
00415         break;
00416     }
00417     AppendImageToList(&cmyk_images,cmyk_image);
00418   }
00419   return(cmyk_images);
00420 }
00421 
00422 /*
00423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00424 %                                                                             %
00425 %                                                                             %
00426 %                                                                             %
00427 %   C r o p I m a g e                                                         %
00428 %                                                                             %
00429 %                                                                             %
00430 %                                                                             %
00431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00432 %
00433 %  CropImage() extracts a region of the image starting at the offset defined
00434 %  by geometry.  Region must be fully defined, and no special handling of
00435 %  geometry flags is performed.
00436 %
00437 %  The format of the CropImage method is:
00438 %
00439 %      Image *CropImage(const Image *image,const RectangleInfo *geometry,
00440 %        ExceptionInfo *exception)
00441 %
00442 %  A description of each parameter follows:
00443 %
00444 %    o image: the image.
00445 %
00446 %    o geometry: Define the region of the image to crop with members
00447 %      x, y, width, and height.
00448 %
00449 %    o exception: return any errors or warnings in this structure.
00450 %
00451 */
00452 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
00453   ExceptionInfo *exception)
00454 {
00455 #define CropImageTag  "Crop/Image"
00456 
00457   CacheView
00458     *crop_view,
00459     *image_view;
00460 
00461   Image
00462     *crop_image;
00463 
00464   MagickBooleanType
00465     status;
00466 
00467   MagickOffsetType
00468     progress;
00469 
00470   OffsetInfo
00471     offset;
00472 
00473   RectangleInfo
00474     bounding_box,
00475     page;
00476 
00477   ssize_t
00478     y;
00479 
00480   /*
00481     Check crop geometry.
00482   */
00483   assert(image != (const Image *) NULL);
00484   assert(image->signature == MagickSignature);
00485   if (image->debug != MagickFalse)
00486     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00487   assert(geometry != (const RectangleInfo *) NULL);
00488   assert(exception != (ExceptionInfo *) NULL);
00489   assert(exception->signature == MagickSignature);
00490   bounding_box=image->page;
00491   if ((bounding_box.width == 0) || (bounding_box.height == 0))
00492     {
00493       bounding_box.width=image->columns;
00494       bounding_box.height=image->rows;
00495     }
00496   page=(*geometry);
00497   if (page.width == 0)
00498     page.width=bounding_box.width;
00499   if (page.height == 0)
00500     page.height=bounding_box.height;
00501   if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
00502       ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
00503       ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
00504       ((page.y-bounding_box.y) > (ssize_t) image->rows))
00505     {
00506       /*
00507         Crop is not within virtual canvas, return 1 pixel transparent image.
00508       */
00509       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00510         "GeometryDoesNotContainImage","`%s'",image->filename);
00511       crop_image=CloneImage(image,1,1,MagickTrue,exception);
00512       if (crop_image == (Image *) NULL)
00513         return((Image *) NULL);
00514       crop_image->background_color.alpha=(Quantum) TransparentAlpha;
00515       (void) SetImageBackgroundColor(crop_image,exception);
00516       crop_image->page=bounding_box;
00517       crop_image->page.x=(-1);
00518       crop_image->page.y=(-1);
00519       if (crop_image->dispose == BackgroundDispose)
00520         crop_image->dispose=NoneDispose;
00521       return(crop_image);
00522     }
00523   if ((page.x < 0) && (bounding_box.x >= 0))
00524     {
00525       page.width+=page.x-bounding_box.x;
00526       page.x=0;
00527     }
00528   else
00529     {
00530       page.width-=bounding_box.x-page.x;
00531       page.x-=bounding_box.x;
00532       if (page.x < 0)
00533         page.x=0;
00534     }
00535   if ((page.y < 0) && (bounding_box.y >= 0))
00536     {
00537       page.height+=page.y-bounding_box.y;
00538       page.y=0;
00539     }
00540   else
00541     {
00542       page.height-=bounding_box.y-page.y;
00543       page.y-=bounding_box.y;
00544       if (page.y < 0)
00545         page.y=0;
00546     }
00547   if ((size_t) (page.x+page.width) > image->columns)
00548     page.width=image->columns-page.x;
00549   if ((geometry->width != 0) && (page.width > geometry->width))
00550     page.width=geometry->width;
00551   if ((size_t) (page.y+page.height) > image->rows)
00552     page.height=image->rows-page.y;
00553   if ((geometry->height != 0) && (page.height > geometry->height))
00554     page.height=geometry->height;
00555   bounding_box.x+=page.x;
00556   bounding_box.y+=page.y;
00557   if ((page.width == 0) || (page.height == 0))
00558     {
00559       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00560         "GeometryDoesNotContainImage","`%s'",image->filename);
00561       return((Image *) NULL);
00562     }
00563   /*
00564     Initialize crop image attributes.
00565   */
00566   crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
00567   if (crop_image == (Image *) NULL)
00568     return((Image *) NULL);
00569   crop_image->page.width=image->page.width;
00570   crop_image->page.height=image->page.height;
00571   offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
00572   offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
00573   if ((offset.x > (ssize_t) image->page.width) ||
00574       (offset.y > (ssize_t) image->page.height))
00575     {
00576       crop_image->page.width=bounding_box.width;
00577       crop_image->page.height=bounding_box.height;
00578     }
00579   crop_image->page.x=bounding_box.x;
00580   crop_image->page.y=bounding_box.y;
00581   /*
00582     Crop image.
00583   */
00584   status=MagickTrue;
00585   progress=0;
00586   image_view=AcquireCacheView(image);
00587   crop_view=AcquireCacheView(crop_image);
00588 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00589   #pragma omp parallel for schedule(static) shared(progress,status)
00590 #endif
00591   for (y=0; y < (ssize_t) crop_image->rows; y++)
00592   {
00593     register const Quantum
00594       *restrict p;
00595 
00596     register Quantum
00597       *restrict q;
00598 
00599     register ssize_t
00600       x;
00601 
00602     if (status == MagickFalse)
00603       continue;
00604     p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
00605       1,exception);
00606     q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
00607       exception);
00608     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00609       {
00610         status=MagickFalse;
00611         continue;
00612       }
00613     for (x=0; x < (ssize_t) crop_image->columns; x++)
00614     {
00615       register ssize_t
00616         i;
00617 
00618       if (GetPixelMask(image,p) != 0)
00619         {
00620           p+=GetPixelChannels(image);
00621           q+=GetPixelChannels(crop_image);
00622           continue;
00623         }
00624       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00625       {
00626         PixelChannel
00627           channel;
00628 
00629         PixelTrait
00630           crop_traits,
00631           traits;
00632 
00633         channel=GetPixelChannelMapChannel(image,i);
00634         traits=GetPixelChannelMapTraits(image,channel);
00635         crop_traits=GetPixelChannelMapTraits(crop_image,channel);
00636         if ((traits == UndefinedPixelTrait) ||
00637             (crop_traits == UndefinedPixelTrait))
00638           continue;
00639         SetPixelChannel(crop_image,channel,p[i],q);
00640       }
00641       p+=GetPixelChannels(image);
00642       q+=GetPixelChannels(crop_image);
00643     }
00644     if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
00645       status=MagickFalse;
00646     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00647       {
00648         MagickBooleanType
00649           proceed;
00650 
00651 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00652         #pragma omp critical (MagickCore_CropImage)
00653 #endif
00654         proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
00655         if (proceed == MagickFalse)
00656           status=MagickFalse;
00657       }
00658   }
00659   crop_view=DestroyCacheView(crop_view);
00660   image_view=DestroyCacheView(image_view);
00661   crop_image->type=image->type;
00662   if (status == MagickFalse)
00663     crop_image=DestroyImage(crop_image);
00664   return(crop_image);
00665 }
00666 
00667 /*
00668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00669 %                                                                             %
00670 %                                                                             %
00671 %                                                                             %
00672 %   C r o p I m a g e T o T i l e s                                           %
00673 %                                                                             %
00674 %                                                                             %
00675 %                                                                             %
00676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00677 %
00678 %  CropImageToTiles() crops a single image, into a possible list of tiles.
00679 %  This may include a single sub-region of the image.  This basically applies
00680 %  all the normal geometry flags for Crop.
00681 %
00682 %      Image *CropImageToTiles(const Image *image,
00683 %         const RectangleInfo *crop_geometry, ExceptionInfo *exception)
00684 %
00685 %  A description of each parameter follows:
00686 %
00687 %    o image: the image The transformed image is returned as this parameter.
00688 %
00689 %    o crop_geometry: A crop geometry string.
00690 %
00691 %    o exception: return any errors or warnings in this structure.
00692 %
00693 */
00694 
00695 static inline ssize_t MagickRound(MagickRealType x)
00696 {
00697   /*
00698     Round the fraction to nearest integer.
00699   */
00700   if (x >= 0.0)
00701     return((ssize_t) (x+0.5));
00702   return((ssize_t) (x-0.5));
00703 }
00704 
00705 MagickExport Image *CropImageToTiles(const Image *image,
00706   const char *crop_geometry, ExceptionInfo *exception)
00707 {
00708   Image
00709     *next,
00710     *crop_image;
00711 
00712   MagickStatusType
00713     flags;
00714 
00715   RectangleInfo
00716     geometry;
00717 
00718   assert(image != (Image *) NULL);
00719   assert(image->signature == MagickSignature);
00720   if (image->debug != MagickFalse)
00721     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00722   crop_image=NewImageList();
00723   next=NewImageList();
00724   flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
00725   if ((flags & AreaValue) != 0)
00726     {
00727       PointInfo
00728         delta,
00729         offset;
00730 
00731       RectangleInfo
00732         crop;
00733 
00734       size_t
00735         height,
00736         width;
00737 
00738       /*
00739         Crop into NxM tiles (@ flag).
00740       */
00741       width=image->columns;
00742       height=image->rows;
00743       if (geometry.width == 0)
00744         geometry.width=1;
00745       if (geometry.height == 0)
00746         geometry.height=1;
00747       if ((flags & AspectValue) == 0)
00748         {
00749           width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
00750           height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
00751         }
00752       else
00753         {
00754           width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
00755           height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
00756         }
00757       delta.x=(double) width/geometry.width;
00758       delta.y=(double) height/geometry.height;
00759       if ( delta.x < 1.0 ) delta.x = 1.0;
00760       if ( delta.y < 1.0 ) delta.y = 1.0;
00761       for (offset.y=0; offset.y < (double) height; )
00762       {
00763         if ((flags & AspectValue) == 0)
00764           {
00765             crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
00766               (geometry.y > 0 ? 0 : geometry.y)));
00767             offset.y+=delta.y;   /* increment now to find width */
00768             crop.height=(size_t) MagickRound((MagickRealType) (offset.y+
00769               (geometry.y < 0 ? 0 : geometry.y)));
00770           }
00771         else
00772           {
00773             crop.y=(ssize_t) MagickRound((MagickRealType) (offset.y-
00774               (geometry.y > 0 ? geometry.y : 0)));
00775             offset.y+=delta.y;  /* increment now to find width */
00776             crop.height=(size_t) MagickRound((MagickRealType)
00777               (offset.y+(geometry.y < -1 ? geometry.y : 0)));
00778           }
00779         crop.height-=crop.y;
00780         crop.y+=image->page.y;
00781         for (offset.x=0; offset.x < (double) width; )
00782         {
00783           if ((flags & AspectValue) == 0)
00784             {
00785               crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
00786                 (geometry.x > 0 ? 0 : geometry.x)));
00787               offset.x+=delta.x;  /* increment now to find height */
00788               crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
00789                 (geometry.x < 0 ? 0 : geometry.x)));
00790             }
00791           else
00792             {
00793               crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
00794                 (geometry.x > 0 ? geometry.x : 0)));
00795               offset.x+=delta.x;  /* increment now to find height */
00796               crop.width=(size_t) MagickRound((MagickRealType) (offset.x+
00797                 (geometry.x < 0 ? geometry.x : 0)));
00798             }
00799           crop.width-=crop.x;
00800           crop.x+=image->page.x;
00801           next=CropImage(image,&crop,exception);
00802           if (next == (Image *) NULL)
00803             break;
00804           AppendImageToList(&crop_image,next);
00805         }
00806         if (next == (Image *) NULL)
00807           break;
00808       }
00809       ClearMagickException(exception);
00810       return(crop_image);
00811     }
00812 
00813   if (((geometry.width == 0) && (geometry.height == 0)) ||
00814       ((flags & XValue) != 0) || ((flags & YValue) != 0))
00815     {
00816       /*
00817         Crop a single region at +X+Y.
00818       */
00819       crop_image=CropImage(image,&geometry,exception);
00820       if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
00821         {
00822           crop_image->page.width=geometry.width;
00823           crop_image->page.height=geometry.height;
00824           crop_image->page.x-=geometry.x;
00825           crop_image->page.y-=geometry.y;
00826         }
00827       return(crop_image);
00828      }
00829   if ((image->columns > geometry.width) || (image->rows > geometry.height))
00830     {
00831       RectangleInfo
00832         page;
00833 
00834       size_t
00835         height,
00836         width;
00837 
00838       ssize_t
00839         x,
00840         y;
00841 
00842       /*
00843         Crop into tiles of fixed size WxH.
00844       */
00845       page=image->page;
00846       if (page.width == 0)
00847         page.width=image->columns;
00848       if (page.height == 0)
00849         page.height=image->rows;
00850       width=geometry.width;
00851       if (width == 0)
00852         width=page.width;
00853       height=geometry.height;
00854       if (height == 0)
00855         height=page.height;
00856       next=NewImageList();
00857       for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
00858       {
00859         for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
00860         {
00861           geometry.width=width;
00862           geometry.height=height;
00863           geometry.x=x;
00864           geometry.y=y;
00865           next=CropImage(image,&geometry,exception);
00866           if (next == (Image *) NULL)
00867             break;
00868           AppendImageToList(&crop_image,next);
00869         }
00870         if (next == (Image *) NULL)
00871           break;
00872       }
00873       return(crop_image);
00874     }
00875   return(CloneImage(image,0,0,MagickTrue,exception));
00876 }
00877 
00878 /*
00879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00880 %                                                                             %
00881 %                                                                             %
00882 %                                                                             %
00883 %   E x c e r p t I m a g e                                                   %
00884 %                                                                             %
00885 %                                                                             %
00886 %                                                                             %
00887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00888 %
00889 %  ExcerptImage() returns a excerpt of the image as defined by the geometry.
00890 %
00891 %  The format of the ExcerptImage method is:
00892 %
00893 %      Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
00894 %        ExceptionInfo *exception)
00895 %
00896 %  A description of each parameter follows:
00897 %
00898 %    o image: the image.
00899 %
00900 %    o geometry: Define the region of the image to extend with members
00901 %      x, y, width, and height.
00902 %
00903 %    o exception: return any errors or warnings in this structure.
00904 %
00905 */
00906 MagickExport Image *ExcerptImage(const Image *image,
00907   const RectangleInfo *geometry,ExceptionInfo *exception)
00908 {
00909 #define ExcerptImageTag  "Excerpt/Image"
00910 
00911   CacheView
00912     *excerpt_view,
00913     *image_view;
00914 
00915   Image
00916     *excerpt_image;
00917 
00918   MagickBooleanType
00919     status;
00920 
00921   MagickOffsetType
00922     progress;
00923 
00924   ssize_t
00925     y;
00926 
00927   /*
00928     Allocate excerpt image.
00929   */
00930   assert(image != (const Image *) NULL);
00931   assert(image->signature == MagickSignature);
00932   if (image->debug != MagickFalse)
00933     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00934   assert(geometry != (const RectangleInfo *) NULL);
00935   assert(exception != (ExceptionInfo *) NULL);
00936   assert(exception->signature == MagickSignature);
00937   excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
00938     exception);
00939   if (excerpt_image == (Image *) NULL)
00940     return((Image *) NULL);
00941   /*
00942     Excerpt each row.
00943   */
00944   status=MagickTrue;
00945   progress=0;
00946   image_view=AcquireCacheView(image);
00947   excerpt_view=AcquireCacheView(excerpt_image);
00948 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00949   #pragma omp parallel for schedule(static,4) shared(progress,status)
00950 #endif
00951   for (y=0; y < (ssize_t) excerpt_image->rows; y++)
00952   {
00953     register const Quantum
00954       *restrict p;
00955 
00956     register Quantum
00957       *restrict q;
00958 
00959     register ssize_t
00960       x;
00961 
00962     if (status == MagickFalse)
00963       continue;
00964     p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
00965       geometry->width,1,exception);
00966     q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
00967       exception);
00968     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00969       {
00970         status=MagickFalse;
00971         continue;
00972       }
00973     for (x=0; x < (ssize_t) excerpt_image->columns; x++)
00974     {
00975       register ssize_t
00976         i;
00977 
00978       if (GetPixelMask(image,p) != 0)
00979         {
00980           p+=GetPixelChannels(image);
00981           q+=GetPixelChannels(excerpt_image);
00982           continue;
00983         }
00984       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00985       {
00986         PixelChannel
00987           channel;
00988 
00989         PixelTrait
00990           excerpt_traits,
00991           traits;
00992 
00993         channel=GetPixelChannelMapChannel(image,i);
00994         traits=GetPixelChannelMapTraits(image,channel);
00995         excerpt_traits=GetPixelChannelMapTraits(excerpt_image,channel);
00996         if ((traits == UndefinedPixelTrait) ||
00997             (excerpt_traits == UndefinedPixelTrait))
00998           continue;
00999         SetPixelChannel(excerpt_image,channel,p[i],q);
01000       }
01001       p+=GetPixelChannels(image);
01002       q+=GetPixelChannels(excerpt_image);
01003     }
01004     if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
01005       status=MagickFalse;
01006     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01007       {
01008         MagickBooleanType
01009           proceed;
01010 
01011 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01012         #pragma omp critical (MagickCore_ExcerptImage)
01013 #endif
01014         proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
01015         if (proceed == MagickFalse)
01016           status=MagickFalse;
01017       }
01018   }
01019   excerpt_view=DestroyCacheView(excerpt_view);
01020   image_view=DestroyCacheView(image_view);
01021   excerpt_image->type=image->type;
01022   if (status == MagickFalse)
01023     excerpt_image=DestroyImage(excerpt_image);
01024   return(excerpt_image);
01025 }
01026 
01027 /*
01028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01029 %                                                                             %
01030 %                                                                             %
01031 %                                                                             %
01032 %   E x t e n t I m a g e                                                     %
01033 %                                                                             %
01034 %                                                                             %
01035 %                                                                             %
01036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01037 %
01038 %  ExtentImage() extends the image as defined by the geometry, gravity, and
01039 %  image background color.  Set the (x,y) offset of the geometry to move the
01040 %  original image relative to the extended image.
01041 %
01042 %  The format of the ExtentImage method is:
01043 %
01044 %      Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
01045 %        ExceptionInfo *exception)
01046 %
01047 %  A description of each parameter follows:
01048 %
01049 %    o image: the image.
01050 %
01051 %    o geometry: Define the region of the image to extend with members
01052 %      x, y, width, and height.
01053 %
01054 %    o exception: return any errors or warnings in this structure.
01055 %
01056 */
01057 MagickExport Image *ExtentImage(const Image *image,
01058   const RectangleInfo *geometry,ExceptionInfo *exception)
01059 {
01060   Image
01061     *extent_image;
01062 
01063   /*
01064     Allocate extent image.
01065   */
01066   assert(image != (const Image *) NULL);
01067   assert(image->signature == MagickSignature);
01068   if (image->debug != MagickFalse)
01069     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01070   assert(geometry != (const RectangleInfo *) NULL);
01071   assert(exception != (ExceptionInfo *) NULL);
01072   assert(exception->signature == MagickSignature);
01073   extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
01074     exception);
01075   if (extent_image == (Image *) NULL)
01076     return((Image *) NULL);
01077   if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse)
01078     {
01079       extent_image=DestroyImage(extent_image);
01080       return((Image *) NULL);
01081     }
01082   if (extent_image->background_color.alpha != OpaqueAlpha)
01083     extent_image->matte=MagickTrue;
01084   (void) SetImageBackgroundColor(extent_image,exception);
01085   (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
01086     -geometry->y,exception);
01087   return(extent_image);
01088 }
01089 
01090 /*
01091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01092 %                                                                             %
01093 %                                                                             %
01094 %                                                                             %
01095 %   F l i p I m a g e                                                         %
01096 %                                                                             %
01097 %                                                                             %
01098 %                                                                             %
01099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01100 %
01101 %  FlipImage() creates a vertical mirror image by reflecting the pixels
01102 %  around the central x-axis.
01103 %
01104 %  The format of the FlipImage method is:
01105 %
01106 %      Image *FlipImage(const Image *image,ExceptionInfo *exception)
01107 %
01108 %  A description of each parameter follows:
01109 %
01110 %    o image: the image.
01111 %
01112 %    o exception: return any errors or warnings in this structure.
01113 %
01114 */
01115 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
01116 {
01117 #define FlipImageTag  "Flip/Image"
01118 
01119   CacheView
01120     *flip_view,
01121     *image_view;
01122 
01123   Image
01124     *flip_image;
01125 
01126   MagickBooleanType
01127     status;
01128 
01129   MagickOffsetType
01130     progress;
01131 
01132   RectangleInfo
01133     page;
01134 
01135   ssize_t
01136     y;
01137 
01138   assert(image != (const Image *) NULL);
01139   assert(image->signature == MagickSignature);
01140   if (image->debug != MagickFalse)
01141     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01142   assert(exception != (ExceptionInfo *) NULL);
01143   assert(exception->signature == MagickSignature);
01144   flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
01145   if (flip_image == (Image *) NULL)
01146     return((Image *) NULL);
01147   /*
01148     Flip image.
01149   */
01150   status=MagickTrue;
01151   progress=0;
01152   page=image->page;
01153   image_view=AcquireCacheView(image);
01154   flip_view=AcquireCacheView(flip_image);
01155 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01156   #pragma omp parallel for schedule(static) shared(progress,status)
01157 #endif
01158   for (y=0; y < (ssize_t) flip_image->rows; y++)
01159   {
01160     register const Quantum
01161       *restrict p;
01162 
01163     register Quantum
01164       *restrict q;
01165 
01166     register ssize_t
01167       x;
01168 
01169     if (status == MagickFalse)
01170       continue;
01171     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
01172     q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
01173       1),flip_image->columns,1,exception);
01174     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
01175       {
01176         status=MagickFalse;
01177         continue;
01178       }
01179     for (x=0; x < (ssize_t) flip_image->columns; x++)
01180     {
01181       register ssize_t
01182         i;
01183 
01184       if (GetPixelMask(image,p) != 0)
01185         {
01186           p+=GetPixelChannels(image);
01187           q+=GetPixelChannels(flip_image);
01188           continue;
01189         }
01190       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01191       {
01192         PixelChannel
01193           channel;
01194 
01195         PixelTrait
01196           flip_traits,
01197           traits;
01198 
01199         channel=GetPixelChannelMapChannel(image,i);
01200         traits=GetPixelChannelMapTraits(image,channel);
01201         flip_traits=GetPixelChannelMapTraits(flip_image,channel);
01202         if ((traits == UndefinedPixelTrait) ||
01203             (flip_traits == UndefinedPixelTrait))
01204           continue;
01205         SetPixelChannel(flip_image,channel,p[i],q);
01206       }
01207       p+=GetPixelChannels(image);
01208       q+=GetPixelChannels(flip_image);
01209     }
01210     if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
01211       status=MagickFalse;
01212     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01213       {
01214         MagickBooleanType
01215           proceed;
01216 
01217 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01218         #pragma omp critical (MagickCore_FlipImage)
01219 #endif
01220         proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
01221         if (proceed == MagickFalse)
01222           status=MagickFalse;
01223       }
01224   }
01225   flip_view=DestroyCacheView(flip_view);
01226   image_view=DestroyCacheView(image_view);
01227   flip_image->type=image->type;
01228   if (page.height != 0)
01229     page.y=(ssize_t) (page.height-flip_image->rows-page.y);
01230   flip_image->page=page;
01231   if (status == MagickFalse)
01232     flip_image=DestroyImage(flip_image);
01233   return(flip_image);
01234 }
01235 
01236 /*
01237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01238 %                                                                             %
01239 %                                                                             %
01240 %                                                                             %
01241 %   F l o p I m a g e                                                         %
01242 %                                                                             %
01243 %                                                                             %
01244 %                                                                             %
01245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01246 %
01247 %  FlopImage() creates a horizontal mirror image by reflecting the pixels
01248 %  around the central y-axis.
01249 %
01250 %  The format of the FlopImage method is:
01251 %
01252 %      Image *FlopImage(const Image *image,ExceptionInfo *exception)
01253 %
01254 %  A description of each parameter follows:
01255 %
01256 %    o image: the image.
01257 %
01258 %    o exception: return any errors or warnings in this structure.
01259 %
01260 */
01261 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
01262 {
01263 #define FlopImageTag  "Flop/Image"
01264 
01265   CacheView
01266     *flop_view,
01267     *image_view;
01268 
01269   Image
01270     *flop_image;
01271 
01272   MagickBooleanType
01273     status;
01274 
01275   MagickOffsetType
01276     progress;
01277 
01278   RectangleInfo
01279     page;
01280 
01281   ssize_t
01282     y;
01283 
01284   assert(image != (const Image *) NULL);
01285   assert(image->signature == MagickSignature);
01286   if (image->debug != MagickFalse)
01287     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01288   assert(exception != (ExceptionInfo *) NULL);
01289   assert(exception->signature == MagickSignature);
01290   flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
01291   if (flop_image == (Image *) NULL)
01292     return((Image *) NULL);
01293   /*
01294     Flop each row.
01295   */
01296   status=MagickTrue;
01297   progress=0;
01298   page=image->page;
01299   image_view=AcquireCacheView(image);
01300   flop_view=AcquireCacheView(flop_image);
01301 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01302   #pragma omp parallel for schedule(static) shared(progress,status)
01303 #endif
01304   for (y=0; y < (ssize_t) flop_image->rows; y++)
01305   {
01306     register const Quantum
01307       *restrict p;
01308 
01309     register ssize_t
01310       x;
01311 
01312     register Quantum
01313       *restrict q;
01314 
01315     if (status == MagickFalse)
01316       continue;
01317     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
01318     q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
01319       exception);
01320     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
01321       {
01322         status=MagickFalse;
01323         continue;
01324       }
01325     q+=GetPixelChannels(flop_image)*flop_image->columns;
01326     for (x=0; x < (ssize_t) flop_image->columns; x++)
01327     {
01328       register ssize_t
01329         i;
01330 
01331       q-=GetPixelChannels(flop_image);
01332       if (GetPixelMask(image,p) != 0)
01333         {
01334           p+=GetPixelChannels(image);
01335           continue;
01336         }
01337       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01338       {
01339         PixelChannel
01340           channel;
01341 
01342         PixelTrait
01343           flop_traits,
01344           traits;
01345 
01346         channel=GetPixelChannelMapChannel(image,i);
01347         traits=GetPixelChannelMapTraits(image,channel);
01348         flop_traits=GetPixelChannelMapTraits(flop_image,channel);
01349         if ((traits == UndefinedPixelTrait) ||
01350             (flop_traits == UndefinedPixelTrait))
01351           continue;
01352         SetPixelChannel(flop_image,channel,p[i],q);
01353       }
01354       p+=GetPixelChannels(image);
01355     }
01356     if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
01357       status=MagickFalse;
01358     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01359       {
01360         MagickBooleanType
01361           proceed;
01362 
01363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01364         #pragma omp critical (MagickCore_FlopImage)
01365 #endif
01366         proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
01367         if (proceed == MagickFalse)
01368           status=MagickFalse;
01369       }
01370   }
01371   flop_view=DestroyCacheView(flop_view);
01372   image_view=DestroyCacheView(image_view);
01373   flop_image->type=image->type;
01374   if (page.width != 0)
01375     page.x=(ssize_t) (page.width-flop_image->columns-page.x);
01376   flop_image->page=page;
01377   if (status == MagickFalse)
01378     flop_image=DestroyImage(flop_image);
01379   return(flop_image);
01380 }
01381 
01382 /*
01383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01384 %                                                                             %
01385 %                                                                             %
01386 %                                                                             %
01387 %   R o l l I m a g e                                                         %
01388 %                                                                             %
01389 %                                                                             %
01390 %                                                                             %
01391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01392 %
01393 %  RollImage() offsets an image as defined by x_offset and y_offset.
01394 %
01395 %  The format of the RollImage method is:
01396 %
01397 %      Image *RollImage(const Image *image,const ssize_t x_offset,
01398 %        const ssize_t y_offset,ExceptionInfo *exception)
01399 %
01400 %  A description of each parameter follows:
01401 %
01402 %    o image: the image.
01403 %
01404 %    o x_offset: the number of columns to roll in the horizontal direction.
01405 %
01406 %    o y_offset: the number of rows to roll in the vertical direction.
01407 %
01408 %    o exception: return any errors or warnings in this structure.
01409 %
01410 */
01411 
01412 static inline MagickBooleanType CopyImageRegion(Image *destination,
01413   const Image *source,const size_t columns,const size_t rows,
01414   const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
01415   ExceptionInfo *exception)
01416 {
01417   CacheView
01418     *source_view,
01419     *destination_view;
01420 
01421   MagickBooleanType
01422     status;
01423 
01424   ssize_t
01425     y;
01426 
01427   status=MagickTrue;
01428   source_view=AcquireCacheView(source);
01429   destination_view=AcquireCacheView(destination);
01430 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01431   #pragma omp parallel for schedule(static) shared(status)
01432 #endif
01433   for (y=0; y < (ssize_t) rows; y++)
01434   {
01435     MagickBooleanType
01436       sync;
01437 
01438     register const Quantum
01439       *restrict p;
01440 
01441     register Quantum
01442       *restrict q;
01443 
01444     register ssize_t
01445       x;
01446 
01447     /*
01448       Transfer scanline.
01449     */
01450     if (status == MagickFalse)
01451       continue;
01452     p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
01453     q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
01454     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
01455       {
01456         status=MagickFalse;
01457         continue;
01458       }
01459     for (x=0; x < (ssize_t) columns; x++)
01460     {
01461       register ssize_t
01462         i;
01463 
01464       if (GetPixelMask(source,p) != 0)
01465         {
01466           p+=GetPixelChannels(source);
01467           q+=GetPixelChannels(destination);
01468           continue;
01469         }
01470       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
01471       {
01472         PixelChannel
01473           channel;
01474 
01475         PixelTrait
01476           destination_traits,
01477           source_traits;
01478 
01479         channel=GetPixelChannelMapChannel(source,i);
01480         source_traits=GetPixelChannelMapTraits(source,channel);
01481         destination_traits=GetPixelChannelMapTraits(destination,channel);
01482         if ((source_traits == UndefinedPixelTrait) ||
01483             (destination_traits == UndefinedPixelTrait))
01484           continue;
01485         SetPixelChannel(destination,channel,p[i],q);
01486       }
01487       p+=GetPixelChannels(source);
01488       q+=GetPixelChannels(destination);
01489     }
01490     sync=SyncCacheViewAuthenticPixels(destination_view,exception);
01491     if (sync == MagickFalse)
01492       status=MagickFalse;
01493   }
01494   destination_view=DestroyCacheView(destination_view);
01495   source_view=DestroyCacheView(source_view);
01496   return(status);
01497 }
01498 
01499 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
01500   const ssize_t y_offset,ExceptionInfo *exception)
01501 {
01502 #define RollImageTag  "Roll/Image"
01503 
01504   Image
01505     *roll_image;
01506 
01507   MagickStatusType
01508     status;
01509 
01510   RectangleInfo
01511     offset;
01512 
01513   /*
01514     Initialize roll image attributes.
01515   */
01516   assert(image != (const Image *) NULL);
01517   assert(image->signature == MagickSignature);
01518   if (image->debug != MagickFalse)
01519     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01520   assert(exception != (ExceptionInfo *) NULL);
01521   assert(exception->signature == MagickSignature);
01522   roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
01523   if (roll_image == (Image *) NULL)
01524     return((Image *) NULL);
01525   offset.x=x_offset;
01526   offset.y=y_offset;
01527   while (offset.x < 0)
01528     offset.x+=(ssize_t) image->columns;
01529   while (offset.x >= (ssize_t) image->columns)
01530     offset.x-=(ssize_t) image->columns;
01531   while (offset.y < 0)
01532     offset.y+=(ssize_t) image->rows;
01533   while (offset.y >= (ssize_t) image->rows)
01534     offset.y-=(ssize_t) image->rows;
01535   /*
01536     Roll image.
01537   */
01538   status=CopyImageRegion(roll_image,image,(size_t) offset.x,
01539     (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
01540     offset.y,0,0,exception);
01541   (void) SetImageProgress(image,RollImageTag,0,3);
01542   status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
01543     (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
01544     exception);
01545   (void) SetImageProgress(image,RollImageTag,1,3);
01546   status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
01547     offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
01548   (void) SetImageProgress(image,RollImageTag,2,3);
01549   status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
01550     offset.y,0,0,offset.x,offset.y,exception);
01551   (void) SetImageProgress(image,RollImageTag,3,3);
01552   roll_image->type=image->type;
01553   if (status == MagickFalse)
01554     roll_image=DestroyImage(roll_image);
01555   return(roll_image);
01556 }
01557 
01558 /*
01559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01560 %                                                                             %
01561 %                                                                             %
01562 %                                                                             %
01563 %   S h a v e I m a g e                                                       %
01564 %                                                                             %
01565 %                                                                             %
01566 %                                                                             %
01567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01568 %
01569 %  ShaveImage() shaves pixels from the image edges.  It allocates the memory
01570 %  necessary for the new Image structure and returns a pointer to the new
01571 %  image.
01572 %
01573 %  The format of the ShaveImage method is:
01574 %
01575 %      Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
01576 %        ExceptionInfo *exception)
01577 %
01578 %  A description of each parameter follows:
01579 %
01580 %    o shave_image: Method ShaveImage returns a pointer to the shaved
01581 %      image.  A null image is returned if there is a memory shortage or
01582 %      if the image width or height is zero.
01583 %
01584 %    o image: the image.
01585 %
01586 %    o shave_info: Specifies a pointer to a RectangleInfo which defines the
01587 %      region of the image to crop.
01588 %
01589 %    o exception: return any errors or warnings in this structure.
01590 %
01591 */
01592 MagickExport Image *ShaveImage(const Image *image,
01593   const RectangleInfo *shave_info,ExceptionInfo *exception)
01594 {
01595   Image
01596     *shave_image;
01597 
01598   RectangleInfo
01599     geometry;
01600 
01601   assert(image != (const Image *) NULL);
01602   assert(image->signature == MagickSignature);
01603   if (image->debug != MagickFalse)
01604     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01605   if (((2*shave_info->width) >= image->columns) ||
01606       ((2*shave_info->height) >= image->rows))
01607     ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
01608   SetGeometry(image,&geometry);
01609   geometry.width-=2*shave_info->width;
01610   geometry.height-=2*shave_info->height;
01611   geometry.x=(ssize_t) shave_info->width+image->page.x;
01612   geometry.y=(ssize_t) shave_info->height+image->page.y;
01613   shave_image=CropImage(image,&geometry,exception);
01614   if (shave_image == (Image *) NULL)
01615     return((Image *) NULL);
01616   shave_image->page.width-=2*shave_info->width;
01617   shave_image->page.height-=2*shave_info->height;
01618   shave_image->page.x-=(ssize_t) shave_info->width;
01619   shave_image->page.y-=(ssize_t) shave_info->height;
01620   return(shave_image);
01621 }
01622 
01623 /*
01624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01625 %                                                                             %
01626 %                                                                             %
01627 %                                                                             %
01628 %   S p l i c e I m a g e                                                     %
01629 %                                                                             %
01630 %                                                                             %
01631 %                                                                             %
01632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01633 %
01634 %  SpliceImage() splices a solid color into the image as defined by the
01635 %  geometry.
01636 %
01637 %  The format of the SpliceImage method is:
01638 %
01639 %      Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
01640 %        ExceptionInfo *exception)
01641 %
01642 %  A description of each parameter follows:
01643 %
01644 %    o image: the image.
01645 %
01646 %    o geometry: Define the region of the image to splice with members
01647 %      x, y, width, and height.
01648 %
01649 %    o exception: return any errors or warnings in this structure.
01650 %
01651 */
01652 MagickExport Image *SpliceImage(const Image *image,
01653   const RectangleInfo *geometry,ExceptionInfo *exception)
01654 {
01655 #define SpliceImageTag  "Splice/Image"
01656 
01657   CacheView
01658     *image_view,
01659     *splice_view;
01660 
01661   Image
01662     *splice_image;
01663 
01664   MagickBooleanType
01665     status;
01666 
01667   MagickOffsetType
01668     progress;
01669 
01670   RectangleInfo
01671     splice_geometry;
01672 
01673   ssize_t
01674     y;
01675 
01676   /*
01677     Allocate splice image.
01678   */
01679   assert(image != (const Image *) NULL);
01680   assert(image->signature == MagickSignature);
01681   if (image->debug != MagickFalse)
01682     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01683   assert(geometry != (const RectangleInfo *) NULL);
01684   assert(exception != (ExceptionInfo *) NULL);
01685   assert(exception->signature == MagickSignature);
01686   splice_geometry=(*geometry);
01687   splice_image=CloneImage(image,image->columns+splice_geometry.width,
01688     image->rows+splice_geometry.height,MagickTrue,exception);
01689   if (splice_image == (Image *) NULL)
01690     return((Image *) NULL);
01691   if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
01692     {
01693       splice_image=DestroyImage(splice_image);
01694       return((Image *) NULL);
01695     }
01696   (void) SetImageBackgroundColor(splice_image,exception);
01697   /*
01698     Respect image geometry.
01699   */
01700   switch (image->gravity)
01701   {
01702     default:
01703     case UndefinedGravity:
01704     case NorthWestGravity:
01705       break;
01706     case NorthGravity:
01707     {
01708       splice_geometry.x+=(ssize_t) splice_geometry.width/2;
01709       break;
01710     }
01711     case NorthEastGravity:
01712     {
01713       splice_geometry.x+=(ssize_t) splice_geometry.width;
01714       break;
01715     }
01716     case WestGravity:
01717     {
01718       splice_geometry.y+=(ssize_t) splice_geometry.width/2;
01719       break;
01720     }
01721     case StaticGravity:
01722     case CenterGravity:
01723     {
01724       splice_geometry.x+=(ssize_t) splice_geometry.width/2;
01725       splice_geometry.y+=(ssize_t) splice_geometry.height/2;
01726       break;
01727     }
01728     case EastGravity:
01729     {
01730       splice_geometry.x+=(ssize_t) splice_geometry.width;
01731       splice_geometry.y+=(ssize_t) splice_geometry.height/2;
01732       break;
01733     }
01734     case SouthWestGravity:
01735     {
01736       splice_geometry.y+=(ssize_t) splice_geometry.height;
01737       break;
01738     }
01739     case SouthGravity:
01740     {
01741       splice_geometry.x+=(ssize_t) splice_geometry.width/2;
01742       splice_geometry.y+=(ssize_t) splice_geometry.height;
01743       break;
01744     }
01745     case SouthEastGravity:
01746     {
01747       splice_geometry.x+=(ssize_t) splice_geometry.width;
01748       splice_geometry.y+=(ssize_t) splice_geometry.height;
01749       break;
01750     }
01751   }
01752   /*
01753     Splice image.
01754   */
01755   status=MagickTrue;
01756   progress=0;
01757   image_view=AcquireCacheView(image);
01758   splice_view=AcquireCacheView(splice_image);
01759 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01760   #pragma omp parallel for schedule(static,4) shared(progress,status)
01761 #endif
01762   for (y=0; y < (ssize_t) splice_geometry.y; y++)
01763   {
01764     register const Quantum
01765       *restrict p;
01766 
01767     register ssize_t
01768       x;
01769 
01770     register Quantum
01771       *restrict q;
01772 
01773     if (status == MagickFalse)
01774       continue;
01775     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
01776     q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
01777       exception);
01778     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
01779       {
01780         status=MagickFalse;
01781         continue;
01782       }
01783     for (x=0; x < splice_geometry.x; x++)
01784     {
01785       register ssize_t
01786         i;
01787 
01788       if (GetPixelMask(image,p) != 0)
01789         {
01790           p+=GetPixelChannels(image);
01791           q+=GetPixelChannels(splice_image);
01792           continue;
01793         }
01794       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01795       {
01796         PixelChannel
01797           channel;
01798 
01799         PixelTrait
01800           splice_traits,
01801           traits;
01802 
01803         channel=GetPixelChannelMapChannel(image,i);
01804         traits=GetPixelChannelMapTraits(image,channel);
01805         splice_traits=GetPixelChannelMapTraits(splice_image,channel);
01806         if ((traits == UndefinedPixelTrait) ||
01807             (splice_traits == UndefinedPixelTrait))
01808           continue;
01809         SetPixelChannel(splice_image,channel,p[i],q);
01810       }
01811       p+=GetPixelChannels(image);
01812       q+=GetPixelChannels(splice_image);
01813     }
01814     for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
01815       q+=GetPixelChannels(splice_image);
01816     for ( ; x < (ssize_t) splice_image->columns; x++)
01817     {
01818       register ssize_t
01819         i;
01820 
01821       if (GetPixelMask(image,p) != 0)
01822         {
01823           p+=GetPixelChannels(image);
01824           q+=GetPixelChannels(splice_image);
01825           continue;
01826         }
01827       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01828       {
01829         PixelChannel
01830           channel;
01831 
01832         PixelTrait
01833           traits,
01834           splice_traits;
01835 
01836         channel=GetPixelChannelMapChannel(image,i);
01837         traits=GetPixelChannelMapTraits(image,channel);
01838         splice_traits=GetPixelChannelMapTraits(splice_image,channel);
01839         if ((traits == UndefinedPixelTrait) ||
01840             (splice_traits == UndefinedPixelTrait))
01841           continue;
01842         SetPixelChannel(splice_image,channel,p[i],q);
01843       }
01844       p+=GetPixelChannels(image);
01845       q+=GetPixelChannels(splice_image);
01846     }
01847     if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
01848       status=MagickFalse;
01849     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01850       {
01851         MagickBooleanType
01852           proceed;
01853 
01854 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01855         #pragma omp critical (MagickCore_TransposeImage)
01856 #endif
01857         proceed=SetImageProgress(image,SpliceImageTag,progress++,
01858           splice_image->rows);
01859         if (proceed == MagickFalse)
01860           status=MagickFalse;
01861       }
01862   }
01863 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01864   #pragma omp parallel for schedule(static,4) shared(progress,status)
01865 #endif
01866   for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
01867        y < (ssize_t) splice_image->rows; y++)
01868   {
01869     register const Quantum
01870       *restrict p;
01871 
01872     register ssize_t
01873       x;
01874 
01875     register Quantum
01876       *restrict q;
01877 
01878     if (status == MagickFalse)
01879       continue;
01880     p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
01881       image->columns,1,exception);
01882     if ((y < 0) || (y >= (ssize_t) splice_image->rows))
01883       continue;
01884     q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
01885       exception);
01886     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
01887       {
01888         status=MagickFalse;
01889         continue;
01890       }
01891     for (x=0; x < splice_geometry.x; x++)
01892     {
01893       register ssize_t
01894         i;
01895 
01896       if (GetPixelMask(image,q) != 0)
01897         {
01898           p+=GetPixelChannels(image);
01899           q+=GetPixelChannels(splice_image);
01900           continue;
01901         }
01902       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01903       {
01904         PixelChannel
01905           channel;
01906 
01907         PixelTrait
01908           traits,
01909           splice_traits;
01910 
01911         channel=GetPixelChannelMapChannel(image,i);
01912         traits=GetPixelChannelMapTraits(image,channel);
01913         splice_traits=GetPixelChannelMapTraits(splice_image,channel);
01914         if ((traits == UndefinedPixelTrait) ||
01915             (splice_traits == UndefinedPixelTrait))
01916           continue;
01917         SetPixelChannel(splice_image,channel,p[i],q);
01918       }
01919       p+=GetPixelChannels(image);
01920       q+=GetPixelChannels(splice_image);
01921     }
01922     for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
01923       q+=GetPixelChannels(splice_image);
01924     for ( ; x < (ssize_t) splice_image->columns; x++)
01925     {
01926       register ssize_t
01927         i;
01928 
01929       if (GetPixelMask(image,q) != 0)
01930         {
01931           p+=GetPixelChannels(image);
01932           q+=GetPixelChannels(splice_image);
01933           continue;
01934         }
01935       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01936       {
01937         PixelChannel
01938           channel;
01939 
01940         PixelTrait
01941           traits,
01942           splice_traits;
01943 
01944         channel=GetPixelChannelMapChannel(image,i);
01945         traits=GetPixelChannelMapTraits(image,channel);
01946         splice_traits=GetPixelChannelMapTraits(splice_image,channel);
01947         if ((traits == UndefinedPixelTrait) ||
01948             (splice_traits == UndefinedPixelTrait))
01949           continue;
01950         SetPixelChannel(splice_image,channel,p[i],q);
01951       }
01952       p+=GetPixelChannels(image);
01953       q+=GetPixelChannels(splice_image);
01954     }
01955     if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
01956       status=MagickFalse;
01957     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01958       {
01959         MagickBooleanType
01960           proceed;
01961 
01962 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01963         #pragma omp critical (MagickCore_TransposeImage)
01964 #endif
01965         proceed=SetImageProgress(image,SpliceImageTag,progress++,
01966           splice_image->rows);
01967         if (proceed == MagickFalse)
01968           status=MagickFalse;
01969       }
01970   }
01971   splice_view=DestroyCacheView(splice_view);
01972   image_view=DestroyCacheView(image_view);
01973   if (status == MagickFalse)
01974     splice_image=DestroyImage(splice_image);
01975   return(splice_image);
01976 }
01977 
01978 /*
01979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01980 %                                                                             %
01981 %                                                                             %
01982 %                                                                             %
01983 %   T r a n s f o r m I m a g e                                               %
01984 %                                                                             %
01985 %                                                                             %
01986 %                                                                             %
01987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01988 %
01989 %  TransformImage() is a convenience method that behaves like ResizeImage() or
01990 %  CropImage() but accepts scaling and/or cropping information as a region
01991 %  geometry specification.  If the operation fails, the original image handle
01992 %  is left as is.
01993 %
01994 %  This should only be used for single images.
01995 %
01996 %  This function destroys what it assumes to be a single image list.
01997 %  If the input image is part of a larger list, all other images in that list
01998 %  will be simply 'lost', not destroyed.
01999 %
02000 %  Also if the crop generates a list of images only the first image is resized.
02001 %  And finally if the crop succeeds and the resize failed, you will get a
02002 %  cropped image, as well as a 'false' or 'failed' report.
02003 %
02004 %  This function and should probably be depreciated in favor of direct calls
02005 %  to CropImageToTiles() or ResizeImage(), as appropriate.
02006 %
02007 %  The format of the TransformImage method is:
02008 %
02009 %      MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
02010 %        const char *image_geometry,ExceptionInfo *exception)
02011 %
02012 %  A description of each parameter follows:
02013 %
02014 %    o image: the image The transformed image is returned as this parameter.
02015 %
02016 %    o crop_geometry: A crop geometry string.  This geometry defines a
02017 %      subregion of the image to crop.
02018 %
02019 %    o image_geometry: An image geometry string.  This geometry defines the
02020 %      final size of the image.
02021 %
02022 %    o exception: return any errors or warnings in this structure.
02023 %
02024 */
02025 MagickExport MagickBooleanType TransformImage(Image **image,
02026   const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
02027 {
02028   Image
02029     *resize_image,
02030     *transform_image;
02031 
02032   MagickStatusType
02033     flags;
02034 
02035   RectangleInfo
02036     geometry;
02037 
02038   assert(image != (Image **) NULL);
02039   assert((*image)->signature == MagickSignature);
02040   if ((*image)->debug != MagickFalse)
02041     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
02042   transform_image=(*image);
02043   if (crop_geometry != (const char *) NULL)
02044     {
02045       Image
02046         *crop_image;
02047 
02048       /*
02049         Crop image to a user specified size.
02050       */
02051       crop_image=CropImageToTiles(*image,crop_geometry,exception);
02052       if (crop_image == (Image *) NULL)
02053         transform_image=CloneImage(*image,0,0,MagickTrue,exception);
02054       else
02055         {
02056           transform_image=DestroyImage(transform_image);
02057           transform_image=GetFirstImageInList(crop_image);
02058         }
02059       *image=transform_image;
02060     }
02061   if (image_geometry == (const char *) NULL)
02062     return(MagickTrue);
02063 
02064   /*
02065     Scale image to a user specified size.
02066   */
02067   flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
02068   (void) flags;
02069   if ((transform_image->columns == geometry.width) &&
02070       (transform_image->rows == geometry.height))
02071     return(MagickTrue);
02072   resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
02073     transform_image->filter,transform_image->blur,exception);
02074   if (resize_image == (Image *) NULL)
02075     return(MagickFalse);
02076   transform_image=DestroyImage(transform_image);
02077   transform_image=resize_image;
02078   *image=transform_image;
02079   return(MagickTrue);
02080 }
02081 
02082 /*
02083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02084 %                                                                             %
02085 %                                                                             %
02086 %                                                                             %
02087 %   T r a n s f o r m I m a g e s                                             %
02088 %                                                                             %
02089 %                                                                             %
02090 %                                                                             %
02091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02092 %
02093 %  TransformImages() calls TransformImage() on each image of a sequence.
02094 %
02095 %  The format of the TransformImage method is:
02096 %
02097 %      MagickBooleanType TransformImages(Image **image,
02098 %        const char *crop_geometry,const char *image_geometry,
02099 %        ExceptionInfo *exception)
02100 %
02101 %  A description of each parameter follows:
02102 %
02103 %    o image: the image The transformed image is returned as this parameter.
02104 %
02105 %    o crop_geometry: A crop geometry string.  This geometry defines a
02106 %      subregion of the image to crop.
02107 %
02108 %    o image_geometry: An image geometry string.  This geometry defines the
02109 %      final size of the image.
02110 %
02111 %    o exception: return any errors or warnings in this structure.
02112 %
02113 */
02114 MagickExport MagickBooleanType TransformImages(Image **images,
02115   const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
02116 {
02117   Image
02118     *image,
02119     **image_list,
02120     *transform_images;
02121 
02122   MagickStatusType
02123     status;
02124 
02125   register ssize_t
02126     i;
02127 
02128   assert(images != (Image **) NULL);
02129   assert((*images)->signature == MagickSignature);
02130   if ((*images)->debug != MagickFalse)
02131     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02132       (*images)->filename);
02133   image_list=ImageListToArray(*images,exception);
02134   if (image_list == (Image **) NULL)
02135     return(MagickFalse);
02136   status=MagickTrue;
02137   transform_images=NewImageList();
02138   for (i=0; image_list[i] != (Image *) NULL; i++)
02139   {
02140     image=image_list[i];
02141     status|=TransformImage(&image,crop_geometry,image_geometry,exception);
02142     AppendImageToList(&transform_images,image);
02143   }
02144   *images=transform_images;
02145   image_list=(Image **) RelinquishMagickMemory(image_list);
02146   return(status != 0 ? MagickTrue : MagickFalse);
02147 }
02148 
02149 /*
02150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02151 %                                                                             %
02152 %                                                                             %
02153 %                                                                             %
02154 %   T r a n s p o s e I m a g e                                               %
02155 %                                                                             %
02156 %                                                                             %
02157 %                                                                             %
02158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02159 %
02160 %  TransposeImage() creates a horizontal mirror image by reflecting the pixels
02161 %  around the central y-axis while rotating them by 90 degrees.
02162 %
02163 %  The format of the TransposeImage method is:
02164 %
02165 %      Image *TransposeImage(const Image *image,ExceptionInfo *exception)
02166 %
02167 %  A description of each parameter follows:
02168 %
02169 %    o image: the image.
02170 %
02171 %    o exception: return any errors or warnings in this structure.
02172 %
02173 */
02174 MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
02175 {
02176 #define TransposeImageTag  "Transpose/Image"
02177 
02178   CacheView
02179     *image_view,
02180     *transpose_view;
02181 
02182   Image
02183     *transpose_image;
02184 
02185   MagickBooleanType
02186     status;
02187 
02188   MagickOffsetType
02189     progress;
02190 
02191   RectangleInfo
02192     page;
02193 
02194   ssize_t
02195     y;
02196 
02197   assert(image != (const Image *) NULL);
02198   assert(image->signature == MagickSignature);
02199   if (image->debug != MagickFalse)
02200     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02201   assert(exception != (ExceptionInfo *) NULL);
02202   assert(exception->signature == MagickSignature);
02203   transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
02204     exception);
02205   if (transpose_image == (Image *) NULL)
02206     return((Image *) NULL);
02207   /*
02208     Transpose image.
02209   */
02210   status=MagickTrue;
02211   progress=0;
02212   image_view=AcquireCacheView(image);
02213   transpose_view=AcquireCacheView(transpose_image);
02214 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02215   #pragma omp parallel for schedule(static,4) shared(progress,status)
02216 #endif
02217   for (y=0; y < (ssize_t) image->rows; y++)
02218   {
02219     register const Quantum
02220       *restrict p;
02221 
02222     register Quantum
02223       *restrict q;
02224 
02225     register ssize_t
02226       x;
02227 
02228     if (status == MagickFalse)
02229       continue;
02230     p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
02231       image->columns,1,exception);
02232     q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
02233       0,1,transpose_image->rows,exception);
02234     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
02235       {
02236         status=MagickFalse;
02237         continue;
02238       }
02239     for (x=0; x < (ssize_t) image->columns; x++)
02240     {
02241       register ssize_t
02242         i;
02243 
02244       if (GetPixelMask(image,q) != 0)
02245         {
02246           p+=GetPixelChannels(image);
02247           q+=GetPixelChannels(transpose_image);
02248           continue;
02249         }
02250       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02251       {
02252         PixelChannel
02253           channel;
02254 
02255         PixelTrait
02256           traits,
02257           transpose_traits;
02258 
02259         channel=GetPixelChannelMapChannel(image,i);
02260         traits=GetPixelChannelMapTraits(image,channel);
02261         transpose_traits=GetPixelChannelMapTraits(transpose_image,channel);
02262         if ((traits == UndefinedPixelTrait) ||
02263             (transpose_traits == UndefinedPixelTrait))
02264           continue;
02265         SetPixelChannel(transpose_image,channel,p[i],q);
02266       }
02267       p+=GetPixelChannels(image);
02268       q+=GetPixelChannels(transpose_image);
02269     }
02270     if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
02271       status=MagickFalse;
02272     if (image->progress_monitor != (MagickProgressMonitor) NULL)
02273       {
02274         MagickBooleanType
02275           proceed;
02276 
02277 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02278         #pragma omp critical (MagickCore_TransposeImage)
02279 #endif
02280         proceed=SetImageProgress(image,TransposeImageTag,progress++,
02281           image->rows);
02282         if (proceed == MagickFalse)
02283           status=MagickFalse;
02284       }
02285   }
02286   transpose_view=DestroyCacheView(transpose_view);
02287   image_view=DestroyCacheView(image_view);
02288   transpose_image->type=image->type;
02289   page=transpose_image->page;
02290   Swap(page.width,page.height);
02291   Swap(page.x,page.y);
02292   transpose_image->page=page;
02293   if (status == MagickFalse)
02294     transpose_image=DestroyImage(transpose_image);
02295   return(transpose_image);
02296 }
02297 
02298 /*
02299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02300 %                                                                             %
02301 %                                                                             %
02302 %                                                                             %
02303 %   T r a n s v e r s e I m a g e                                             %
02304 %                                                                             %
02305 %                                                                             %
02306 %                                                                             %
02307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02308 %
02309 %  TransverseImage() creates a vertical mirror image by reflecting the pixels
02310 %  around the central x-axis while rotating them by 270 degrees.
02311 %
02312 %  The format of the TransverseImage method is:
02313 %
02314 %      Image *TransverseImage(const Image *image,ExceptionInfo *exception)
02315 %
02316 %  A description of each parameter follows:
02317 %
02318 %    o image: the image.
02319 %
02320 %    o exception: return any errors or warnings in this structure.
02321 %
02322 */
02323 MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
02324 {
02325 #define TransverseImageTag  "Transverse/Image"
02326 
02327   CacheView
02328     *image_view,
02329     *transverse_view;
02330 
02331   Image
02332     *transverse_image;
02333 
02334   MagickBooleanType
02335     status;
02336 
02337   MagickOffsetType
02338     progress;
02339 
02340   RectangleInfo
02341     page;
02342 
02343   ssize_t
02344     y;
02345 
02346   assert(image != (const Image *) NULL);
02347   assert(image->signature == MagickSignature);
02348   if (image->debug != MagickFalse)
02349     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02350   assert(exception != (ExceptionInfo *) NULL);
02351   assert(exception->signature == MagickSignature);
02352   transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
02353     exception);
02354   if (transverse_image == (Image *) NULL)
02355     return((Image *) NULL);
02356   /*
02357     Transverse image.
02358   */
02359   status=MagickTrue;
02360   progress=0;
02361   image_view=AcquireCacheView(image);
02362   transverse_view=AcquireCacheView(transverse_image);
02363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02364   #pragma omp parallel for schedule(static,4) shared(progress,status)
02365 #endif
02366   for (y=0; y < (ssize_t) image->rows; y++)
02367   {
02368     MagickBooleanType
02369       sync;
02370 
02371     register const Quantum
02372       *restrict p;
02373 
02374     register Quantum
02375       *restrict q;
02376 
02377     register ssize_t
02378       x;
02379 
02380     if (status == MagickFalse)
02381       continue;
02382     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
02383     q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
02384       0,1,transverse_image->rows,exception);
02385     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
02386       {
02387         status=MagickFalse;
02388         continue;
02389       }
02390     q+=GetPixelChannels(transverse_image)*image->columns;
02391     for (x=0; x < (ssize_t) image->columns; x++)
02392     {
02393       register ssize_t
02394         i;
02395 
02396       q-=GetPixelChannels(transverse_image);
02397       if (GetPixelMask(image,p) != 0)
02398         {
02399           p+=GetPixelChannels(image);
02400           continue;
02401         }
02402       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02403       {
02404         PixelChannel
02405           channel;
02406 
02407         PixelTrait
02408           traits,
02409           transverse_traits;
02410 
02411         channel=GetPixelChannelMapChannel(image,i);
02412         traits=GetPixelChannelMapTraits(image,channel);
02413         transverse_traits=GetPixelChannelMapTraits(transverse_image,channel);
02414         if ((traits == UndefinedPixelTrait) ||
02415             (transverse_traits == UndefinedPixelTrait))
02416           continue;
02417         SetPixelChannel(transverse_image,channel,p[i],q);
02418       }
02419       p+=GetPixelChannels(image);
02420     }
02421     sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
02422     if (sync == MagickFalse)
02423       status=MagickFalse;
02424     if (image->progress_monitor != (MagickProgressMonitor) NULL)
02425       {
02426         MagickBooleanType
02427           proceed;
02428 
02429 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02430         #pragma omp critical (MagickCore_TransverseImage)
02431 #endif
02432         proceed=SetImageProgress(image,TransverseImageTag,progress++,
02433           image->rows);
02434         if (proceed == MagickFalse)
02435           status=MagickFalse;
02436       }
02437   }
02438   transverse_view=DestroyCacheView(transverse_view);
02439   image_view=DestroyCacheView(image_view);
02440   transverse_image->type=image->type;
02441   page=transverse_image->page;
02442   Swap(page.width,page.height);
02443   Swap(page.x,page.y);
02444   if (page.width != 0)
02445     page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
02446   if (page.height != 0)
02447     page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
02448   transverse_image->page=page;
02449   if (status == MagickFalse)
02450     transverse_image=DestroyImage(transverse_image);
02451   return(transverse_image);
02452 }
02453 
02454 /*
02455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02456 %                                                                             %
02457 %                                                                             %
02458 %                                                                             %
02459 %   T r i m I m a g e                                                         %
02460 %                                                                             %
02461 %                                                                             %
02462 %                                                                             %
02463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02464 %
02465 %  TrimImage() trims pixels from the image edges.  It allocates the memory
02466 %  necessary for the new Image structure and returns a pointer to the new
02467 %  image.
02468 %
02469 %  The format of the TrimImage method is:
02470 %
02471 %      Image *TrimImage(const Image *image,ExceptionInfo *exception)
02472 %
02473 %  A description of each parameter follows:
02474 %
02475 %    o image: the image.
02476 %
02477 %    o exception: return any errors or warnings in this structure.
02478 %
02479 */
02480 MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
02481 {
02482   RectangleInfo
02483     geometry;
02484 
02485   assert(image != (const Image *) NULL);
02486   assert(image->signature == MagickSignature);
02487   if (image->debug != MagickFalse)
02488     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02489   geometry=GetImageBoundingBox(image,exception);
02490   if ((geometry.width == 0) || (geometry.height == 0))
02491     {
02492       Image
02493         *crop_image;
02494 
02495       crop_image=CloneImage(image,1,1,MagickTrue,exception);
02496       if (crop_image == (Image *) NULL)
02497         return((Image *) NULL);
02498       crop_image->background_color.alpha=(Quantum) TransparentAlpha;
02499       (void) SetImageBackgroundColor(crop_image,exception);
02500       crop_image->page=image->page;
02501       crop_image->page.x=(-1);
02502       crop_image->page.y=(-1);
02503       return(crop_image);
02504     }
02505   geometry.x+=image->page.x;
02506   geometry.y+=image->page.y;
02507   return(CropImage(image,&geometry,exception));
02508 }