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-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/cache.h"
00044 #include "magick/cache-view.h"
00045 #include "magick/color.h"
00046 #include "magick/color-private.h"
00047 #include "magick/composite.h"
00048 #include "magick/effect.h"
00049 #include "magick/exception.h"
00050 #include "magick/exception-private.h"
00051 #include "magick/geometry.h"
00052 #include "magick/image.h"
00053 #include "magick/memory_.h"
00054 #include "magick/layer.h"
00055 #include "magick/list.h"
00056 #include "magick/monitor.h"
00057 #include "magick/monitor-private.h"
00058 #include "magick/pixel-private.h"
00059 #include "magick/resource_.h"
00060 #include "magick/resize.h"
00061 #include "magick/statistic.h"
00062 #include "magick/string_.h"
00063 #include "magick/transform.h"
00064 
00065 /*
00066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00067 %                                                                             %
00068 %                                                                             %
00069 %                                                                             %
00070 %   C h o p I m a g e                                                         %
00071 %                                                                             %
00072 %                                                                             %
00073 %                                                                             %
00074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00075 %
00076 %  Chop() removes a region of an image and collapses the image to occupy the
00077 %  removed portion.
00078 %
00079 %  The format of the ChopImage method is:
00080 %
00081 %      Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
00082 %        ExceptionInfo *exception)
00083 %
00084 %  A description of each parameter follows:
00085 %
00086 %    o image: the image.
00087 %
00088 %    o chop_info: Define the region of the image to chop.
00089 %
00090 %    o exception: return any errors or warnings in this structure.
00091 %
00092 */
00093 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
00094   ExceptionInfo *exception)
00095 {
00096 #define ChopImageTag  "Chop/Image"
00097 
00098   Image
00099     *chop_image;
00100 
00101   long
00102     j,
00103     y;
00104 
00105   MagickBooleanType
00106     proceed;
00107 
00108   RectangleInfo
00109     extent;
00110 
00111   register long
00112     i;
00113 
00114   ViewInfo
00115     *chop_view,
00116     *image_view;
00117 
00118   /*
00119     Check chop geometry.
00120   */
00121   assert(image != (const Image *) NULL);
00122   assert(image->signature == MagickSignature);
00123   if (image->debug != MagickFalse)
00124     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00125   assert(exception != (ExceptionInfo *) NULL);
00126   assert(exception->signature == MagickSignature);
00127   assert(chop_info != (RectangleInfo *) NULL);
00128   if (((chop_info->x+(long) chop_info->width) < 0) ||
00129       ((chop_info->y+(long) chop_info->height) < 0) ||
00130       (chop_info->x > (long) image->columns) ||
00131       (chop_info->y > (long) image->rows))
00132     ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
00133   extent=(*chop_info);
00134   if ((extent.x+(long) extent.width) > (long) image->columns)
00135     extent.width=(unsigned long) ((long) image->columns-extent.x);
00136   if ((extent.y+(long) extent.height) > (long) image->rows)
00137     extent.height=(unsigned long) ((long) image->rows-extent.y);
00138   if (extent.x < 0)
00139     {
00140       extent.width-=(unsigned long) (-extent.x);
00141       extent.x=0;
00142     }
00143   if (extent.y < 0)
00144     {
00145       extent.height-=(unsigned long) (-extent.y);
00146       extent.y=0;
00147     }
00148   chop_image=CloneImage(image,image->columns-extent.width,image->rows-
00149     extent.height,MagickTrue,exception);
00150   if (chop_image == (Image *) NULL)
00151     return((Image *) NULL);
00152   /*
00153     Extract chop image.
00154   */
00155   i=0;
00156   j=0;
00157   image_view=AcquireCacheView(image);
00158   chop_view=AcquireCacheView(chop_image);
00159   for (y=0; y < (long) extent.y; y++)
00160   {
00161     register const PixelPacket
00162       *p;
00163 
00164     register IndexPacket
00165       *chop_indexes,
00166       *indexes;
00167 
00168     register long
00169       x;
00170 
00171     register PixelPacket
00172       *q;
00173 
00174     p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
00175     q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
00176       exception);
00177     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00178       break;
00179     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00180     chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
00181     for (x=0; x < (long) image->columns; x++)
00182     {
00183       if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
00184         {
00185           *q=(*p);
00186           if (indexes != (IndexPacket *) NULL)
00187             {
00188               if (chop_indexes != (IndexPacket *) NULL)
00189                 *chop_indexes++=indexes[x];
00190             }
00191           q++;
00192         }
00193       p++;
00194     }
00195     if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00196       break;
00197     proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
00198     if (proceed == MagickFalse)
00199       break;
00200   }
00201   /*
00202     Extract chop image.
00203   */
00204   i+=extent.height;
00205   for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
00206   {
00207     register const PixelPacket
00208       *p;
00209 
00210     register IndexPacket
00211       *chop_indexes,
00212       *indexes;
00213 
00214     register long
00215       x;
00216 
00217     register PixelPacket
00218       *q;
00219 
00220     p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
00221     q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
00222       exception);
00223     if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00224       break;
00225     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00226     chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
00227     for (x=0; x < (long) image->columns; x++)
00228     {
00229       if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
00230         {
00231           *q=(*p);
00232           if (indexes != (IndexPacket *) NULL)
00233             {
00234               if (chop_indexes != (IndexPacket *) NULL)
00235                 *chop_indexes++=indexes[x];
00236             }
00237           q++;
00238         }
00239       p++;
00240     }
00241     if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
00242       break;
00243     proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
00244     if (proceed == MagickFalse)
00245       break;
00246   }
00247   chop_view=DestroyCacheView(chop_view);
00248   image_view=DestroyCacheView(image_view);
00249   chop_image->type=image->type;
00250   return(chop_image);
00251 }
00252 
00253 /*
00254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00255 %                                                                             %
00256 %                                                                             %
00257 %                                                                             %
00258 +     C o n s o l i d a t e C M Y K I m a g e                                 %
00259 %                                                                             %
00260 %                                                                             %
00261 %                                                                             %
00262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00263 %
00264 %  ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
00265 %  single image.
00266 %
00267 %  The format of the ConsolidateCMYKImage method is:
00268 %
00269 %      Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
00270 %
00271 %  A description of each parameter follows:
00272 %
00273 %    o image: the image sequence.
00274 %
00275 %    o exception: return any errors or warnings in this structure.
00276 %
00277 */
00278 MagickExport Image *ConsolidateCMYKImages(const Image *images,
00279   ExceptionInfo *exception)
00280 {
00281   Image
00282     *cmyk_image,
00283     *cmyk_images;
00284 
00285   long
00286     y;
00287 
00288   register long
00289     i;
00290 
00291   /*
00292     Consolidate separate C, M, Y, and K planes into a single image.
00293   */
00294   assert(images != (Image *) NULL);
00295   assert(images->signature == MagickSignature);
00296   if (images->debug != MagickFalse)
00297     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00298   assert(exception != (ExceptionInfo *) NULL);
00299   assert(exception->signature == MagickSignature);
00300   cmyk_images=NewImageList();
00301   for (i=0; i < (long) GetImageListLength(images); i+=4)
00302   {
00303     cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
00304       exception);
00305     if (cmyk_image == (Image *) NULL)
00306       break;
00307     if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
00308       break;
00309     cmyk_image->colorspace=CMYKColorspace;
00310     for (y=0; y < (long) images->rows; y++)
00311     {
00312       register const PixelPacket
00313         *p;
00314 
00315       register long
00316         x;
00317 
00318       register PixelPacket
00319         *q;
00320 
00321       p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00322       q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00323       if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00324         break;
00325       for (x=0; x < (long) images->columns; x++)
00326       {
00327         q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00328         p++;
00329         q++;
00330       }
00331       if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00332         break;
00333     }
00334     images=GetNextImageInList(images);
00335     if (images == (Image *) NULL)
00336       break;
00337     for (y=0; y < (long) images->rows; y++)
00338     {
00339       register const PixelPacket
00340         *p;
00341 
00342       register long
00343         x;
00344 
00345       register PixelPacket
00346         *q;
00347 
00348       p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00349       q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00350       if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00351         break;
00352       for (x=0; x < (long) images->columns; x++)
00353       {
00354         q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00355         p++;
00356         q++;
00357       }
00358       if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00359         break;
00360     }
00361     images=GetNextImageInList(images);
00362     if (images == (Image *) NULL)
00363       break;
00364     for (y=0; y < (long) images->rows; y++)
00365     {
00366       register const PixelPacket
00367         *p;
00368 
00369       register long
00370         x;
00371 
00372       register PixelPacket
00373         *q;
00374 
00375       p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00376       q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00377       if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00378         break;
00379       for (x=0; x < (long) images->columns; x++)
00380       {
00381         q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
00382         p++;
00383         q++;
00384       }
00385       if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00386         break;
00387     }
00388     images=GetNextImageInList(images);
00389     if (images == (Image *) NULL)
00390       break;
00391     for (y=0; y < (long) images->rows; y++)
00392     {
00393       register const PixelPacket
00394         *p;
00395 
00396       register IndexPacket
00397         *indexes;
00398 
00399       register long
00400         x;
00401 
00402       register PixelPacket
00403         *q;
00404 
00405       p=GetVirtualPixels(images,0,y,images->columns,1,exception);
00406       q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
00407       if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00408         break;
00409       indexes=GetAuthenticIndexQueue(cmyk_image);
00410       for (x=0; x < (long) images->columns; x++)
00411       {
00412         indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
00413         p++;
00414       }
00415       if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
00416         break;
00417     }
00418     AppendImageToList(&cmyk_images,cmyk_image);
00419     images=GetNextImageInList(images);
00420     if (images == (Image *) NULL)
00421       break;
00422   }
00423   return(cmyk_images);
00424 }
00425 
00426 /*
00427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00428 %                                                                             %
00429 %                                                                             %
00430 %                                                                             %
00431 %   C r o p I m a g e                                                         %
00432 %                                                                             %
00433 %                                                                             %
00434 %                                                                             %
00435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00436 %
00437 %  CropImage() extracts a region of the image starting at the offset defined
00438 %  by geometry.
00439 %
00440 %  The format of the CropImage method is:
00441 %
00442 %      Image *CropImage(const Image *image,const RectangleInfo *geometry,
00443 %        ExceptionInfo *exception)
00444 %
00445 %  A description of each parameter follows:
00446 %
00447 %    o image: the image.
00448 %
00449 %    o geometry: Define the region of the image to crop with members
00450 %      x, y, width, and height.
00451 %
00452 %    o exception: return any errors or warnings in this structure.
00453 %
00454 */
00455 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
00456   ExceptionInfo *exception)
00457 {
00458 #define CropImageTag  "Crop/Image"
00459 
00460   Image
00461     *crop_image;
00462 
00463   long
00464     progress,
00465     y;
00466 
00467   MagickBooleanType
00468     status;
00469 
00470   RectangleInfo
00471     bounding_box,
00472     page;
00473 
00474   ViewInfo
00475     *crop_view,
00476     *image_view;
00477 
00478   /*
00479     Check crop geometry.
00480   */
00481   assert(image != (const Image *) NULL);
00482   assert(image->signature == MagickSignature);
00483   if (image->debug != MagickFalse)
00484     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00485   assert(geometry != (const RectangleInfo *) NULL);
00486   assert(exception != (ExceptionInfo *) NULL);
00487   assert(exception->signature == MagickSignature);
00488   bounding_box=image->page;
00489   if ((bounding_box.width == 0) || (bounding_box.height == 0))
00490     {
00491       bounding_box.width=image->columns;
00492       bounding_box.height=image->rows;
00493     }
00494   page=(*geometry);
00495   if (page.width == 0)
00496     page.width=bounding_box.width;
00497   if (page.height == 0)
00498     page.height=bounding_box.height;
00499   if (((bounding_box.x-page.x) >= (long) page.width) ||
00500       ((bounding_box.y-page.y) >= (long) page.height) ||
00501       ((page.x-bounding_box.x) > (long) image->columns) ||
00502       ((page.y-bounding_box.y) > (long) image->rows))
00503     {
00504       /*
00505         Crop is not within virtual canvas, return 1 pixel transparent image.
00506       */
00507       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00508         "GeometryDoesNotContainImage","`%s'",image->filename);
00509       crop_image=CloneImage(image,1,1,MagickTrue,exception);
00510       if (crop_image == (Image *) NULL)
00511         return((Image *) NULL);
00512       crop_image->background_color.opacity=(Quantum) TransparentOpacity;
00513       (void) SetImageBackgroundColor(crop_image);
00514       crop_image->page=bounding_box;
00515       crop_image->page.x=(-1);
00516       crop_image->page.y=(-1);
00517       if ( crop_image->dispose == BackgroundDispose )
00518         crop_image->dispose = NoneDispose;
00519       return(crop_image);
00520     }
00521   if ((page.x < 0) && (bounding_box.x >= 0))
00522     {
00523       page.width+=page.x-bounding_box.x;
00524       page.x=0;
00525     }
00526   else
00527     {
00528       page.width-=bounding_box.x-page.x;
00529       page.x-=bounding_box.x;
00530       if (page.x < 0)
00531         page.x=0;
00532     }
00533   if ((page.y < 0) && (bounding_box.y >= 0))
00534     {
00535       page.height+=page.y-bounding_box.y;
00536       page.y=0;
00537     }
00538   else
00539     {
00540       page.height-=bounding_box.y-page.y;
00541       page.y-=bounding_box.y;
00542       if (page.y < 0)
00543         page.y=0;
00544     }
00545   if ((unsigned long) (page.x+page.width) > image->columns)
00546     page.width=image->columns-page.x;
00547   if (geometry->width != 0)
00548     if (page.width > geometry->width)
00549       page.width=geometry->width;
00550   if ((unsigned long) (page.y+page.height) > image->rows)
00551     page.height=image->rows-page.y;
00552   if (geometry->height != 0)
00553     if (page.height > geometry->height)
00554       page.height=geometry->height;
00555   bounding_box.x+=page.x;
00556   bounding_box.y+=page.y;
00557   /*
00558     Initialize crop image attributes.
00559   */
00560   crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
00561   if (crop_image == (Image *) NULL)
00562     return((Image *) NULL);
00563   crop_image->page.width=image->page.width;
00564   crop_image->page.height=image->page.height;
00565   if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
00566       ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
00567     {
00568       crop_image->page.width=bounding_box.width;
00569       crop_image->page.height=bounding_box.height;
00570     }
00571   crop_image->page.x=bounding_box.x;
00572   crop_image->page.y=bounding_box.y;
00573   /*
00574     Crop image.
00575   */
00576   status=MagickTrue;
00577   progress=0;
00578   image_view=AcquireCacheView(image);
00579   crop_view=AcquireCacheView(crop_image);
00580 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00581   #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00582 #endif
00583   for (y=0; y < (long) crop_image->rows; y++)
00584   {
00585     register const IndexPacket
00586       *indexes;
00587 
00588     register const PixelPacket
00589       *p;
00590 
00591     register IndexPacket
00592       *crop_indexes;
00593 
00594     register PixelPacket
00595       *q;
00596 
00597     if (status == MagickFalse)
00598       continue;
00599     p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
00600       1,exception);
00601     q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
00602       exception);
00603     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00604       {
00605         status=MagickFalse;
00606         continue;
00607       }
00608     (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
00609     indexes=GetCacheViewVirtualIndexQueue(image_view);
00610     if (indexes != (IndexPacket *) NULL)
00611       {
00612         crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
00613         if (crop_indexes != (IndexPacket *) NULL)
00614           (void) CopyMagickMemory(crop_indexes,indexes,(size_t)
00615             crop_image->columns*sizeof(*crop_indexes));
00616       }
00617     if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
00618       status=MagickFalse;
00619     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00620       {
00621         MagickBooleanType
00622           proceed;
00623 
00624 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00625   #pragma omp critical
00626 #endif
00627         proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
00628         if (proceed == MagickFalse)
00629           status=MagickFalse;
00630       }
00631   }
00632   crop_view=DestroyCacheView(crop_view);
00633   image_view=DestroyCacheView(image_view);
00634   crop_image->type=image->type;
00635   if (status == MagickFalse)
00636     crop_image=DestroyImage(crop_image);
00637   return(crop_image);
00638 }
00639 
00640 /*
00641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00642 %                                                                             %
00643 %                                                                             %
00644 %                                                                             %
00645 %   E x c e r p t I m a g e                                                   %
00646 %                                                                             %
00647 %                                                                             %
00648 %                                                                             %
00649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00650 %
00651 %  ExcerptImage() returns a excerpt of the image as defined by the geometry.
00652 %
00653 %  The format of the ExcerptImage method is:
00654 %
00655 %      Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
00656 %        ExceptionInfo *exception)
00657 %
00658 %  A description of each parameter follows:
00659 %
00660 %    o image: the image.
00661 %
00662 %    o geometry: Define the region of the image to extend with members
00663 %      x, y, width, and height.
00664 %
00665 %    o exception: return any errors or warnings in this structure.
00666 %
00667 */
00668 MagickExport Image *ExcerptImage(const Image *image,
00669   const RectangleInfo *geometry,ExceptionInfo *exception)
00670 {
00671 #define ExcerptImageTag  "Excerpt/Image"
00672 
00673   Image
00674     *excerpt_image;
00675 
00676   long
00677     progress,
00678     y;
00679 
00680   MagickBooleanType
00681     status;
00682 
00683   ViewInfo
00684     *excerpt_view,
00685     *image_view;
00686 
00687   /*
00688     Allocate excerpt image.
00689   */
00690   assert(image != (const Image *) NULL);
00691   assert(image->signature == MagickSignature);
00692   if (image->debug != MagickFalse)
00693     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00694   assert(geometry != (const RectangleInfo *) NULL);
00695   assert(exception != (ExceptionInfo *) NULL);
00696   assert(exception->signature == MagickSignature);
00697   excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
00698     exception);
00699   if (excerpt_image == (Image *) NULL)
00700     return((Image *) NULL);
00701   /*
00702     Excerpt each row.
00703   */
00704   status=MagickTrue;
00705   progress=0;
00706   image_view=AcquireCacheView(image);
00707   excerpt_view=AcquireCacheView(excerpt_image);
00708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00709   #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00710 #endif
00711   for (y=0; y < (long) excerpt_image->rows; y++)
00712   {
00713     register const PixelPacket
00714       *p;
00715 
00716     register IndexPacket
00717       *excerpt_indexes,
00718       *indexes;
00719 
00720     register PixelPacket
00721       *q;
00722 
00723     if (status == MagickFalse)
00724       continue;
00725     p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
00726       geometry->width,1,exception);
00727     q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
00728       exception);
00729     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00730       {
00731         status=MagickFalse;
00732         continue;
00733       }
00734     (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
00735     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00736     if (indexes != (IndexPacket *) NULL)
00737       {
00738         excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
00739         if (excerpt_indexes != (IndexPacket *) NULL)
00740           (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
00741             excerpt_image->columns*sizeof(*excerpt_indexes));
00742       }
00743     if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
00744       status=MagickFalse;
00745     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00746       {
00747         MagickBooleanType
00748           proceed;
00749 
00750 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00751   #pragma omp critical
00752 #endif
00753         proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
00754         if (proceed == MagickFalse)
00755           status=MagickFalse;
00756       }
00757   }
00758   excerpt_view=DestroyCacheView(excerpt_view);
00759   image_view=DestroyCacheView(image_view);
00760   excerpt_image->type=image->type;
00761   if (status == MagickFalse)
00762     excerpt_image=DestroyImage(excerpt_image);
00763   return(excerpt_image);
00764 }
00765 
00766 /*
00767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00768 %                                                                             %
00769 %                                                                             %
00770 %                                                                             %
00771 %   E x t e n t I m a g e                                                     %
00772 %                                                                             %
00773 %                                                                             %
00774 %                                                                             %
00775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00776 %
00777 %  ExtentImage() extends the image as defined by the geometry, gravity, and
00778 %  image background color.  Set the (x,y) offset of the geometry to move the
00779 %  original image relative to the extended image.
00780 %
00781 %  The format of the ExtentImage method is:
00782 %
00783 %      Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
00784 %        ExceptionInfo *exception)
00785 %
00786 %  A description of each parameter follows:
00787 %
00788 %    o image: the image.
00789 %
00790 %    o geometry: Define the region of the image to extend with members
00791 %      x, y, width, and height.
00792 %
00793 %    o exception: return any errors or warnings in this structure.
00794 %
00795 */
00796 MagickExport Image *ExtentImage(const Image *image,
00797   const RectangleInfo *geometry,ExceptionInfo *exception)
00798 {
00799   Image
00800     *extent_image;
00801 
00802   /*
00803     Allocate extent image.
00804   */
00805   assert(image != (const Image *) NULL);
00806   assert(image->signature == MagickSignature);
00807   if (image->debug != MagickFalse)
00808     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00809   assert(geometry != (const RectangleInfo *) NULL);
00810   assert(exception != (ExceptionInfo *) NULL);
00811   assert(exception->signature == MagickSignature);
00812   extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
00813     exception);
00814   if (extent_image == (Image *) NULL)
00815     return((Image *) NULL);
00816   if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
00817     {
00818       InheritException(exception,&extent_image->exception);
00819       extent_image=DestroyImage(extent_image);
00820       return((Image *) NULL);
00821     }
00822   if (image->background_color.opacity != OpaqueOpacity)
00823     extent_image->matte=MagickTrue;
00824   (void) SetImageBackgroundColor(extent_image);
00825   (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
00826     -geometry->y);
00827   return(extent_image);
00828 }
00829 
00830 /*
00831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00832 %                                                                             %
00833 %                                                                             %
00834 %                                                                             %
00835 %   F l i p I m a g e                                                         %
00836 %                                                                             %
00837 %                                                                             %
00838 %                                                                             %
00839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00840 %
00841 %  FlipImage() creates a vertical mirror image by reflecting the pixels
00842 %  around the central x-axis.
00843 %
00844 %  The format of the FlipImage method is:
00845 %
00846 %      Image *FlipImage(const Image *image,ExceptionInfo *exception)
00847 %
00848 %  A description of each parameter follows:
00849 %
00850 %    o image: the image.
00851 %
00852 %    o exception: return any errors or warnings in this structure.
00853 %
00854 */
00855 MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
00856 {
00857 #define FlipImageTag  "Flip/Image"
00858 
00859   Image
00860     *flip_image;
00861 
00862   long
00863     progress,
00864     y;
00865 
00866   MagickBooleanType
00867     status;
00868 
00869   ViewInfo
00870     *flip_view,
00871     *image_view;
00872 
00873   assert(image != (const Image *) NULL);
00874   assert(image->signature == MagickSignature);
00875   if (image->debug != MagickFalse)
00876     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00877   assert(exception != (ExceptionInfo *) NULL);
00878   assert(exception->signature == MagickSignature);
00879   flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00880   if (flip_image == (Image *) NULL)
00881     return((Image *) NULL);
00882   /*
00883     Flip image.
00884   */
00885   status=MagickTrue;
00886   progress=0;
00887   image_view=AcquireCacheView(image);
00888   flip_view=AcquireCacheView(flip_image);
00889 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00890   #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00891 #endif
00892   for (y=0; y < (long) flip_image->rows; y++)
00893   {
00894     register const IndexPacket
00895       *indexes;
00896 
00897     register const PixelPacket
00898       *p;
00899 
00900     register IndexPacket
00901       *flip_indexes;
00902 
00903     register PixelPacket
00904       *q;
00905 
00906     if (status == MagickFalse)
00907       continue;
00908     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00909     q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
00910       flip_image->columns,1,exception);
00911     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00912       {
00913         status=MagickFalse;
00914         continue;
00915       }
00916     (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
00917     indexes=GetCacheViewVirtualIndexQueue(image_view);
00918     flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
00919     if ((indexes != (const IndexPacket *) NULL) &&
00920         (flip_indexes != (IndexPacket *) NULL))
00921       (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
00922         sizeof(*flip_indexes));
00923     if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
00924       status=MagickFalse;
00925     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00926       {
00927         MagickBooleanType
00928           proceed;
00929 
00930 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00931   #pragma omp critical
00932 #endif
00933         proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
00934         if (proceed == MagickFalse)
00935           status=MagickFalse;
00936       }
00937   }
00938   flip_view=DestroyCacheView(flip_view);
00939   image_view=DestroyCacheView(image_view);
00940   flip_image->type=image->type;
00941   if (status == MagickFalse)
00942     flip_image=DestroyImage(flip_image);
00943   return(flip_image);
00944 }
00945 
00946 /*
00947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00948 %                                                                             %
00949 %                                                                             %
00950 %                                                                             %
00951 %   F l o p I m a g e                                                         %
00952 %                                                                             %
00953 %                                                                             %
00954 %                                                                             %
00955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00956 %
00957 %  FlopImage() creates a horizontal mirror image by reflecting the pixels
00958 %  around the central y-axis.
00959 %
00960 %  The format of the FlopImage method is:
00961 %
00962 %      Image *FlopImage(const Image *image,ExceptionInfo *exception)
00963 %
00964 %  A description of each parameter follows:
00965 %
00966 %    o image: the image.
00967 %
00968 %    o exception: return any errors or warnings in this structure.
00969 %
00970 */
00971 MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
00972 {
00973 #define FlopImageTag  "Flop/Image"
00974 
00975   Image
00976     *flop_image;
00977 
00978   long
00979     progress,
00980     y;
00981 
00982   MagickBooleanType
00983     status;
00984 
00985   ViewInfo
00986     *flop_view,
00987     *image_view;
00988 
00989   assert(image != (const Image *) NULL);
00990   assert(image->signature == MagickSignature);
00991   if (image->debug != MagickFalse)
00992     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00993   assert(exception != (ExceptionInfo *) NULL);
00994   assert(exception->signature == MagickSignature);
00995   flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00996   if (flop_image == (Image *) NULL)
00997     return((