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

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1