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