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