transform.c

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

Generated on Thu Jul 2 12:03:22 2009 for MagickCore by  doxygen 1.5.8