MagickCore  7.0.3
transform.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
7 % T R R A A NN N SS F O O R R MM MM %
8 % T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
9 % T R R A A N NN SS F O O R R M M %
10 % T R R A A N N SSSSS F OOO R R M M %
11 % %
12 % %
13 % MagickCore Image Transform Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/cache.h"
45 #include "MagickCore/cache-view.h"
46 #include "MagickCore/color.h"
49 #include "MagickCore/composite.h"
50 #include "MagickCore/distort.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/effect.h"
53 #include "MagickCore/exception.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/layer.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/monitor.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/resize.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
68 #include "MagickCore/transform.h"
70 
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 % %
74 % %
75 % %
76 % A u t o O r i e n t I m a g e %
77 % %
78 % %
79 % %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 % AutoOrientImage() adjusts an image so that its orientation is suitable for
83 % viewing (i.e. top-left orientation).
84 %
85 % The format of the AutoOrientImage method is:
86 %
87 % Image *AutoOrientImage(const Image *image,
88 % const OrientationType orientation,ExceptionInfo *exception)
89 %
90 % A description of each parameter follows:
91 %
92 % o image: The image.
93 %
94 % o orientation: Current image orientation.
95 %
96 % o exception: Return any errors or warnings in this structure.
97 %
98 */
100  const OrientationType orientation,ExceptionInfo *exception)
101 {
102  Image
103  *orient_image;
104 
105  assert(image != (const Image *) NULL);
106  assert(image->signature == MagickCoreSignature);
107  assert(exception != (ExceptionInfo *) NULL);
108  assert(exception->signature == MagickCoreSignature);
109  orient_image=(Image *) NULL;
110  switch(orientation)
111  {
113  case TopLeftOrientation:
114  default:
115  {
116  orient_image=CloneImage(image,0,0,MagickTrue,exception);
117  break;
118  }
119  case TopRightOrientation:
120  {
121  orient_image=FlopImage(image,exception);
122  break;
123  }
125  {
126  orient_image=RotateImage(image,180.0,exception);
127  break;
128  }
130  {
131  orient_image=FlipImage(image,exception);
132  break;
133  }
134  case LeftTopOrientation:
135  {
136  orient_image=TransposeImage(image,exception);
137  break;
138  }
139  case RightTopOrientation:
140  {
141  orient_image=RotateImage(image,90.0,exception);
142  break;
143  }
145  {
146  orient_image=TransverseImage(image,exception);
147  break;
148  }
150  {
151  orient_image=RotateImage(image,270.0,exception);
152  break;
153  }
154  }
155  if (orient_image != (Image *) NULL)
156  orient_image->orientation=TopLeftOrientation;
157  return(orient_image);
158 }
159 
160 /*
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162 % %
163 % %
164 % %
165 % C h o p I m a g e %
166 % %
167 % %
168 % %
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 %
171 % ChopImage() removes a region of an image and collapses the image to occupy
172 % the removed portion.
173 %
174 % The format of the ChopImage method is:
175 %
176 % Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
177 % ExceptionInfo *exception)
178 %
179 % A description of each parameter follows:
180 %
181 % o image: the image.
182 %
183 % o chop_info: Define the region of the image to chop.
184 %
185 % o exception: return any errors or warnings in this structure.
186 %
187 */
188 MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
189  ExceptionInfo *exception)
190 {
191 #define ChopImageTag "Chop/Image"
192 
193  CacheView
194  *chop_view,
195  *image_view;
196 
197  Image
198  *chop_image;
199 
201  status;
202 
204  progress;
205 
207  extent;
208 
209  ssize_t
210  y;
211 
212  /*
213  Check chop geometry.
214  */
215  assert(image != (const Image *) NULL);
216  assert(image->signature == MagickCoreSignature);
217  if (image->debug != MagickFalse)
218  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
219  assert(exception != (ExceptionInfo *) NULL);
220  assert(exception->signature == MagickCoreSignature);
221  assert(chop_info != (RectangleInfo *) NULL);
222  if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
223  ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
224  (chop_info->x > (ssize_t) image->columns) ||
225  (chop_info->y > (ssize_t) image->rows))
226  ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
227  extent=(*chop_info);
228  if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
229  extent.width=(size_t) ((ssize_t) image->columns-extent.x);
230  if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
231  extent.height=(size_t) ((ssize_t) image->rows-extent.y);
232  if (extent.x < 0)
233  {
234  extent.width-=(size_t) (-extent.x);
235  extent.x=0;
236  }
237  if (extent.y < 0)
238  {
239  extent.height-=(size_t) (-extent.y);
240  extent.y=0;
241  }
242  chop_image=CloneImage(image,image->columns-extent.width,image->rows-
243  extent.height,MagickTrue,exception);
244  if (chop_image == (Image *) NULL)
245  return((Image *) NULL);
246  /*
247  Extract chop image.
248  */
249  status=MagickTrue;
250  progress=0;
251  image_view=AcquireVirtualCacheView(image,exception);
252  chop_view=AcquireAuthenticCacheView(chop_image,exception);
253 #if defined(MAGICKCORE_OPENMP_SUPPORT)
254  #pragma omp parallel for schedule(static) shared(status) \
255  magick_number_threads(image,chop_image,extent.y,1)
256 #endif
257  for (y=0; y < (ssize_t) extent.y; y++)
258  {
259  register const Quantum
260  *magick_restrict p;
261 
262  register ssize_t
263  x;
264 
265  register Quantum
266  *magick_restrict q;
267 
268  if (status == MagickFalse)
269  continue;
270  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
271  q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
272  exception);
273  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
274  {
275  status=MagickFalse;
276  continue;
277  }
278  for (x=0; x < (ssize_t) image->columns; x++)
279  {
280  if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
281  {
282  register ssize_t
283  i;
284 
285  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
286  {
287  PixelChannel channel = GetPixelChannelChannel(image,i);
288  PixelTrait traits = GetPixelChannelTraits(image,channel);
289  PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
290  if ((traits == UndefinedPixelTrait) ||
291  (chop_traits == UndefinedPixelTrait))
292  continue;
293  SetPixelChannel(chop_image,channel,p[i],q);
294  }
295  q+=GetPixelChannels(chop_image);
296  }
297  p+=GetPixelChannels(image);
298  }
299  if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
300  status=MagickFalse;
301  if (image->progress_monitor != (MagickProgressMonitor) NULL)
302  {
304  proceed;
305 
306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
307  #pragma omp atomic
308 #endif
309  progress++;
310  proceed=SetImageProgress(image,ChopImageTag,progress,image->rows);
311  if (proceed == MagickFalse)
312  status=MagickFalse;
313  }
314  }
315  /*
316  Extract chop image.
317  */
318 #if defined(MAGICKCORE_OPENMP_SUPPORT)
319  #pragma omp parallel for schedule(static) shared(progress,status) \
320  magick_number_threads(image,chop_image,image->rows-(extent.y+extent.height),1)
321 #endif
322  for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
323  {
324  register const Quantum
325  *magick_restrict p;
326 
327  register ssize_t
328  x;
329 
330  register Quantum
331  *magick_restrict q;
332 
333  if (status == MagickFalse)
334  continue;
335  p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
336  image->columns,1,exception);
337  q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
338  1,exception);
339  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
340  {
341  status=MagickFalse;
342  continue;
343  }
344  for (x=0; x < (ssize_t) image->columns; x++)
345  {
346  if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
347  {
348  register ssize_t
349  i;
350 
351  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
352  {
353  PixelChannel channel = GetPixelChannelChannel(image,i);
354  PixelTrait traits = GetPixelChannelTraits(image,channel);
355  PixelTrait chop_traits=GetPixelChannelTraits(chop_image,channel);
356  if ((traits == UndefinedPixelTrait) ||
357  (chop_traits == UndefinedPixelTrait))
358  continue;
359  SetPixelChannel(chop_image,channel,p[i],q);
360  }
361  q+=GetPixelChannels(chop_image);
362  }
363  p+=GetPixelChannels(image);
364  }
365  if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
366  status=MagickFalse;
367  if (image->progress_monitor != (MagickProgressMonitor) NULL)
368  {
370  proceed;
371 
372 #if defined(MAGICKCORE_OPENMP_SUPPORT)
373  #pragma omp atomic
374 #endif
375  progress++;
376  proceed=SetImageProgress(image,ChopImageTag,progress,image->rows);
377  if (proceed == MagickFalse)
378  status=MagickFalse;
379  }
380  }
381  chop_view=DestroyCacheView(chop_view);
382  image_view=DestroyCacheView(image_view);
383  chop_image->type=image->type;
384  if (status == MagickFalse)
385  chop_image=DestroyImage(chop_image);
386  return(chop_image);
387 }
388 
389 /*
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391 % %
392 % %
393 % %
394 + C o n s o l i d a t e C M Y K I m a g e %
395 % %
396 % %
397 % %
398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399 %
400 % ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
401 % single image.
402 %
403 % The format of the ConsolidateCMYKImage method is:
404 %
405 % Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
406 %
407 % A description of each parameter follows:
408 %
409 % o image: the image sequence.
410 %
411 % o exception: return any errors or warnings in this structure.
412 %
413 */
415  ExceptionInfo *exception)
416 {
417  CacheView
418  *cmyk_view,
419  *image_view;
420 
421  Image
422  *cmyk_image,
423  *cmyk_images;
424 
425  register ssize_t
426  j;
427 
428  ssize_t
429  y;
430 
431  /*
432  Consolidate separate C, M, Y, and K planes into a single image.
433  */
434  assert(images != (Image *) NULL);
435  assert(images->signature == MagickCoreSignature);
436  if (images->debug != MagickFalse)
437  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
438  assert(exception != (ExceptionInfo *) NULL);
439  assert(exception->signature == MagickCoreSignature);
440  cmyk_images=NewImageList();
441  for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
442  {
443  register ssize_t
444  i;
445 
446  assert(images != (Image *) NULL);
447  cmyk_image=CloneImage(images,0,0,MagickTrue,
448  exception);
449  if (cmyk_image == (Image *) NULL)
450  break;
451  if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
452  break;
453  (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
454  for (i=0; i < 4; i++)
455  {
456  image_view=AcquireVirtualCacheView(images,exception);
457  cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
458  for (y=0; y < (ssize_t) images->rows; y++)
459  {
460  register const Quantum
461  *magick_restrict p;
462 
463  register ssize_t
464  x;
465 
466  register Quantum
467  *magick_restrict q;
468 
469  p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
470  q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
471  exception);
472  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
473  break;
474  for (x=0; x < (ssize_t) images->columns; x++)
475  {
476  Quantum
477  pixel;
478 
480  switch (i)
481  {
482  case 0: SetPixelCyan(cmyk_image,pixel,q); break;
483  case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
484  case 2: SetPixelYellow(cmyk_image,pixel,q); break;
485  case 3: SetPixelBlack(cmyk_image,pixel,q); break;
486  default: break;
487  }
488  p+=GetPixelChannels(images);
489  q+=GetPixelChannels(cmyk_image);
490  }
491  if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
492  break;
493  }
494  cmyk_view=DestroyCacheView(cmyk_view);
495  image_view=DestroyCacheView(image_view);
496  images=GetNextImageInList(images);
497  if (images == (Image *) NULL)
498  break;
499  }
500  AppendImageToList(&cmyk_images,cmyk_image);
501  }
502  return(cmyk_images);
503 }
504 
505 /*
506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 % %
508 % %
509 % %
510 % C r o p I m a g e %
511 % %
512 % %
513 % %
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515 %
516 % CropImage() extracts a region of the image starting at the offset defined
517 % by geometry. Region must be fully defined, and no special handling of
518 % geometry flags is performed.
519 %
520 % The format of the CropImage method is:
521 %
522 % Image *CropImage(const Image *image,const RectangleInfo *geometry,
523 % ExceptionInfo *exception)
524 %
525 % A description of each parameter follows:
526 %
527 % o image: the image.
528 %
529 % o geometry: Define the region of the image to crop with members
530 % x, y, width, and height.
531 %
532 % o exception: return any errors or warnings in this structure.
533 %
534 */
535 MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
536  ExceptionInfo *exception)
537 {
538 #define CropImageTag "Crop/Image"
539 
540  CacheView
541  *crop_view,
542  *image_view;
543 
544  Image
545  *crop_image;
546 
548  status;
549 
551  progress;
552 
553  OffsetInfo
554  offset;
555 
557  bounding_box,
558  page;
559 
560  ssize_t
561  y;
562 
563  /*
564  Check crop geometry.
565  */
566  assert(image != (const Image *) NULL);
567  assert(image->signature == MagickCoreSignature);
568  if (image->debug != MagickFalse)
569  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
570  assert(geometry != (const RectangleInfo *) NULL);
571  assert(exception != (ExceptionInfo *) NULL);
572  assert(exception->signature == MagickCoreSignature);
573  bounding_box=image->page;
574  if ((bounding_box.width == 0) || (bounding_box.height == 0))
575  {
576  bounding_box.width=image->columns;
577  bounding_box.height=image->rows;
578  }
579  page=(*geometry);
580  if (page.width == 0)
581  page.width=bounding_box.width;
582  if (page.height == 0)
583  page.height=bounding_box.height;
584  if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
585  ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
586  ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
587  ((page.y-bounding_box.y) > (ssize_t) image->rows))
588  {
589  /*
590  Crop is not within virtual canvas, return 1 pixel transparent image.
591  */
593  "GeometryDoesNotContainImage","`%s'",image->filename);
594  crop_image=CloneImage(image,1,1,MagickTrue,exception);
595  if (crop_image == (Image *) NULL)
596  return((Image *) NULL);
598  crop_image->alpha_trait=BlendPixelTrait;
599  (void) SetImageBackgroundColor(crop_image,exception);
600  crop_image->page=bounding_box;
601  crop_image->page.x=(-1);
602  crop_image->page.y=(-1);
603  if (crop_image->dispose == BackgroundDispose)
604  crop_image->dispose=NoneDispose;
605  return(crop_image);
606  }
607  if ((page.x < 0) && (bounding_box.x >= 0))
608  {
609  page.width+=page.x-bounding_box.x;
610  page.x=0;
611  }
612  else
613  {
614  page.width-=bounding_box.x-page.x;
615  page.x-=bounding_box.x;
616  if (page.x < 0)
617  page.x=0;
618  }
619  if ((page.y < 0) && (bounding_box.y >= 0))
620  {
621  page.height+=page.y-bounding_box.y;
622  page.y=0;
623  }
624  else
625  {
626  page.height-=bounding_box.y-page.y;
627  page.y-=bounding_box.y;
628  if (page.y < 0)
629  page.y=0;
630  }
631  if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
632  page.width=image->columns-page.x;
633  if ((geometry->width != 0) && (page.width > geometry->width))
634  page.width=geometry->width;
635  if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
636  page.height=image->rows-page.y;
637  if ((geometry->height != 0) && (page.height > geometry->height))
638  page.height=geometry->height;
639  bounding_box.x+=page.x;
640  bounding_box.y+=page.y;
641  if ((page.width == 0) || (page.height == 0))
642  {
644  "GeometryDoesNotContainImage","`%s'",image->filename);
645  return((Image *) NULL);
646  }
647  /*
648  Initialize crop image attributes.
649  */
650  crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
651  if (crop_image == (Image *) NULL)
652  return((Image *) NULL);
653  crop_image->page.width=image->page.width;
654  crop_image->page.height=image->page.height;
655  offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
656  offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
657  if ((offset.x > (ssize_t) image->page.width) ||
658  (offset.y > (ssize_t) image->page.height))
659  {
660  crop_image->page.width=bounding_box.width;
661  crop_image->page.height=bounding_box.height;
662  }
663  crop_image->page.x=bounding_box.x;
664  crop_image->page.y=bounding_box.y;
665  /*
666  Crop image.
667  */
668  status=MagickTrue;
669  progress=0;
670  image_view=AcquireVirtualCacheView(image,exception);
671  crop_view=AcquireAuthenticCacheView(crop_image,exception);
672 #if defined(MAGICKCORE_OPENMP_SUPPORT)
673  #pragma omp parallel for schedule(static) shared(status) \
674  magick_number_threads(image,crop_image,crop_image->rows,1)
675 #endif
676  for (y=0; y < (ssize_t) crop_image->rows; y++)
677  {
678  register const Quantum
679  *magick_restrict p;
680 
681  register Quantum
682  *magick_restrict q;
683 
684  register ssize_t
685  x;
686 
687  if (status == MagickFalse)
688  continue;
689  p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
690  1,exception);
691  q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
692  exception);
693  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
694  {
695  status=MagickFalse;
696  continue;
697  }
698  for (x=0; x < (ssize_t) crop_image->columns; x++)
699  {
700  register ssize_t
701  i;
702 
703  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
704  {
705  PixelChannel channel = GetPixelChannelChannel(image,i);
706  PixelTrait traits = GetPixelChannelTraits(image,channel);
707  PixelTrait crop_traits=GetPixelChannelTraits(crop_image,channel);
708  if ((traits == UndefinedPixelTrait) ||
709  (crop_traits == UndefinedPixelTrait))
710  continue;
711  SetPixelChannel(crop_image,channel,p[i],q);
712  }
713  p+=GetPixelChannels(image);
714  q+=GetPixelChannels(crop_image);
715  }
716  if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
717  status=MagickFalse;
718  if (image->progress_monitor != (MagickProgressMonitor) NULL)
719  {
721  proceed;
722 
723 #if defined(MAGICKCORE_OPENMP_SUPPORT)
724  #pragma omp atomic
725 #endif
726  progress++;
727  proceed=SetImageProgress(image,CropImageTag,progress,image->rows);
728  if (proceed == MagickFalse)
729  status=MagickFalse;
730  }
731  }
732  crop_view=DestroyCacheView(crop_view);
733  image_view=DestroyCacheView(image_view);
734  crop_image->type=image->type;
735  if (status == MagickFalse)
736  crop_image=DestroyImage(crop_image);
737  return(crop_image);
738 }
739 
740 /*
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 % %
743 % %
744 % %
745 % C r o p I m a g e T o T i l e s %
746 % %
747 % %
748 % %
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 %
751 % CropImageToTiles() crops a single image, into a possible list of tiles.
752 % This may include a single sub-region of the image. This basically applies
753 % all the normal geometry flags for Crop.
754 %
755 % Image *CropImageToTiles(const Image *image,
756 % const RectangleInfo *crop_geometry, ExceptionInfo *exception)
757 %
758 % A description of each parameter follows:
759 %
760 % o image: the image The transformed image is returned as this parameter.
761 %
762 % o crop_geometry: A crop geometry string.
763 %
764 % o exception: return any errors or warnings in this structure.
765 %
766 */
767 
768 static inline double MagickRound(double x)
769 {
770  /*
771  Round the fraction to nearest integer.
772  */
773  if ((x-floor(x)) < (ceil(x)-x))
774  return(floor(x));
775  return(ceil(x));
776 }
777 
779  const char *crop_geometry,ExceptionInfo *exception)
780 {
781  Image
782  *next,
783  *crop_image;
784 
786  flags;
787 
789  geometry;
790 
791  assert(image != (Image *) NULL);
792  assert(image->signature == MagickCoreSignature);
793  if (image->debug != MagickFalse)
794  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
795  crop_image=NewImageList();
796  next=NewImageList();
797  flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
798  if ((flags & AreaValue) != 0)
799  {
800  PointInfo
801  delta,
802  offset;
803 
805  crop;
806 
807  size_t
808  height,
809  width;
810 
811  /*
812  Crop into NxM tiles (@ flag).
813  */
814  width=image->columns;
815  height=image->rows;
816  if (geometry.width == 0)
817  geometry.width=1;
818  if (geometry.height == 0)
819  geometry.height=1;
820  if ((flags & AspectValue) == 0)
821  {
822  width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
823  height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
824  }
825  else
826  {
827  width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
828  height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
829  }
830  delta.x=(double) width/geometry.width;
831  delta.y=(double) height/geometry.height;
832  if (delta.x < 1.0)
833  delta.x=1.0;
834  if (delta.y < 1.0)
835  delta.y=1.0;
836  for (offset.y=0; offset.y < (double) height; )
837  {
838  if ((flags & AspectValue) == 0)
839  {
840  crop.y=(ssize_t) MagickRound((double) (offset.y-
841  (geometry.y > 0 ? 0 : geometry.y)));
842  offset.y+=delta.y; /* increment now to find width */
843  crop.height=(size_t) MagickRound((double) (offset.y+
844  (geometry.y < 0 ? 0 : geometry.y)));
845  }
846  else
847  {
848  crop.y=(ssize_t) MagickRound((double) (offset.y-
849  (geometry.y > 0 ? geometry.y : 0)));
850  offset.y+=delta.y; /* increment now to find width */
851  crop.height=(size_t) MagickRound((double)
852  (offset.y+(geometry.y < -1 ? geometry.y : 0)));
853  }
854  crop.height-=crop.y;
855  crop.y+=image->page.y;
856  for (offset.x=0; offset.x < (double) width; )
857  {
858  if ((flags & AspectValue) == 0)
859  {
860  crop.x=(ssize_t) MagickRound((double) (offset.x-
861  (geometry.x > 0 ? 0 : geometry.x)));
862  offset.x+=delta.x; /* increment now to find height */
863  crop.width=(size_t) MagickRound((double) (offset.x+
864  (geometry.x < 0 ? 0 : geometry.x)));
865  }
866  else
867  {
868  crop.x=(ssize_t) MagickRound((double) (offset.x-
869  (geometry.x > 0 ? geometry.x : 0)));
870  offset.x+=delta.x; /* increment now to find height */
871  crop.width=(size_t) MagickRound((double) (offset.x+
872  (geometry.x < 0 ? geometry.x : 0)));
873  }
874  crop.width-=crop.x;
875  crop.x+=image->page.x;
876  next=CropImage(image,&crop,exception);
877  if (next != (Image *) NULL)
878  AppendImageToList(&crop_image,next);
879  }
880  }
881  ClearMagickException(exception);
882  return(crop_image);
883  }
884  if (((geometry.width == 0) && (geometry.height == 0)) ||
885  ((flags & XValue) != 0) || ((flags & YValue) != 0))
886  {
887  /*
888  Crop a single region at +X+Y.
889  */
890  crop_image=CropImage(image,&geometry,exception);
891  if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
892  {
893  crop_image->page.width=geometry.width;
894  crop_image->page.height=geometry.height;
895  crop_image->page.x-=geometry.x;
896  crop_image->page.y-=geometry.y;
897  }
898  return(crop_image);
899  }
900  if ((image->columns > geometry.width) || (image->rows > geometry.height))
901  {
903  page;
904 
905  size_t
906  height,
907  width;
908 
909  ssize_t
910  x,
911  y;
912 
913  /*
914  Crop into tiles of fixed size WxH.
915  */
916  page=image->page;
917  if (page.width == 0)
918  page.width=image->columns;
919  if (page.height == 0)
920  page.height=image->rows;
921  width=geometry.width;
922  if (width == 0)
923  width=page.width;
924  height=geometry.height;
925  if (height == 0)
926  height=page.height;
927  next=NewImageList();
928  for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
929  {
930  for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
931  {
932  geometry.width=width;
933  geometry.height=height;
934  geometry.x=x;
935  geometry.y=y;
936  next=CropImage(image,&geometry,exception);
937  if (next == (Image *) NULL)
938  break;
939  AppendImageToList(&crop_image,next);
940  }
941  if (next == (Image *) NULL)
942  break;
943  }
944  return(crop_image);
945  }
946  return(CloneImage(image,0,0,MagickTrue,exception));
947 }
948 
949 /*
950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
951 % %
952 % %
953 % %
954 % E x c e r p t I m a g e %
955 % %
956 % %
957 % %
958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959 %
960 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
961 %
962 % The format of the ExcerptImage method is:
963 %
964 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
965 % ExceptionInfo *exception)
966 %
967 % A description of each parameter follows:
968 %
969 % o image: the image.
970 %
971 % o geometry: Define the region of the image to extend with members
972 % x, y, width, and height.
973 %
974 % o exception: return any errors or warnings in this structure.
975 %
976 */
978  const RectangleInfo *geometry,ExceptionInfo *exception)
979 {
980 #define ExcerptImageTag "Excerpt/Image"
981 
982  CacheView
983  *excerpt_view,
984  *image_view;
985 
986  Image
987  *excerpt_image;
988 
990  status;
991 
993  progress;
994 
995  ssize_t
996  y;
997 
998  /*
999  Allocate excerpt image.
1000  */
1001  assert(image != (const Image *) NULL);
1002  assert(image->signature == MagickCoreSignature);
1003  if (image->debug != MagickFalse)
1004  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1005  assert(geometry != (const RectangleInfo *) NULL);
1006  assert(exception != (ExceptionInfo *) NULL);
1007  assert(exception->signature == MagickCoreSignature);
1008  excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1009  exception);
1010  if (excerpt_image == (Image *) NULL)
1011  return((Image *) NULL);
1012  /*
1013  Excerpt each row.
1014  */
1015  status=MagickTrue;
1016  progress=0;
1017  image_view=AcquireVirtualCacheView(image,exception);
1018  excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1019 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1020  #pragma omp parallel for schedule(static) shared(progress,status) \
1021  magick_number_threads(image,excerpt_image,excerpt_image->rows,1)
1022 #endif
1023  for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1024  {
1025  register const Quantum
1026  *magick_restrict p;
1027 
1028  register Quantum
1029  *magick_restrict q;
1030 
1031  register ssize_t
1032  x;
1033 
1034  if (status == MagickFalse)
1035  continue;
1036  p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1037  geometry->width,1,exception);
1038  q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1039  exception);
1040  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1041  {
1042  status=MagickFalse;
1043  continue;
1044  }
1045  for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1046  {
1047  register ssize_t
1048  i;
1049 
1050  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1051  {
1052  PixelChannel channel = GetPixelChannelChannel(image,i);
1053  PixelTrait traits = GetPixelChannelTraits(image,channel);
1054  PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1055  if ((traits == UndefinedPixelTrait) ||
1056  (excerpt_traits == UndefinedPixelTrait))
1057  continue;
1058  SetPixelChannel(excerpt_image,channel,p[i],q);
1059  }
1060  p+=GetPixelChannels(image);
1061  q+=GetPixelChannels(excerpt_image);
1062  }
1063  if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1064  status=MagickFalse;
1065  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1066  {
1068  proceed;
1069 
1070 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1071  #pragma omp atomic
1072 #endif
1073  progress++;
1074  proceed=SetImageProgress(image,ExcerptImageTag,progress,image->rows);
1075  if (proceed == MagickFalse)
1076  status=MagickFalse;
1077  }
1078  }
1079  excerpt_view=DestroyCacheView(excerpt_view);
1080  image_view=DestroyCacheView(image_view);
1081  excerpt_image->type=image->type;
1082  if (status == MagickFalse)
1083  excerpt_image=DestroyImage(excerpt_image);
1084  return(excerpt_image);
1085 }
1086 
1087 /*
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 % %
1090 % %
1091 % %
1092 % E x t e n t I m a g e %
1093 % %
1094 % %
1095 % %
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1097 %
1098 % ExtentImage() extends the image as defined by the geometry, gravity, and
1099 % image background color. Set the (x,y) offset of the geometry to move the
1100 % original image relative to the extended image.
1101 %
1102 % The format of the ExtentImage method is:
1103 %
1104 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1105 % ExceptionInfo *exception)
1106 %
1107 % A description of each parameter follows:
1108 %
1109 % o image: the image.
1110 %
1111 % o geometry: Define the region of the image to extend with members
1112 % x, y, width, and height.
1113 %
1114 % o exception: return any errors or warnings in this structure.
1115 %
1116 */
1118  const RectangleInfo *geometry,ExceptionInfo *exception)
1119 {
1120  Image
1121  *extent_image;
1122 
1124  status;
1125 
1126  /*
1127  Allocate extent image.
1128  */
1129  assert(image != (const Image *) NULL);
1130  assert(image->signature == MagickCoreSignature);
1131  if (image->debug != MagickFalse)
1132  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1133  assert(geometry != (const RectangleInfo *) NULL);
1134  assert(exception != (ExceptionInfo *) NULL);
1135  assert(exception->signature == MagickCoreSignature);
1136  extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1137  exception);
1138  if (extent_image == (Image *) NULL)
1139  return((Image *) NULL);
1140  status=SetImageBackgroundColor(extent_image,exception);
1141  if (status == MagickFalse)
1142  {
1143  extent_image=DestroyImage(extent_image);
1144  return((Image *) NULL);
1145  }
1146  status=CompositeImage(extent_image,image,image->compose,MagickTrue,
1147  -geometry->x,-geometry->y,exception);
1148  return(extent_image);
1149 }
1150 
1151 /*
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153 % %
1154 % %
1155 % %
1156 % F l i p I m a g e %
1157 % %
1158 % %
1159 % %
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161 %
1162 % FlipImage() creates a vertical mirror image by reflecting the pixels
1163 % around the central x-axis.
1164 %
1165 % The format of the FlipImage method is:
1166 %
1167 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1168 %
1169 % A description of each parameter follows:
1170 %
1171 % o image: the image.
1172 %
1173 % o exception: return any errors or warnings in this structure.
1174 %
1175 */
1177 {
1178 #define FlipImageTag "Flip/Image"
1179 
1180  CacheView
1181  *flip_view,
1182  *image_view;
1183 
1184  Image
1185  *flip_image;
1186 
1188  status;
1189 
1191  progress;
1192 
1194  page;
1195 
1196  ssize_t
1197  y;
1198 
1199  assert(image != (const Image *) NULL);
1200  assert(image->signature == MagickCoreSignature);
1201  if (image->debug != MagickFalse)
1202  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1203  assert(exception != (ExceptionInfo *) NULL);
1204  assert(exception->signature == MagickCoreSignature);
1205  flip_image=CloneImage(image,0,0,MagickTrue,exception);
1206  if (flip_image == (Image *) NULL)
1207  return((Image *) NULL);
1208  /*
1209  Flip image.
1210  */
1211  status=MagickTrue;
1212  progress=0;
1213  page=image->page;
1214  image_view=AcquireVirtualCacheView(image,exception);
1215  flip_view=AcquireAuthenticCacheView(flip_image,exception);
1216 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1217  #pragma omp parallel for schedule(static) shared(status) \
1218  magick_number_threads(image,flip_image,flip_image->rows,1)
1219 #endif
1220  for (y=0; y < (ssize_t) flip_image->rows; y++)
1221  {
1222  register const Quantum
1223  *magick_restrict p;
1224 
1225  register Quantum
1226  *magick_restrict q;
1227 
1228  register ssize_t
1229  x;
1230 
1231  if (status == MagickFalse)
1232  continue;
1233  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1234  q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1235  1),flip_image->columns,1,exception);
1236  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1237  {
1238  status=MagickFalse;
1239  continue;
1240  }
1241  for (x=0; x < (ssize_t) flip_image->columns; x++)
1242  {
1243  register ssize_t
1244  i;
1245 
1246  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1247  {
1248  PixelChannel channel = GetPixelChannelChannel(image,i);
1249  PixelTrait traits = GetPixelChannelTraits(image,channel);
1250  PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1251  if ((traits == UndefinedPixelTrait) ||
1252  (flip_traits == UndefinedPixelTrait))
1253  continue;
1254  SetPixelChannel(flip_image,channel,p[i],q);
1255  }
1256  p+=GetPixelChannels(image);
1257  q+=GetPixelChannels(flip_image);
1258  }
1259  if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1260  status=MagickFalse;
1261  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1262  {
1264  proceed;
1265 
1266 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1267  #pragma omp atomic
1268 #endif
1269  progress++;
1270  proceed=SetImageProgress(image,FlipImageTag,progress,image->rows);
1271  if (proceed == MagickFalse)
1272  status=MagickFalse;
1273  }
1274  }
1275  flip_view=DestroyCacheView(flip_view);
1276  image_view=DestroyCacheView(image_view);
1277  flip_image->type=image->type;
1278  if (page.height != 0)
1279  page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1280  flip_image->page=page;
1281  if (status == MagickFalse)
1282  flip_image=DestroyImage(flip_image);
1283  return(flip_image);
1284 }
1285 
1286 /*
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288 % %
1289 % %
1290 % %
1291 % F l o p I m a g e %
1292 % %
1293 % %
1294 % %
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296 %
1297 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1298 % around the central y-axis.
1299 %
1300 % The format of the FlopImage method is:
1301 %
1302 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1303 %
1304 % A description of each parameter follows:
1305 %
1306 % o image: the image.
1307 %
1308 % o exception: return any errors or warnings in this structure.
1309 %
1310 */
1312 {
1313 #define FlopImageTag "Flop/Image"
1314 
1315  CacheView
1316  *flop_view,
1317  *image_view;
1318 
1319  Image
1320  *flop_image;
1321 
1323  status;
1324 
1326  progress;
1327 
1329  page;
1330 
1331  ssize_t
1332  y;
1333 
1334  assert(image != (const Image *) NULL);
1335  assert(image->signature == MagickCoreSignature);
1336  if (image->debug != MagickFalse)
1337  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1338  assert(exception != (ExceptionInfo *) NULL);
1339  assert(exception->signature == MagickCoreSignature);
1340  flop_image=CloneImage(image,0,0,MagickTrue,exception);
1341  if (flop_image == (Image *) NULL)
1342  return((Image *) NULL);
1343  /*
1344  Flop each row.
1345  */
1346  status=MagickTrue;
1347  progress=0;
1348  page=image->page;
1349  image_view=AcquireVirtualCacheView(image,exception);
1350  flop_view=AcquireAuthenticCacheView(flop_image,exception);
1351 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1352  #pragma omp parallel for schedule(static) shared(status) \
1353  magick_number_threads(image,flop_image,flop_image->rows,1)
1354 #endif
1355  for (y=0; y < (ssize_t) flop_image->rows; y++)
1356  {
1357  register const Quantum
1358  *magick_restrict p;
1359 
1360  register ssize_t
1361  x;
1362 
1363  register Quantum
1364  *magick_restrict q;
1365 
1366  if (status == MagickFalse)
1367  continue;
1368  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1369  q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1370  exception);
1371  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1372  {
1373  status=MagickFalse;
1374  continue;
1375  }
1376  q+=GetPixelChannels(flop_image)*flop_image->columns;
1377  for (x=0; x < (ssize_t) flop_image->columns; x++)
1378  {
1379  register ssize_t
1380  i;
1381 
1382  q-=GetPixelChannels(flop_image);
1383  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1384  {
1385  PixelChannel channel = GetPixelChannelChannel(image,i);
1386  PixelTrait traits = GetPixelChannelTraits(image,channel);
1387  PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1388  if ((traits == UndefinedPixelTrait) ||
1389  (flop_traits == UndefinedPixelTrait))
1390  continue;
1391  SetPixelChannel(flop_image,channel,p[i],q);
1392  }
1393  p+=GetPixelChannels(image);
1394  }
1395  if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1396  status=MagickFalse;
1397  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1398  {
1400  proceed;
1401 
1402 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1403  #pragma omp atomic
1404 #endif
1405  progress++;
1406  proceed=SetImageProgress(image,FlopImageTag,progress,image->rows);
1407  if (proceed == MagickFalse)
1408  status=MagickFalse;
1409  }
1410  }
1411  flop_view=DestroyCacheView(flop_view);
1412  image_view=DestroyCacheView(image_view);
1413  flop_image->type=image->type;
1414  if (page.width != 0)
1415  page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1416  flop_image->page=page;
1417  if (status == MagickFalse)
1418  flop_image=DestroyImage(flop_image);
1419  return(flop_image);
1420 }
1421 
1422 /*
1423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424 % %
1425 % %
1426 % %
1427 % R o l l I m a g e %
1428 % %
1429 % %
1430 % %
1431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432 %
1433 % RollImage() offsets an image as defined by x_offset and y_offset.
1434 %
1435 % The format of the RollImage method is:
1436 %
1437 % Image *RollImage(const Image *image,const ssize_t x_offset,
1438 % const ssize_t y_offset,ExceptionInfo *exception)
1439 %
1440 % A description of each parameter follows:
1441 %
1442 % o image: the image.
1443 %
1444 % o x_offset: the number of columns to roll in the horizontal direction.
1445 %
1446 % o y_offset: the number of rows to roll in the vertical direction.
1447 %
1448 % o exception: return any errors or warnings in this structure.
1449 %
1450 */
1451 
1452 static MagickBooleanType CopyImageRegion(Image *destination,const Image *source, const size_t columns,const size_t rows,const ssize_t sx,const ssize_t sy,
1453  const ssize_t dx,const ssize_t dy,ExceptionInfo *exception)
1454 {
1455  CacheView
1456  *source_view,
1457  *destination_view;
1458 
1460  status;
1461 
1462  ssize_t
1463  y;
1464 
1465  if (columns == 0)
1466  return(MagickTrue);
1467  status=MagickTrue;
1468  source_view=AcquireVirtualCacheView(source,exception);
1469  destination_view=AcquireAuthenticCacheView(destination,exception);
1470 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1471  #pragma omp parallel for schedule(static) shared(status) \
1472  magick_number_threads(source,destination,rows,1)
1473 #endif
1474  for (y=0; y < (ssize_t) rows; y++)
1475  {
1477  sync;
1478 
1479  register const Quantum
1480  *magick_restrict p;
1481 
1482  register Quantum
1483  *magick_restrict q;
1484 
1485  register ssize_t
1486  x;
1487 
1488  /*
1489  Transfer scanline.
1490  */
1491  if (status == MagickFalse)
1492  continue;
1493  p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1494  q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1495  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1496  {
1497  status=MagickFalse;
1498  continue;
1499  }
1500  for (x=0; x < (ssize_t) columns; x++)
1501  {
1502  register ssize_t
1503  i;
1504 
1505  for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1506  {
1507  PixelChannel channel = GetPixelChannelChannel(source,i);
1508  PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1509  PixelTrait destination_traits=GetPixelChannelTraits(destination,
1510  channel);
1511  if ((source_traits == UndefinedPixelTrait) ||
1512  (destination_traits == UndefinedPixelTrait))
1513  continue;
1514  SetPixelChannel(destination,channel,p[i],q);
1515  }
1516  p+=GetPixelChannels(source);
1517  q+=GetPixelChannels(destination);
1518  }
1519  sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1520  if (sync == MagickFalse)
1521  status=MagickFalse;
1522  }
1523  destination_view=DestroyCacheView(destination_view);
1524  source_view=DestroyCacheView(source_view);
1525  return(status);
1526 }
1527 
1528 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1529  const ssize_t y_offset,ExceptionInfo *exception)
1530 {
1531 #define RollImageTag "Roll/Image"
1532 
1533  Image
1534  *roll_image;
1535 
1537  status;
1538 
1540  offset;
1541 
1542  /*
1543  Initialize roll image attributes.
1544  */
1545  assert(image != (const Image *) NULL);
1546  assert(image->signature == MagickCoreSignature);
1547  if (image->debug != MagickFalse)
1548  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1549  assert(exception != (ExceptionInfo *) NULL);
1550  assert(exception->signature == MagickCoreSignature);
1551  roll_image=CloneImage(image,0,0,MagickTrue,exception);
1552  if (roll_image == (Image *) NULL)
1553  return((Image *) NULL);
1554  offset.x=x_offset;
1555  offset.y=y_offset;
1556  while (offset.x < 0)
1557  offset.x+=(ssize_t) image->columns;
1558  while (offset.x >= (ssize_t) image->columns)
1559  offset.x-=(ssize_t) image->columns;
1560  while (offset.y < 0)
1561  offset.y+=(ssize_t) image->rows;
1562  while (offset.y >= (ssize_t) image->rows)
1563  offset.y-=(ssize_t) image->rows;
1564  /*
1565  Roll image.
1566  */
1567  status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1568  (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1569  offset.y,0,0,exception);
1570  (void) SetImageProgress(image,RollImageTag,0,3);
1571  status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1572  (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1573  exception);
1574  (void) SetImageProgress(image,RollImageTag,1,3);
1575  status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1576  offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1577  (void) SetImageProgress(image,RollImageTag,2,3);
1578  status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1579  offset.y,0,0,offset.x,offset.y,exception);
1580  (void) SetImageProgress(image,RollImageTag,3,3);
1581  roll_image->type=image->type;
1582  if (status == MagickFalse)
1583  roll_image=DestroyImage(roll_image);
1584  return(roll_image);
1585 }
1586 
1587 /*
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % %
1590 % %
1591 % %
1592 % S h a v e I m a g e %
1593 % %
1594 % %
1595 % %
1596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597 %
1598 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1599 % necessary for the new Image structure and returns a pointer to the new
1600 % image.
1601 %
1602 % The format of the ShaveImage method is:
1603 %
1604 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1605 % ExceptionInfo *exception)
1606 %
1607 % A description of each parameter follows:
1608 %
1609 % o shave_image: Method ShaveImage returns a pointer to the shaved
1610 % image. A null image is returned if there is a memory shortage or
1611 % if the image width or height is zero.
1612 %
1613 % o image: the image.
1614 %
1615 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1616 % region of the image to crop.
1617 %
1618 % o exception: return any errors or warnings in this structure.
1619 %
1620 */
1622  const RectangleInfo *shave_info,ExceptionInfo *exception)
1623 {
1624  Image
1625  *shave_image;
1626 
1628  geometry;
1629 
1630  assert(image != (const Image *) NULL);
1631  assert(image->signature == MagickCoreSignature);
1632  if (image->debug != MagickFalse)
1633  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1634  if (((2*shave_info->width) >= image->columns) ||
1635  ((2*shave_info->height) >= image->rows))
1636  ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1637  SetGeometry(image,&geometry);
1638  geometry.width-=2*shave_info->width;
1639  geometry.height-=2*shave_info->height;
1640  geometry.x=(ssize_t) shave_info->width+image->page.x;
1641  geometry.y=(ssize_t) shave_info->height+image->page.y;
1642  shave_image=CropImage(image,&geometry,exception);
1643  if (shave_image == (Image *) NULL)
1644  return((Image *) NULL);
1645  shave_image->page.width-=2*shave_info->width;
1646  shave_image->page.height-=2*shave_info->height;
1647  shave_image->page.x-=(ssize_t) shave_info->width;
1648  shave_image->page.y-=(ssize_t) shave_info->height;
1649  return(shave_image);
1650 }
1651 
1652 /*
1653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1654 % %
1655 % %
1656 % %
1657 % S p l i c e I m a g e %
1658 % %
1659 % %
1660 % %
1661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662 %
1663 % SpliceImage() splices a solid color into the image as defined by the
1664 % geometry.
1665 %
1666 % The format of the SpliceImage method is:
1667 %
1668 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1669 % ExceptionInfo *exception)
1670 %
1671 % A description of each parameter follows:
1672 %
1673 % o image: the image.
1674 %
1675 % o geometry: Define the region of the image to splice with members
1676 % x, y, width, and height.
1677 %
1678 % o exception: return any errors or warnings in this structure.
1679 %
1680 */
1682  const RectangleInfo *geometry,ExceptionInfo *exception)
1683 {
1684 #define SpliceImageTag "Splice/Image"
1685 
1686  CacheView
1687  *image_view,
1688  *splice_view;
1689 
1690  Image
1691  *splice_image;
1692 
1694  status;
1695 
1697  progress;
1698 
1700  splice_geometry;
1701 
1702  ssize_t
1703  columns,
1704  y;
1705 
1706  /*
1707  Allocate splice image.
1708  */
1709  assert(image != (const Image *) NULL);
1710  assert(image->signature == MagickCoreSignature);
1711  if (image->debug != MagickFalse)
1712  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1713  assert(geometry != (const RectangleInfo *) NULL);
1714  assert(exception != (ExceptionInfo *) NULL);
1715  assert(exception->signature == MagickCoreSignature);
1716  splice_geometry=(*geometry);
1717  splice_image=CloneImage(image,image->columns+splice_geometry.width,
1718  image->rows+splice_geometry.height,MagickTrue,exception);
1719  if (splice_image == (Image *) NULL)
1720  return((Image *) NULL);
1721  if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1722  {
1723  splice_image=DestroyImage(splice_image);
1724  return((Image *) NULL);
1725  }
1726  if ((IsPixelInfoGray(&splice_image->background_color) == MagickFalse) &&
1727  (IsGrayColorspace(splice_image->colorspace) != MagickFalse))
1728  (void) SetImageColorspace(splice_image,sRGBColorspace,exception);
1729  if ((splice_image->background_color.alpha_trait != UndefinedPixelTrait) &&
1730  (splice_image->alpha_trait == UndefinedPixelTrait))
1731  (void) SetImageAlpha(splice_image,OpaqueAlpha,exception);
1732  (void) SetImageBackgroundColor(splice_image,exception);
1733  /*
1734  Respect image geometry.
1735  */
1736  switch (image->gravity)
1737  {
1738  default:
1739  case UndefinedGravity:
1740  case NorthWestGravity:
1741  break;
1742  case NorthGravity:
1743  {
1744  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1745  break;
1746  }
1747  case NorthEastGravity:
1748  {
1749  splice_geometry.x+=(ssize_t) splice_geometry.width;
1750  break;
1751  }
1752  case WestGravity:
1753  {
1754  splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1755  break;
1756  }
1757  case CenterGravity:
1758  {
1759  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1760  splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1761  break;
1762  }
1763  case EastGravity:
1764  {
1765  splice_geometry.x+=(ssize_t) splice_geometry.width;
1766  splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1767  break;
1768  }
1769  case SouthWestGravity:
1770  {
1771  splice_geometry.y+=(ssize_t) splice_geometry.height;
1772  break;
1773  }
1774  case SouthGravity:
1775  {
1776  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1777  splice_geometry.y+=(ssize_t) splice_geometry.height;
1778  break;
1779  }
1780  case SouthEastGravity:
1781  {
1782  splice_geometry.x+=(ssize_t) splice_geometry.width;
1783  splice_geometry.y+=(ssize_t) splice_geometry.height;
1784  break;
1785  }
1786  }
1787  /*
1788  Splice image.
1789  */
1790  status=MagickTrue;
1791  progress=0;
1792  columns=MagickMin(splice_geometry.x,(ssize_t) splice_image->columns);
1793  image_view=AcquireVirtualCacheView(image,exception);
1794  splice_view=AcquireAuthenticCacheView(splice_image,exception);
1795 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1796  #pragma omp parallel for schedule(static) shared(progress,status) \
1797  magick_number_threads(image,splice_image,splice_geometry.y,1)
1798 #endif
1799  for (y=0; y < (ssize_t) splice_geometry.y; y++)
1800  {
1801  register const Quantum
1802  *magick_restrict p;
1803 
1804  register ssize_t
1805  x;
1806 
1807  register Quantum
1808  *magick_restrict q;
1809 
1810  if (status == MagickFalse)
1811  continue;
1812  p=GetCacheViewVirtualPixels(image_view,0,y,splice_image->columns,1,
1813  exception);
1814  q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1815  exception);
1816  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1817  {
1818  status=MagickFalse;
1819  continue;
1820  }
1821  for (x=0; x < columns; x++)
1822  {
1823  register ssize_t
1824  i;
1825 
1826  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1827  {
1828  PixelChannel channel = GetPixelChannelChannel(image,i);
1829  PixelTrait traits = GetPixelChannelTraits(image,channel);
1830  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1831  if ((traits == UndefinedPixelTrait) ||
1832  (splice_traits == UndefinedPixelTrait))
1833  continue;
1834  SetPixelChannel(splice_image,channel,p[i],q);
1835  }
1836  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1837  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1838  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1839  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1840  p+=GetPixelChannels(image);
1841  q+=GetPixelChannels(splice_image);
1842  }
1843  for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1844  q+=GetPixelChannels(splice_image);
1845  for ( ; x < (ssize_t) splice_image->columns; x++)
1846  {
1847  register ssize_t
1848  i;
1849 
1850  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1851  {
1852  PixelChannel channel = GetPixelChannelChannel(image,i);
1853  PixelTrait traits = GetPixelChannelTraits(image,channel);
1854  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1855  if ((traits == UndefinedPixelTrait) ||
1856  (splice_traits == UndefinedPixelTrait))
1857  continue;
1858  SetPixelChannel(splice_image,channel,p[i],q);
1859  }
1860  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1861  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1862  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1863  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1864  p+=GetPixelChannels(image);
1865  q+=GetPixelChannels(splice_image);
1866  }
1867  if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1868  status=MagickFalse;
1869  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1870  {
1872  proceed;
1873 
1874 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1875  #pragma omp atomic
1876 #endif
1877  progress++;
1878  proceed=SetImageProgress(image,SpliceImageTag,progress,
1879  splice_image->rows);
1880  if (proceed == MagickFalse)
1881  status=MagickFalse;
1882  }
1883  }
1884 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1885  #pragma omp parallel for schedule(static) shared(progress,status) \
1886  magick_number_threads(image,splice_image,splice_image->rows,2)
1887 #endif
1888  for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1889  y < (ssize_t) splice_image->rows; y++)
1890  {
1891  register const Quantum
1892  *magick_restrict p;
1893 
1894  register ssize_t
1895  x;
1896 
1897  register Quantum
1898  *magick_restrict q;
1899 
1900  if (status == MagickFalse)
1901  continue;
1902  if ((y < 0) || (y >= (ssize_t)splice_image->rows))
1903  continue;
1904  p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1905  splice_image->columns,1,exception);
1906  q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1907  exception);
1908  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1909  {
1910  status=MagickFalse;
1911  continue;
1912  }
1913  for (x=0; x < columns; x++)
1914  {
1915  register ssize_t
1916  i;
1917 
1918  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1919  {
1920  PixelChannel channel = GetPixelChannelChannel(image,i);
1921  PixelTrait traits = GetPixelChannelTraits(image,channel);
1922  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1923  if ((traits == UndefinedPixelTrait) ||
1924  (splice_traits == UndefinedPixelTrait))
1925  continue;
1926  SetPixelChannel(splice_image,channel,p[i],q);
1927  }
1928  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1929  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1930  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1931  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1932  p+=GetPixelChannels(image);
1933  q+=GetPixelChannels(splice_image);
1934  }
1935  for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1936  q+=GetPixelChannels(splice_image);
1937  for ( ; x < (ssize_t) splice_image->columns; x++)
1938  {
1939  register ssize_t
1940  i;
1941 
1942  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1943  {
1944  PixelChannel channel = GetPixelChannelChannel(image,i);
1945  PixelTrait traits = GetPixelChannelTraits(image,channel);
1946  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1947  if ((traits == UndefinedPixelTrait) ||
1948  (splice_traits == UndefinedPixelTrait))
1949  continue;
1950  SetPixelChannel(splice_image,channel,p[i],q);
1951  }
1952  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1953  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1954  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1955  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1956  p+=GetPixelChannels(image);
1957  q+=GetPixelChannels(splice_image);
1958  }
1959  if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1960  status=MagickFalse;
1961  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1962  {
1964  proceed;
1965 
1966 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1967  #pragma omp atomic
1968 #endif
1969  progress++;
1970  proceed=SetImageProgress(image,SpliceImageTag,progress,
1971  splice_image->rows);
1972  if (proceed == MagickFalse)
1973  status=MagickFalse;
1974  }
1975  }
1976  splice_view=DestroyCacheView(splice_view);
1977  image_view=DestroyCacheView(image_view);
1978  if (status == MagickFalse)
1979  splice_image=DestroyImage(splice_image);
1980  return(splice_image);
1981 }
1982 
1983 /*
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985 % %
1986 % %
1987 % %
1988 % T r a n s f o r m I m a g e %
1989 % %
1990 % %
1991 % %
1992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 %
1994 % TransformImage() is a convenience method that behaves like ResizeImage() or
1995 % CropImage() but accepts scaling and/or cropping information as a region
1996 % geometry specification. If the operation fails, the original image handle
1997 % is left as is.
1998 %
1999 % This should only be used for single images.
2000 %
2001 % This function destroys what it assumes to be a single image list.
2002 % If the input image is part of a larger list, all other images in that list
2003 % will be simply 'lost', not destroyed.
2004 %
2005 % Also if the crop generates a list of images only the first image is resized.
2006 % And finally if the crop succeeds and the resize failed, you will get a
2007 % cropped image, as well as a 'false' or 'failed' report.
2008 %
2009 % This function and should probably be deprecated in favor of direct calls
2010 % to CropImageToTiles() or ResizeImage(), as appropriate.
2011 %
2012 % The format of the TransformImage method is:
2013 %
2014 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2015 % const char *image_geometry,ExceptionInfo *exception)
2016 %
2017 % A description of each parameter follows:
2018 %
2019 % o image: the image The transformed image is returned as this parameter.
2020 %
2021 % o crop_geometry: A crop geometry string. This geometry defines a
2022 % subregion of the image to crop.
2023 %
2024 % o image_geometry: An image geometry string. This geometry defines the
2025 % final size of the image.
2026 %
2027 % o exception: return any errors or warnings in this structure.
2028 %
2029 */
2031  const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2032 {
2033  Image
2034  *resize_image,
2035  *transform_image;
2036 
2038  geometry;
2039 
2040  assert(image != (Image **) NULL);
2041  assert((*image)->signature == MagickCoreSignature);
2042  if ((*image)->debug != MagickFalse)
2043  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2044  transform_image=(*image);
2045  if (crop_geometry != (const char *) NULL)
2046  {
2047  Image
2048  *crop_image;
2049 
2050  /*
2051  Crop image to a user specified size.
2052  */
2053  crop_image=CropImageToTiles(*image,crop_geometry,exception);
2054  if (crop_image == (Image *) NULL)
2055  transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2056  else
2057  {
2058  transform_image=DestroyImage(transform_image);
2059  transform_image=GetFirstImageInList(crop_image);
2060  }
2061  *image=transform_image;
2062  }
2063  if (image_geometry == (const char *) NULL)
2064  return(MagickTrue);
2065  /*
2066  Scale image to a user specified size.
2067  */
2068  (void) ParseRegionGeometry(transform_image,image_geometry,&geometry,
2069  exception);
2070  if ((transform_image->columns == geometry.width) &&
2071  (transform_image->rows == geometry.height))
2072  return(MagickTrue);
2073  resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2074  transform_image->filter,exception);
2075  if (resize_image == (Image *) NULL)
2076  return(MagickFalse);
2077  transform_image=DestroyImage(transform_image);
2078  transform_image=resize_image;
2079  *image=transform_image;
2080  return(MagickTrue);
2081 }
2082 
2083 /*
2084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085 % %
2086 % %
2087 % %
2088 % T r a n s p o s e I m a g e %
2089 % %
2090 % %
2091 % %
2092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093 %
2094 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2095 % around the central y-axis while rotating them by 90 degrees.
2096 %
2097 % The format of the TransposeImage method is:
2098 %
2099 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2100 %
2101 % A description of each parameter follows:
2102 %
2103 % o image: the image.
2104 %
2105 % o exception: return any errors or warnings in this structure.
2106 %
2107 */
2109 {
2110 #define TransposeImageTag "Transpose/Image"
2111 
2112  CacheView
2113  *image_view,
2114  *transpose_view;
2115 
2116  Image
2117  *transpose_image;
2118 
2120  status;
2121 
2123  progress;
2124 
2126  page;
2127 
2128  ssize_t
2129  y;
2130 
2131  assert(image != (const Image *) NULL);
2132  assert(image->signature == MagickCoreSignature);
2133  if (image->debug != MagickFalse)
2134  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2135  assert(exception != (ExceptionInfo *) NULL);
2136  assert(exception->signature == MagickCoreSignature);
2137  transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2138  exception);
2139  if (transpose_image == (Image *) NULL)
2140  return((Image *) NULL);
2141  /*
2142  Transpose image.
2143  */
2144  status=MagickTrue;
2145  progress=0;
2146  image_view=AcquireVirtualCacheView(image,exception);
2147  transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2148 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2149  #pragma omp parallel for schedule(static) shared(progress,status) \
2150  magick_number_threads(image,transpose_image,image->rows,1)
2151 #endif
2152  for (y=0; y < (ssize_t) image->rows; y++)
2153  {
2154  register const Quantum
2155  *magick_restrict p;
2156 
2157  register Quantum
2158  *magick_restrict q;
2159 
2160  register ssize_t
2161  x;
2162 
2163  if (status == MagickFalse)
2164  continue;
2165  p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2166  image->columns,1,exception);
2167  q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2168  0,1,transpose_image->rows,exception);
2169  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2170  {
2171  status=MagickFalse;
2172  continue;
2173  }
2174  for (x=0; x < (ssize_t) image->columns; x++)
2175  {
2176  register ssize_t
2177  i;
2178 
2179  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2180  {
2181  PixelChannel channel = GetPixelChannelChannel(image,i);
2182  PixelTrait traits = GetPixelChannelTraits(image,channel);
2183  PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2184  channel);
2185  if ((traits == UndefinedPixelTrait) ||
2186  (transpose_traits == UndefinedPixelTrait))
2187  continue;
2188  SetPixelChannel(transpose_image,channel,p[i],q);
2189  }
2190  p+=GetPixelChannels(image);
2191  q+=GetPixelChannels(transpose_image);
2192  }
2193  if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2194  status=MagickFalse;
2195  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2196  {
2198  proceed;
2199 
2200 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2201  #pragma omp atomic
2202 #endif
2203  progress++;
2204  proceed=SetImageProgress(image,TransposeImageTag,progress,image->rows);
2205  if (proceed == MagickFalse)
2206  status=MagickFalse;
2207  }
2208  }
2209  transpose_view=DestroyCacheView(transpose_view);
2210  image_view=DestroyCacheView(image_view);
2211  transpose_image->type=image->type;
2212  page=transpose_image->page;
2213  Swap(page.width,page.height);
2214  Swap(page.x,page.y);
2215  transpose_image->page=page;
2216  if (status == MagickFalse)
2217  transpose_image=DestroyImage(transpose_image);
2218  return(transpose_image);
2219 }
2220 
2221 /*
2222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223 % %
2224 % %
2225 % %
2226 % T r a n s v e r s e I m a g e %
2227 % %
2228 % %
2229 % %
2230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2231 %
2232 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2233 % around the central x-axis while rotating them by 270 degrees.
2234 %
2235 % The format of the TransverseImage method is:
2236 %
2237 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2238 %
2239 % A description of each parameter follows:
2240 %
2241 % o image: the image.
2242 %
2243 % o exception: return any errors or warnings in this structure.
2244 %
2245 */
2247 {
2248 #define TransverseImageTag "Transverse/Image"
2249 
2250  CacheView
2251  *image_view,
2252  *transverse_view;
2253 
2254  Image
2255  *transverse_image;
2256 
2258  status;
2259 
2261  progress;
2262 
2264  page;
2265 
2266  ssize_t
2267  y;
2268 
2269  assert(image != (const Image *) NULL);
2270  assert(image->signature == MagickCoreSignature);
2271  if (image->debug != MagickFalse)
2272  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2273  assert(exception != (ExceptionInfo *) NULL);
2274  assert(exception->signature == MagickCoreSignature);
2275  transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2276  exception);
2277  if (transverse_image == (Image *) NULL)
2278  return((Image *) NULL);
2279  /*
2280  Transverse image.
2281  */
2282  status=MagickTrue;
2283  progress=0;
2284  image_view=AcquireVirtualCacheView(image,exception);
2285  transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2287  #pragma omp parallel for schedule(static) shared(progress,status) \
2288  magick_number_threads(image,transverse_image,image->rows,1)
2289 #endif
2290  for (y=0; y < (ssize_t) image->rows; y++)
2291  {
2293  sync;
2294 
2295  register const Quantum
2296  *magick_restrict p;
2297 
2298  register Quantum
2299  *magick_restrict q;
2300 
2301  register ssize_t
2302  x;
2303 
2304  if (status == MagickFalse)
2305  continue;
2306  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2307  q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2308  0,1,transverse_image->rows,exception);
2309  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2310  {
2311  status=MagickFalse;
2312  continue;
2313  }
2314  q+=GetPixelChannels(transverse_image)*image->columns;
2315  for (x=0; x < (ssize_t) image->columns; x++)
2316  {
2317  register ssize_t
2318  i;
2319 
2320  q-=GetPixelChannels(transverse_image);
2321  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2322  {
2323  PixelChannel channel = GetPixelChannelChannel(image,i);
2324  PixelTrait traits = GetPixelChannelTraits(image,channel);
2325  PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2326  channel);
2327  if ((traits == UndefinedPixelTrait) ||
2328  (transverse_traits == UndefinedPixelTrait))
2329  continue;
2330  SetPixelChannel(transverse_image,channel,p[i],q);
2331  }
2332  p+=GetPixelChannels(image);
2333  }
2334  sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2335  if (sync == MagickFalse)
2336  status=MagickFalse;
2337  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2338  {
2340  proceed;
2341 
2342 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2343  #pragma omp atomic
2344 #endif
2345  progress++;
2346  proceed=SetImageProgress(image,TransverseImageTag,progress,image->rows);
2347  if (proceed == MagickFalse)
2348  status=MagickFalse;
2349  }
2350  }
2351  transverse_view=DestroyCacheView(transverse_view);
2352  image_view=DestroyCacheView(image_view);
2353  transverse_image->type=image->type;
2354  page=transverse_image->page;
2355  Swap(page.width,page.height);
2356  Swap(page.x,page.y);
2357  if (page.width != 0)
2358  page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2359  if (page.height != 0)
2360  page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2361  transverse_image->page=page;
2362  if (status == MagickFalse)
2363  transverse_image=DestroyImage(transverse_image);
2364  return(transverse_image);
2365 }
2366 
2367 /*
2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2369 % %
2370 % %
2371 % %
2372 % T r i m I m a g e %
2373 % %
2374 % %
2375 % %
2376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2377 %
2378 % TrimImage() trims pixels from the image edges. It allocates the memory
2379 % necessary for the new Image structure and returns a pointer to the new
2380 % image.
2381 %
2382 % The format of the TrimImage method is:
2383 %
2384 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2385 %
2386 % A description of each parameter follows:
2387 %
2388 % o image: the image.
2389 %
2390 % o exception: return any errors or warnings in this structure.
2391 %
2392 */
2394 {
2396  geometry;
2397 
2398  assert(image != (const Image *) NULL);
2399  assert(image->signature == MagickCoreSignature);
2400  if (image->debug != MagickFalse)
2401  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2402  geometry=GetImageBoundingBox(image,exception);
2403  if ((geometry.width == 0) || (geometry.height == 0))
2404  {
2405  Image
2406  *crop_image;
2407 
2408  crop_image=CloneImage(image,1,1,MagickTrue,exception);
2409  if (crop_image == (Image *) NULL)
2410  return((Image *) NULL);
2412  crop_image->alpha_trait=BlendPixelTrait;
2413  (void) SetImageBackgroundColor(crop_image,exception);
2414  crop_image->page=image->page;
2415  crop_image->page.x=(-1);
2416  crop_image->page.y=(-1);
2417  return(crop_image);
2418  }
2419  geometry.x+=image->page.x;
2420  geometry.y+=image->page.y;
2421  return(CropImage(image,&geometry,exception));
2422 }
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport Image * ResizeImage(const Image *image, const size_t columns, const size_t rows, const FilterType filter, ExceptionInfo *exception)
Definition: resize.c:3700
MagickDoubleType MagickRealType
Definition: magick-type.h:120
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
MagickExport Image * FlipImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:1176
#define TransparentAlpha
Definition: image.h:26
DisposeType dispose
Definition: image.h:237
#define RollImageTag
MagickProgressMonitor progress_monitor
Definition: image.h:303
ImageType type
Definition: image.h:264
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
FilterType filter
Definition: image.h:219
PixelTrait alpha_trait
Definition: pixel.h:178
ssize_t y
Definition: geometry.h:116
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport Image * ConsolidateCMYKImages(const Image *images, ExceptionInfo *exception)
Definition: transform.c:414
OrientationType
Definition: image.h:76
MagickExport Image * FlopImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:1311
MagickExport Image * TransposeImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:2108
size_t signature
Definition: exception.h:123
#define OpaqueAlpha
Definition: image.h:25
MagickExport MagickBooleanType SetImageAlpha(Image *image, const Quantum alpha, ExceptionInfo *exception)
Definition: image.c:2337
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
static MagickBooleanType IsGrayColorspace(const ColorspaceType colorspace)
MagickExport Image * TransverseImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:2246
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
ssize_t offset
Definition: token.c:69
MagickRealType alpha
Definition: pixel.h:190
#define TransposeImageTag
MagickExport MagickBooleanType CompositeImage(Image *image, const Image *composite, const CompositeOperator compose, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:528
size_t width
Definition: geometry.h:130
#define ChopImageTag
MagickExport Image * CropImageToTiles(const Image *image, const char *crop_geometry, ExceptionInfo *exception)
Definition: transform.c:778
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:129
Definition: image.h:151
MagickExport Image * CropImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:535
double x
Definition: geometry.h:123
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
MagickExport Image * GetFirstImageInList(const Image *images)
Definition: list.c:561
MagickBooleanType
Definition: magick-type.h:158
MagickExport Image * NewImageList(void)
Definition: list.c:938
unsigned int MagickStatusType
Definition: magick-type.h:121
double y
Definition: geometry.h:123
MagickExport Image * SpliceImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:1681
GravityType gravity
Definition: image.h:231
RectangleInfo page
Definition: image.h:212
MagickExport Image * RollImage(const Image *image, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: transform.c:1528
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait alpha_trait
Definition: image.h:280
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1413
MagickExport Image * RotateImage(const Image *image, const double degrees, ExceptionInfo *exception)
Definition: distort.c:2853
MagickExport MagickBooleanType SetImageBackgroundColor(Image *image, ExceptionInfo *exception)
Definition: image.c:2415
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
MagickExport Image * ExcerptImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:977
ssize_t x
Definition: geometry.h:134
size_t height
Definition: geometry.h:130
static void SetPixelMagenta(const Image *magick_restrict image, const Quantum magenta, Quantum *magick_restrict pixel)
#define FlipImageTag
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2615
PixelChannel
Definition: pixel.h:67
#define SpliceImageTag
static size_t GetPixelChannels(const Image *magick_restrict image)
MagickExport Image * ChopImage(const Image *image, const RectangleInfo *chop_info, ExceptionInfo *exception)
Definition: transform.c:188
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
static void SetPixelCyan(const Image *magick_restrict image, const Quantum cyan, Quantum *magick_restrict pixel)
#define ThrowImageException(severity, tag)
static Quantum ClampToQuantum(const MagickRealType value)
Definition: quantum.h:84
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
MagickExport void ClearMagickException(ExceptionInfo *exception)
Definition: exception.c:164
#define TransverseImageTag
unsigned short Quantum
Definition: magick-type.h:82
static MagickBooleanType IsPixelInfoGray(const PixelInfo *magick_restrict pixel)
#define FlopImageTag
MagickExport RectangleInfo GetImageBoundingBox(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:380
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1196
MagickExport Image * ExtentImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:1117
MagickExport MagickStatusType ParseGravityGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1232
MagickExport Image * GetNextImageInList(const Image *images)
Definition: list.c:771
MagickExport Image * ShaveImage(const Image *image, const RectangleInfo *shave_info, ExceptionInfo *exception)
Definition: transform.c:1621
#define CropImageTag
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
MagickExport void AppendImageToList(Image **images, const Image *append)
Definition: list.c:78
static void SetPixelYellow(const Image *magick_restrict image, const Quantum yellow, Quantum *magick_restrict pixel)
#define MagickMin(x, y)
Definition: image-private.h:27
static void SetPixelAlpha(const Image *magick_restrict image, const Quantum alpha, Quantum *magick_restrict pixel)
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1683
ssize_t x
Definition: geometry.h:116
static double MagickRound(double x)
Definition: transform.c:768
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
#define Swap(x, y)
Definition: studio.h:345
CompositeOperator compose
Definition: image.h:234
MagickExport Image * AutoOrientImage(const Image *image, const OrientationType orientation, ExceptionInfo *exception)
Definition: transform.c:99
static void SetPixelRed(const Image *magick_restrict image, const Quantum red, Quantum *magick_restrict pixel)
#define MagickPrivate
MagickExport Image * TrimImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:2393
static MagickBooleanType CopyImageRegion(Image *destination, const Image *source, const size_t columns, const size_t rows, const ssize_t sx, const ssize_t sy, const ssize_t dx, const ssize_t dy, ExceptionInfo *exception)
Definition: transform.c:1452
#define MagickExport
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
OrientationType orientation
Definition: image.h:166
ssize_t y
Definition: geometry.h:134
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
static void SetPixelBlack(const Image *magick_restrict image, const Quantum black, Quantum *magick_restrict pixel)
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:134
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
PixelInfo background_color
Definition: image.h:179
MagickExport size_t GetImageListLength(const Image *images)
Definition: list.c:696
#define ExcerptImageTag
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1181
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:796
ColorspaceType colorspace
Definition: image.h:157
MagickExport MagickStatusType ParseRegionGeometry(const Image *image, const char *geometry, RectangleInfo *region_info, ExceptionInfo *exception)
Definition: geometry.c:1644
#define QuantumRange
Definition: magick-type.h:83
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickBooleanType debug
Definition: image.h:334
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)
MagickPrivate MagickBooleanType TransformImage(Image **, const char *, const char *, ExceptionInfo *)
Definition: transform.c:2030