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