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