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"
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  register const Quantum
262  *magick_restrict p;
263 
264  register ssize_t
265  x;
266 
267  register 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  register 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  register const Quantum
327  *magick_restrict p;
328 
329  register ssize_t
330  x;
331 
332  register 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  register 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  register 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  register 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  register const Quantum
463  *magick_restrict p;
464 
465  register ssize_t
466  x;
467 
468  register 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  register const Quantum
681  *magick_restrict p;
682 
683  register Quantum
684  *magick_restrict q;
685 
686  register 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  register 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 double ConstrainPixelOffset(double x)
771 {
772  if (x < (double) -(SSIZE_MAX-512))
773  return((double) -(SSIZE_MAX-512));
774  if (x > (double) (SSIZE_MAX-512))
775  return((double) (SSIZE_MAX-512));
776  return(x);
777 }
778 
779 static inline ssize_t PixelRoundOffset(double x)
780 {
781  /*
782  Round the fraction to nearest integer.
783  */
784  if ((x-floor(x)) < (ceil(x)-x))
785  return((ssize_t) floor(ConstrainPixelOffset(x)));
786  return((ssize_t) ceil(ConstrainPixelOffset(x)));
787 }
788 
790  const char *crop_geometry,ExceptionInfo *exception)
791 {
792  Image
793  *next,
794  *crop_image;
795 
797  flags;
798 
800  geometry;
801 
802  assert(image != (Image *) NULL);
803  assert(image->signature == MagickCoreSignature);
804  if (image->debug != MagickFalse)
805  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
806  crop_image=NewImageList();
807  next=NewImageList();
808  flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
809  if ((flags & AreaValue) != 0)
810  {
811  PointInfo
812  delta,
813  offset;
814 
816  crop;
817 
818  size_t
819  height,
820  width;
821 
822  /*
823  Crop into NxM tiles (@ flag).
824  */
825  width=image->columns;
826  height=image->rows;
827  if (geometry.width == 0)
828  geometry.width=1;
829  if (geometry.height == 0)
830  geometry.height=1;
831  if ((flags & AspectValue) == 0)
832  {
833  width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
834  height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
835  }
836  else
837  {
838  width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
839  height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
840  }
841  delta.x=(double) width/geometry.width;
842  delta.y=(double) height/geometry.height;
843  if (delta.x < 1.0)
844  delta.x=1.0;
845  if (delta.y < 1.0)
846  delta.y=1.0;
847  for (offset.y=0; offset.y < (double) height; )
848  {
849  if ((flags & AspectValue) == 0)
850  {
851  crop.y=PixelRoundOffset((double) (offset.y-
852  (geometry.y > 0 ? 0 : geometry.y)));
853  offset.y+=delta.y; /* increment now to find width */
854  crop.height=(size_t) PixelRoundOffset((double) (offset.y+
855  (geometry.y < 0 ? 0 : geometry.y)));
856  }
857  else
858  {
859  crop.y=PixelRoundOffset((double) (offset.y-
860  (geometry.y > 0 ? geometry.y : 0)));
861  offset.y+=delta.y; /* increment now to find width */
862  crop.height=(size_t) PixelRoundOffset((double)
863  (offset.y+(geometry.y < -1 ? geometry.y : 0)));
864  }
865  crop.height-=crop.y;
866  crop.y+=image->page.y;
867  for (offset.x=0; offset.x < (double) width; )
868  {
869  if ((flags & AspectValue) == 0)
870  {
871  crop.x=PixelRoundOffset((double) (offset.x-
872  (geometry.x > 0 ? 0 : geometry.x)));
873  offset.x+=delta.x; /* increment now to find height */
874  crop.width=(size_t) PixelRoundOffset((double) (offset.x+
875  (geometry.x < 0 ? 0 : geometry.x)));
876  }
877  else
878  {
879  crop.x=PixelRoundOffset((double) (offset.x-
880  (geometry.x > 0 ? geometry.x : 0)));
881  offset.x+=delta.x; /* increment now to find height */
882  crop.width=(size_t) PixelRoundOffset((double) (offset.x+
883  (geometry.x < 0 ? geometry.x : 0)));
884  }
885  crop.width-=crop.x;
886  crop.x+=image->page.x;
887  next=CropImage(image,&crop,exception);
888  if (next != (Image *) NULL)
889  AppendImageToList(&crop_image,next);
890  }
891  }
892  ClearMagickException(exception);
893  return(crop_image);
894  }
895  if (((geometry.width == 0) && (geometry.height == 0)) ||
896  ((flags & XValue) != 0) || ((flags & YValue) != 0))
897  {
898  /*
899  Crop a single region at +X+Y.
900  */
901  crop_image=CropImage(image,&geometry,exception);
902  if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
903  {
904  crop_image->page.width=geometry.width;
905  crop_image->page.height=geometry.height;
906  crop_image->page.x-=geometry.x;
907  crop_image->page.y-=geometry.y;
908  }
909  return(crop_image);
910  }
911  if ((image->columns > geometry.width) || (image->rows > geometry.height))
912  {
914  page;
915 
916  size_t
917  height,
918  width;
919 
920  ssize_t
921  x,
922  y;
923 
924  /*
925  Crop into tiles of fixed size WxH.
926  */
927  page=image->page;
928  if (page.width == 0)
929  page.width=image->columns;
930  if (page.height == 0)
931  page.height=image->rows;
932  width=geometry.width;
933  if (width == 0)
934  width=page.width;
935  height=geometry.height;
936  if (height == 0)
937  height=page.height;
938  next=NewImageList();
939  for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
940  {
941  for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
942  {
943  geometry.width=width;
944  geometry.height=height;
945  geometry.x=x;
946  geometry.y=y;
947  next=CropImage(image,&geometry,exception);
948  if (next == (Image *) NULL)
949  break;
950  AppendImageToList(&crop_image,next);
951  }
952  if (next == (Image *) NULL)
953  break;
954  }
955  return(crop_image);
956  }
957  return(CloneImage(image,0,0,MagickTrue,exception));
958 }
959 
960 /*
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 % %
963 % %
964 % %
965 % E x c e r p t I m a g e %
966 % %
967 % %
968 % %
969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970 %
971 % ExcerptImage() returns a excerpt of the image as defined by the geometry.
972 %
973 % The format of the ExcerptImage method is:
974 %
975 % Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
976 % ExceptionInfo *exception)
977 %
978 % A description of each parameter follows:
979 %
980 % o image: the image.
981 %
982 % o geometry: Define the region of the image to extend with members
983 % x, y, width, and height.
984 %
985 % o exception: return any errors or warnings in this structure.
986 %
987 */
989  const RectangleInfo *geometry,ExceptionInfo *exception)
990 {
991 #define ExcerptImageTag "Excerpt/Image"
992 
993  CacheView
994  *excerpt_view,
995  *image_view;
996 
997  Image
998  *excerpt_image;
999 
1001  status;
1002 
1004  progress;
1005 
1006  ssize_t
1007  y;
1008 
1009  /*
1010  Allocate excerpt image.
1011  */
1012  assert(image != (const Image *) NULL);
1013  assert(image->signature == MagickCoreSignature);
1014  if (image->debug != MagickFalse)
1015  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1016  assert(geometry != (const RectangleInfo *) NULL);
1017  assert(exception != (ExceptionInfo *) NULL);
1018  assert(exception->signature == MagickCoreSignature);
1019  excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1020  exception);
1021  if (excerpt_image == (Image *) NULL)
1022  return((Image *) NULL);
1023  /*
1024  Excerpt each row.
1025  */
1026  status=MagickTrue;
1027  progress=0;
1028  image_view=AcquireVirtualCacheView(image,exception);
1029  excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
1030 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1031  #pragma omp parallel for schedule(static) shared(progress,status) \
1032  magick_number_threads(image,excerpt_image,excerpt_image->rows,1)
1033 #endif
1034  for (y=0; y < (ssize_t) excerpt_image->rows; y++)
1035  {
1036  register const Quantum
1037  *magick_restrict p;
1038 
1039  register Quantum
1040  *magick_restrict q;
1041 
1042  register ssize_t
1043  x;
1044 
1045  if (status == MagickFalse)
1046  continue;
1047  p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
1048  geometry->width,1,exception);
1049  q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
1050  exception);
1051  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1052  {
1053  status=MagickFalse;
1054  continue;
1055  }
1056  for (x=0; x < (ssize_t) excerpt_image->columns; x++)
1057  {
1058  register ssize_t
1059  i;
1060 
1061  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1062  {
1063  PixelChannel channel = GetPixelChannelChannel(image,i);
1064  PixelTrait traits = GetPixelChannelTraits(image,channel);
1065  PixelTrait excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
1066  if ((traits == UndefinedPixelTrait) ||
1067  (excerpt_traits == UndefinedPixelTrait))
1068  continue;
1069  SetPixelChannel(excerpt_image,channel,p[i],q);
1070  }
1071  p+=GetPixelChannels(image);
1072  q+=GetPixelChannels(excerpt_image);
1073  }
1074  if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1075  status=MagickFalse;
1076  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1077  {
1079  proceed;
1080 
1081 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1082  #pragma omp atomic
1083 #endif
1084  progress++;
1085  proceed=SetImageProgress(image,ExcerptImageTag,progress,image->rows);
1086  if (proceed == MagickFalse)
1087  status=MagickFalse;
1088  }
1089  }
1090  excerpt_view=DestroyCacheView(excerpt_view);
1091  image_view=DestroyCacheView(image_view);
1092  excerpt_image->type=image->type;
1093  if (status == MagickFalse)
1094  excerpt_image=DestroyImage(excerpt_image);
1095  return(excerpt_image);
1096 }
1097 
1098 /*
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % %
1101 % %
1102 % %
1103 % E x t e n t I m a g e %
1104 % %
1105 % %
1106 % %
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 %
1109 % ExtentImage() extends the image as defined by the geometry, gravity, and
1110 % image background color. Set the (x,y) offset of the geometry to move the
1111 % original image relative to the extended image.
1112 %
1113 % The format of the ExtentImage method is:
1114 %
1115 % Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1116 % ExceptionInfo *exception)
1117 %
1118 % A description of each parameter follows:
1119 %
1120 % o image: the image.
1121 %
1122 % o geometry: Define the region of the image to extend with members
1123 % x, y, width, and height.
1124 %
1125 % o exception: return any errors or warnings in this structure.
1126 %
1127 */
1129  const RectangleInfo *geometry,ExceptionInfo *exception)
1130 {
1131  Image
1132  *extent_image;
1133 
1135  status;
1136 
1137  const StringInfo
1138  *profile;
1139 
1140  /*
1141  Allocate extent image.
1142  */
1143  assert(image != (const Image *) NULL);
1144  assert(image->signature == MagickCoreSignature);
1145  if (image->debug != MagickFalse)
1146  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1147  assert(geometry != (const RectangleInfo *) NULL);
1148  assert(exception != (ExceptionInfo *) NULL);
1149  assert(exception->signature == MagickCoreSignature);
1150  extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1151  exception);
1152  if (extent_image == (Image *) NULL)
1153  return((Image *) NULL);
1154  status=SetImageBackgroundColor(extent_image,exception);
1155  if (status == MagickFalse)
1156  {
1157  extent_image=DestroyImage(extent_image);
1158  return((Image *) NULL);
1159  }
1160  status=CompositeImage(extent_image,image,image->compose,MagickTrue,
1161  -geometry->x,-geometry->y,exception);
1162  if (status != MagickFalse)
1163  {
1164  profile=GetImageProfile(extent_image,"8bim");
1165  if (profile != (StringInfo *) NULL)
1166  Update8BIMClipPath(profile,image->columns,image->rows,geometry);
1167  }
1168  return(extent_image);
1169 }
1170 
1171 /*
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 % %
1174 % %
1175 % %
1176 % F l i p I m a g e %
1177 % %
1178 % %
1179 % %
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 %
1182 % FlipImage() creates a vertical mirror image by reflecting the pixels
1183 % around the central x-axis.
1184 %
1185 % The format of the FlipImage method is:
1186 %
1187 % Image *FlipImage(const Image *image,ExceptionInfo *exception)
1188 %
1189 % A description of each parameter follows:
1190 %
1191 % o image: the image.
1192 %
1193 % o exception: return any errors or warnings in this structure.
1194 %
1195 */
1197 {
1198 #define FlipImageTag "Flip/Image"
1199 
1200  CacheView
1201  *flip_view,
1202  *image_view;
1203 
1204  Image
1205  *flip_image;
1206 
1208  status;
1209 
1211  progress;
1212 
1214  page;
1215 
1216  ssize_t
1217  y;
1218 
1219  assert(image != (const Image *) NULL);
1220  assert(image->signature == MagickCoreSignature);
1221  if (image->debug != MagickFalse)
1222  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1223  assert(exception != (ExceptionInfo *) NULL);
1224  assert(exception->signature == MagickCoreSignature);
1225  flip_image=CloneImage(image,0,0,MagickTrue,exception);
1226  if (flip_image == (Image *) NULL)
1227  return((Image *) NULL);
1228  /*
1229  Flip image.
1230  */
1231  status=MagickTrue;
1232  progress=0;
1233  page=image->page;
1234  image_view=AcquireVirtualCacheView(image,exception);
1235  flip_view=AcquireAuthenticCacheView(flip_image,exception);
1236 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1237  #pragma omp parallel for schedule(static) shared(status) \
1238  magick_number_threads(image,flip_image,flip_image->rows,1)
1239 #endif
1240  for (y=0; y < (ssize_t) flip_image->rows; y++)
1241  {
1242  register const Quantum
1243  *magick_restrict p;
1244 
1245  register Quantum
1246  *magick_restrict q;
1247 
1248  register ssize_t
1249  x;
1250 
1251  if (status == MagickFalse)
1252  continue;
1253  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1254  q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1255  1),flip_image->columns,1,exception);
1256  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1257  {
1258  status=MagickFalse;
1259  continue;
1260  }
1261  for (x=0; x < (ssize_t) flip_image->columns; x++)
1262  {
1263  register ssize_t
1264  i;
1265 
1266  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1267  {
1268  PixelChannel channel = GetPixelChannelChannel(image,i);
1269  PixelTrait traits = GetPixelChannelTraits(image,channel);
1270  PixelTrait flip_traits=GetPixelChannelTraits(flip_image,channel);
1271  if ((traits == UndefinedPixelTrait) ||
1272  (flip_traits == UndefinedPixelTrait))
1273  continue;
1274  SetPixelChannel(flip_image,channel,p[i],q);
1275  }
1276  p+=GetPixelChannels(image);
1277  q+=GetPixelChannels(flip_image);
1278  }
1279  if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1280  status=MagickFalse;
1281  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1282  {
1284  proceed;
1285 
1286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1287  #pragma omp atomic
1288 #endif
1289  progress++;
1290  proceed=SetImageProgress(image,FlipImageTag,progress,image->rows);
1291  if (proceed == MagickFalse)
1292  status=MagickFalse;
1293  }
1294  }
1295  flip_view=DestroyCacheView(flip_view);
1296  image_view=DestroyCacheView(image_view);
1297  flip_image->type=image->type;
1298  if (page.height != 0)
1299  page.y=(ssize_t) (page.height-flip_image->rows-page.y);
1300  flip_image->page=page;
1301  if (status == MagickFalse)
1302  flip_image=DestroyImage(flip_image);
1303  return(flip_image);
1304 }
1305 
1306 /*
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % %
1309 % %
1310 % %
1311 % F l o p I m a g e %
1312 % %
1313 % %
1314 % %
1315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316 %
1317 % FlopImage() creates a horizontal mirror image by reflecting the pixels
1318 % around the central y-axis.
1319 %
1320 % The format of the FlopImage method is:
1321 %
1322 % Image *FlopImage(const Image *image,ExceptionInfo *exception)
1323 %
1324 % A description of each parameter follows:
1325 %
1326 % o image: the image.
1327 %
1328 % o exception: return any errors or warnings in this structure.
1329 %
1330 */
1332 {
1333 #define FlopImageTag "Flop/Image"
1334 
1335  CacheView
1336  *flop_view,
1337  *image_view;
1338 
1339  Image
1340  *flop_image;
1341 
1343  status;
1344 
1346  progress;
1347 
1349  page;
1350 
1351  ssize_t
1352  y;
1353 
1354  assert(image != (const Image *) NULL);
1355  assert(image->signature == MagickCoreSignature);
1356  if (image->debug != MagickFalse)
1357  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1358  assert(exception != (ExceptionInfo *) NULL);
1359  assert(exception->signature == MagickCoreSignature);
1360  flop_image=CloneImage(image,0,0,MagickTrue,exception);
1361  if (flop_image == (Image *) NULL)
1362  return((Image *) NULL);
1363  /*
1364  Flop each row.
1365  */
1366  status=MagickTrue;
1367  progress=0;
1368  page=image->page;
1369  image_view=AcquireVirtualCacheView(image,exception);
1370  flop_view=AcquireAuthenticCacheView(flop_image,exception);
1371 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1372  #pragma omp parallel for schedule(static) shared(status) \
1373  magick_number_threads(image,flop_image,flop_image->rows,1)
1374 #endif
1375  for (y=0; y < (ssize_t) flop_image->rows; y++)
1376  {
1377  register const Quantum
1378  *magick_restrict p;
1379 
1380  register ssize_t
1381  x;
1382 
1383  register Quantum
1384  *magick_restrict q;
1385 
1386  if (status == MagickFalse)
1387  continue;
1388  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1389  q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1390  exception);
1391  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1392  {
1393  status=MagickFalse;
1394  continue;
1395  }
1396  q+=GetPixelChannels(flop_image)*flop_image->columns;
1397  for (x=0; x < (ssize_t) flop_image->columns; x++)
1398  {
1399  register ssize_t
1400  i;
1401 
1402  q-=GetPixelChannels(flop_image);
1403  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1404  {
1405  PixelChannel channel = GetPixelChannelChannel(image,i);
1406  PixelTrait traits = GetPixelChannelTraits(image,channel);
1407  PixelTrait flop_traits=GetPixelChannelTraits(flop_image,channel);
1408  if ((traits == UndefinedPixelTrait) ||
1409  (flop_traits == UndefinedPixelTrait))
1410  continue;
1411  SetPixelChannel(flop_image,channel,p[i],q);
1412  }
1413  p+=GetPixelChannels(image);
1414  }
1415  if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1416  status=MagickFalse;
1417  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1418  {
1420  proceed;
1421 
1422 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1423  #pragma omp atomic
1424 #endif
1425  progress++;
1426  proceed=SetImageProgress(image,FlopImageTag,progress,image->rows);
1427  if (proceed == MagickFalse)
1428  status=MagickFalse;
1429  }
1430  }
1431  flop_view=DestroyCacheView(flop_view);
1432  image_view=DestroyCacheView(image_view);
1433  flop_image->type=image->type;
1434  if (page.width != 0)
1435  page.x=(ssize_t) (page.width-flop_image->columns-page.x);
1436  flop_image->page=page;
1437  if (status == MagickFalse)
1438  flop_image=DestroyImage(flop_image);
1439  return(flop_image);
1440 }
1441 
1442 /*
1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444 % %
1445 % %
1446 % %
1447 % R o l l I m a g e %
1448 % %
1449 % %
1450 % %
1451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452 %
1453 % RollImage() offsets an image as defined by x_offset and y_offset.
1454 %
1455 % The format of the RollImage method is:
1456 %
1457 % Image *RollImage(const Image *image,const ssize_t x_offset,
1458 % const ssize_t y_offset,ExceptionInfo *exception)
1459 %
1460 % A description of each parameter follows:
1461 %
1462 % o image: the image.
1463 %
1464 % o x_offset: the number of columns to roll in the horizontal direction.
1465 %
1466 % o y_offset: the number of rows to roll in the vertical direction.
1467 %
1468 % o exception: return any errors or warnings in this structure.
1469 %
1470 */
1471 
1472 static MagickBooleanType CopyImageRegion(Image *destination,const Image *source, const size_t columns,const size_t rows,const ssize_t sx,const ssize_t sy,
1473  const ssize_t dx,const ssize_t dy,ExceptionInfo *exception)
1474 {
1475  CacheView
1476  *source_view,
1477  *destination_view;
1478 
1480  status;
1481 
1482  ssize_t
1483  y;
1484 
1485  if (columns == 0)
1486  return(MagickTrue);
1487  status=MagickTrue;
1488  source_view=AcquireVirtualCacheView(source,exception);
1489  destination_view=AcquireAuthenticCacheView(destination,exception);
1490 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1491  #pragma omp parallel for schedule(static) shared(status) \
1492  magick_number_threads(source,destination,rows,1)
1493 #endif
1494  for (y=0; y < (ssize_t) rows; y++)
1495  {
1497  sync;
1498 
1499  register const Quantum
1500  *magick_restrict p;
1501 
1502  register Quantum
1503  *magick_restrict q;
1504 
1505  register ssize_t
1506  x;
1507 
1508  /*
1509  Transfer scanline.
1510  */
1511  if (status == MagickFalse)
1512  continue;
1513  p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1514  q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1515  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1516  {
1517  status=MagickFalse;
1518  continue;
1519  }
1520  for (x=0; x < (ssize_t) columns; x++)
1521  {
1522  register ssize_t
1523  i;
1524 
1525  for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1526  {
1527  PixelChannel channel = GetPixelChannelChannel(source,i);
1528  PixelTrait source_traits=GetPixelChannelTraits(source,channel);
1529  PixelTrait destination_traits=GetPixelChannelTraits(destination,
1530  channel);
1531  if ((source_traits == UndefinedPixelTrait) ||
1532  (destination_traits == UndefinedPixelTrait))
1533  continue;
1534  SetPixelChannel(destination,channel,p[i],q);
1535  }
1536  p+=GetPixelChannels(source);
1537  q+=GetPixelChannels(destination);
1538  }
1539  sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1540  if (sync == MagickFalse)
1541  status=MagickFalse;
1542  }
1543  destination_view=DestroyCacheView(destination_view);
1544  source_view=DestroyCacheView(source_view);
1545  return(status);
1546 }
1547 
1548 MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1549  const ssize_t y_offset,ExceptionInfo *exception)
1550 {
1551 #define RollImageTag "Roll/Image"
1552 
1553  Image
1554  *roll_image;
1555 
1557  status;
1558 
1560  offset;
1561 
1562  /*
1563  Initialize roll image attributes.
1564  */
1565  assert(image != (const Image *) NULL);
1566  assert(image->signature == MagickCoreSignature);
1567  if (image->debug != MagickFalse)
1568  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1569  assert(exception != (ExceptionInfo *) NULL);
1570  assert(exception->signature == MagickCoreSignature);
1571  roll_image=CloneImage(image,0,0,MagickTrue,exception);
1572  if (roll_image == (Image *) NULL)
1573  return((Image *) NULL);
1574  offset.x=x_offset;
1575  offset.y=y_offset;
1576  while (offset.x < 0)
1577  offset.x+=(ssize_t) image->columns;
1578  while (offset.x >= (ssize_t) image->columns)
1579  offset.x-=(ssize_t) image->columns;
1580  while (offset.y < 0)
1581  offset.y+=(ssize_t) image->rows;
1582  while (offset.y >= (ssize_t) image->rows)
1583  offset.y-=(ssize_t) image->rows;
1584  /*
1585  Roll image.
1586  */
1587  status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1588  (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
1589  offset.y,0,0,exception);
1590  (void) SetImageProgress(image,RollImageTag,0,3);
1591  status&=CopyImageRegion(roll_image,image,image->columns-offset.x,
1592  (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
1593  exception);
1594  (void) SetImageProgress(image,RollImageTag,1,3);
1595  status&=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1596  offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
1597  (void) SetImageProgress(image,RollImageTag,2,3);
1598  status&=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1599  offset.y,0,0,offset.x,offset.y,exception);
1600  (void) SetImageProgress(image,RollImageTag,3,3);
1601  roll_image->type=image->type;
1602  if (status == MagickFalse)
1603  roll_image=DestroyImage(roll_image);
1604  return(roll_image);
1605 }
1606 
1607 /*
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 % %
1610 % %
1611 % %
1612 % S h a v e I m a g e %
1613 % %
1614 % %
1615 % %
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 %
1618 % ShaveImage() shaves pixels from the image edges. It allocates the memory
1619 % necessary for the new Image structure and returns a pointer to the new
1620 % image.
1621 %
1622 % The format of the ShaveImage method is:
1623 %
1624 % Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1625 % ExceptionInfo *exception)
1626 %
1627 % A description of each parameter follows:
1628 %
1629 % o shave_image: Method ShaveImage returns a pointer to the shaved
1630 % image. A null image is returned if there is a memory shortage or
1631 % if the image width or height is zero.
1632 %
1633 % o image: the image.
1634 %
1635 % o shave_info: Specifies a pointer to a RectangleInfo which defines the
1636 % region of the image to crop.
1637 %
1638 % o exception: return any errors or warnings in this structure.
1639 %
1640 */
1642  const RectangleInfo *shave_info,ExceptionInfo *exception)
1643 {
1644  Image
1645  *shave_image;
1646 
1648  geometry;
1649 
1650  assert(image != (const Image *) NULL);
1651  assert(image->signature == MagickCoreSignature);
1652  if (image->debug != MagickFalse)
1653  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1654  if (((2*shave_info->width) >= image->columns) ||
1655  ((2*shave_info->height) >= image->rows))
1656  ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1657  SetGeometry(image,&geometry);
1658  geometry.width-=2*shave_info->width;
1659  geometry.height-=2*shave_info->height;
1660  geometry.x=(ssize_t) shave_info->width+image->page.x;
1661  geometry.y=(ssize_t) shave_info->height+image->page.y;
1662  shave_image=CropImage(image,&geometry,exception);
1663  if (shave_image == (Image *) NULL)
1664  return((Image *) NULL);
1665  shave_image->page.width-=2*shave_info->width;
1666  shave_image->page.height-=2*shave_info->height;
1667  shave_image->page.x-=(ssize_t) shave_info->width;
1668  shave_image->page.y-=(ssize_t) shave_info->height;
1669  return(shave_image);
1670 }
1671 
1672 /*
1673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674 % %
1675 % %
1676 % %
1677 % S p l i c e I m a g e %
1678 % %
1679 % %
1680 % %
1681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1682 %
1683 % SpliceImage() splices a solid color into the image as defined by the
1684 % geometry.
1685 %
1686 % The format of the SpliceImage method is:
1687 %
1688 % Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1689 % ExceptionInfo *exception)
1690 %
1691 % A description of each parameter follows:
1692 %
1693 % o image: the image.
1694 %
1695 % o geometry: Define the region of the image to splice with members
1696 % x, y, width, and height.
1697 %
1698 % o exception: return any errors or warnings in this structure.
1699 %
1700 */
1702  const RectangleInfo *geometry,ExceptionInfo *exception)
1703 {
1704 #define SpliceImageTag "Splice/Image"
1705 
1706  CacheView
1707  *image_view,
1708  *splice_view;
1709 
1710  Image
1711  *splice_image;
1712 
1714  status;
1715 
1717  progress;
1718 
1720  splice_geometry;
1721 
1722  ssize_t
1723  columns,
1724  y;
1725 
1726  /*
1727  Allocate splice image.
1728  */
1729  assert(image != (const Image *) NULL);
1730  assert(image->signature == MagickCoreSignature);
1731  if (image->debug != MagickFalse)
1732  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1733  assert(geometry != (const RectangleInfo *) NULL);
1734  assert(exception != (ExceptionInfo *) NULL);
1735  assert(exception->signature == MagickCoreSignature);
1736  splice_geometry=(*geometry);
1737  splice_image=CloneImage(image,image->columns+splice_geometry.width,
1738  image->rows+splice_geometry.height,MagickTrue,exception);
1739  if (splice_image == (Image *) NULL)
1740  return((Image *) NULL);
1741  if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
1742  {
1743  splice_image=DestroyImage(splice_image);
1744  return((Image *) NULL);
1745  }
1746  if ((IsPixelInfoGray(&splice_image->background_color) == MagickFalse) &&
1747  (IsGrayColorspace(splice_image->colorspace) != MagickFalse))
1748  (void) SetImageColorspace(splice_image,sRGBColorspace,exception);
1749  if ((splice_image->background_color.alpha_trait != UndefinedPixelTrait) &&
1750  (splice_image->alpha_trait == UndefinedPixelTrait))
1751  (void) SetImageAlpha(splice_image,OpaqueAlpha,exception);
1752  (void) SetImageBackgroundColor(splice_image,exception);
1753  /*
1754  Respect image geometry.
1755  */
1756  switch (image->gravity)
1757  {
1758  default:
1759  case UndefinedGravity:
1760  case NorthWestGravity:
1761  break;
1762  case NorthGravity:
1763  {
1764  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1765  break;
1766  }
1767  case NorthEastGravity:
1768  {
1769  splice_geometry.x+=(ssize_t) splice_geometry.width;
1770  break;
1771  }
1772  case WestGravity:
1773  {
1774  splice_geometry.y+=(ssize_t) splice_geometry.width/2;
1775  break;
1776  }
1777  case CenterGravity:
1778  {
1779  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1780  splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1781  break;
1782  }
1783  case EastGravity:
1784  {
1785  splice_geometry.x+=(ssize_t) splice_geometry.width;
1786  splice_geometry.y+=(ssize_t) splice_geometry.height/2;
1787  break;
1788  }
1789  case SouthWestGravity:
1790  {
1791  splice_geometry.y+=(ssize_t) splice_geometry.height;
1792  break;
1793  }
1794  case SouthGravity:
1795  {
1796  splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1797  splice_geometry.y+=(ssize_t) splice_geometry.height;
1798  break;
1799  }
1800  case SouthEastGravity:
1801  {
1802  splice_geometry.x+=(ssize_t) splice_geometry.width;
1803  splice_geometry.y+=(ssize_t) splice_geometry.height;
1804  break;
1805  }
1806  }
1807  /*
1808  Splice image.
1809  */
1810  status=MagickTrue;
1811  progress=0;
1812  columns=MagickMin(splice_geometry.x,(ssize_t) splice_image->columns);
1813  image_view=AcquireVirtualCacheView(image,exception);
1814  splice_view=AcquireAuthenticCacheView(splice_image,exception);
1815 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1816  #pragma omp parallel for schedule(static) shared(progress,status) \
1817  magick_number_threads(image,splice_image,splice_geometry.y,1)
1818 #endif
1819  for (y=0; y < (ssize_t) splice_geometry.y; y++)
1820  {
1821  register const Quantum
1822  *magick_restrict p;
1823 
1824  register ssize_t
1825  x;
1826 
1827  register Quantum
1828  *magick_restrict q;
1829 
1830  if (status == MagickFalse)
1831  continue;
1832  p=GetCacheViewVirtualPixels(image_view,0,y,splice_image->columns,1,
1833  exception);
1834  q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1835  exception);
1836  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1837  {
1838  status=MagickFalse;
1839  continue;
1840  }
1841  for (x=0; x < columns; x++)
1842  {
1843  register ssize_t
1844  i;
1845 
1846  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1847  {
1848  PixelChannel channel = GetPixelChannelChannel(image,i);
1849  PixelTrait traits = GetPixelChannelTraits(image,channel);
1850  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1851  if ((traits == UndefinedPixelTrait) ||
1852  (splice_traits == UndefinedPixelTrait))
1853  continue;
1854  SetPixelChannel(splice_image,channel,p[i],q);
1855  }
1856  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1857  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1858  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1859  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1860  p+=GetPixelChannels(image);
1861  q+=GetPixelChannels(splice_image);
1862  }
1863  for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1864  q+=GetPixelChannels(splice_image);
1865  for ( ; x < (ssize_t) splice_image->columns; x++)
1866  {
1867  register ssize_t
1868  i;
1869 
1870  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1871  {
1872  PixelChannel channel = GetPixelChannelChannel(image,i);
1873  PixelTrait traits = GetPixelChannelTraits(image,channel);
1874  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1875  if ((traits == UndefinedPixelTrait) ||
1876  (splice_traits == UndefinedPixelTrait))
1877  continue;
1878  SetPixelChannel(splice_image,channel,p[i],q);
1879  }
1880  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1881  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1882  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1883  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1884  p+=GetPixelChannels(image);
1885  q+=GetPixelChannels(splice_image);
1886  }
1887  if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1888  status=MagickFalse;
1889  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1890  {
1892  proceed;
1893 
1894 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1895  #pragma omp atomic
1896 #endif
1897  progress++;
1898  proceed=SetImageProgress(image,SpliceImageTag,progress,
1899  splice_image->rows);
1900  if (proceed == MagickFalse)
1901  status=MagickFalse;
1902  }
1903  }
1904 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1905  #pragma omp parallel for schedule(static) shared(progress,status) \
1906  magick_number_threads(image,splice_image,splice_image->rows,2)
1907 #endif
1908  for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1909  y < (ssize_t) splice_image->rows; y++)
1910  {
1911  register const Quantum
1912  *magick_restrict p;
1913 
1914  register ssize_t
1915  x;
1916 
1917  register Quantum
1918  *magick_restrict q;
1919 
1920  if (status == MagickFalse)
1921  continue;
1922  if ((y < 0) || (y >= (ssize_t)splice_image->rows))
1923  continue;
1924  p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
1925  splice_image->columns,1,exception);
1926  q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1927  exception);
1928  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1929  {
1930  status=MagickFalse;
1931  continue;
1932  }
1933  for (x=0; x < columns; x++)
1934  {
1935  register ssize_t
1936  i;
1937 
1938  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1939  {
1940  PixelChannel channel = GetPixelChannelChannel(image,i);
1941  PixelTrait traits = GetPixelChannelTraits(image,channel);
1942  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1943  if ((traits == UndefinedPixelTrait) ||
1944  (splice_traits == UndefinedPixelTrait))
1945  continue;
1946  SetPixelChannel(splice_image,channel,p[i],q);
1947  }
1948  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1949  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1950  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1951  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1952  p+=GetPixelChannels(image);
1953  q+=GetPixelChannels(splice_image);
1954  }
1955  for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
1956  q+=GetPixelChannels(splice_image);
1957  for ( ; x < (ssize_t) splice_image->columns; x++)
1958  {
1959  register ssize_t
1960  i;
1961 
1962  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1963  {
1964  PixelChannel channel = GetPixelChannelChannel(image,i);
1965  PixelTrait traits = GetPixelChannelTraits(image,channel);
1966  PixelTrait splice_traits=GetPixelChannelTraits(splice_image,channel);
1967  if ((traits == UndefinedPixelTrait) ||
1968  (splice_traits == UndefinedPixelTrait))
1969  continue;
1970  SetPixelChannel(splice_image,channel,p[i],q);
1971  }
1972  SetPixelRed(splice_image,GetPixelRed(image,p),q);
1973  SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
1974  SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
1975  SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
1976  p+=GetPixelChannels(image);
1977  q+=GetPixelChannels(splice_image);
1978  }
1979  if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1980  status=MagickFalse;
1981  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1982  {
1984  proceed;
1985 
1986 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1987  #pragma omp atomic
1988 #endif
1989  progress++;
1990  proceed=SetImageProgress(image,SpliceImageTag,progress,
1991  splice_image->rows);
1992  if (proceed == MagickFalse)
1993  status=MagickFalse;
1994  }
1995  }
1996  splice_view=DestroyCacheView(splice_view);
1997  image_view=DestroyCacheView(image_view);
1998  if (status == MagickFalse)
1999  splice_image=DestroyImage(splice_image);
2000  return(splice_image);
2001 }
2002 
2003 /*
2004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005 % %
2006 % %
2007 % %
2008 % T r a n s f o r m I m a g e %
2009 % %
2010 % %
2011 % %
2012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 %
2014 % TransformImage() is a convenience method that behaves like ResizeImage() or
2015 % CropImage() but accepts scaling and/or cropping information as a region
2016 % geometry specification. If the operation fails, the original image handle
2017 % is left as is.
2018 %
2019 % This should only be used for single images.
2020 %
2021 % This function destroys what it assumes to be a single image list.
2022 % If the input image is part of a larger list, all other images in that list
2023 % will be simply 'lost', not destroyed.
2024 %
2025 % Also if the crop generates a list of images only the first image is resized.
2026 % And finally if the crop succeeds and the resize failed, you will get a
2027 % cropped image, as well as a 'false' or 'failed' report.
2028 %
2029 % This function and should probably be deprecated in favor of direct calls
2030 % to CropImageToTiles() or ResizeImage(), as appropriate.
2031 %
2032 % The format of the TransformImage method is:
2033 %
2034 % MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
2035 % const char *image_geometry,ExceptionInfo *exception)
2036 %
2037 % A description of each parameter follows:
2038 %
2039 % o image: the image The transformed image is returned as this parameter.
2040 %
2041 % o crop_geometry: A crop geometry string. This geometry defines a
2042 % subregion of the image to crop.
2043 %
2044 % o image_geometry: An image geometry string. This geometry defines the
2045 % final size of the image.
2046 %
2047 % o exception: return any errors or warnings in this structure.
2048 %
2049 */
2051  const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
2052 {
2053  Image
2054  *resize_image,
2055  *transform_image;
2056 
2058  geometry;
2059 
2060  assert(image != (Image **) NULL);
2061  assert((*image)->signature == MagickCoreSignature);
2062  if ((*image)->debug != MagickFalse)
2063  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2064  transform_image=(*image);
2065  if (crop_geometry != (const char *) NULL)
2066  {
2067  Image
2068  *crop_image;
2069 
2070  /*
2071  Crop image to a user specified size.
2072  */
2073  crop_image=CropImageToTiles(*image,crop_geometry,exception);
2074  if (crop_image == (Image *) NULL)
2075  transform_image=CloneImage(*image,0,0,MagickTrue,exception);
2076  else
2077  {
2078  transform_image=DestroyImage(transform_image);
2079  transform_image=GetFirstImageInList(crop_image);
2080  }
2081  *image=transform_image;
2082  }
2083  if (image_geometry == (const char *) NULL)
2084  return(MagickTrue);
2085  /*
2086  Scale image to a user specified size.
2087  */
2088  (void) ParseRegionGeometry(transform_image,image_geometry,&geometry,
2089  exception);
2090  if ((transform_image->columns == geometry.width) &&
2091  (transform_image->rows == geometry.height))
2092  return(MagickTrue);
2093  resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
2094  transform_image->filter,exception);
2095  if (resize_image == (Image *) NULL)
2096  return(MagickFalse);
2097  transform_image=DestroyImage(transform_image);
2098  transform_image=resize_image;
2099  *image=transform_image;
2100  return(MagickTrue);
2101 }
2102 
2103 /*
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2105 % %
2106 % %
2107 % %
2108 % T r a n s p o s e I m a g e %
2109 % %
2110 % %
2111 % %
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113 %
2114 % TransposeImage() creates a horizontal mirror image by reflecting the pixels
2115 % around the central y-axis while rotating them by 90 degrees.
2116 %
2117 % The format of the TransposeImage method is:
2118 %
2119 % Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2120 %
2121 % A description of each parameter follows:
2122 %
2123 % o image: the image.
2124 %
2125 % o exception: return any errors or warnings in this structure.
2126 %
2127 */
2129 {
2130 #define TransposeImageTag "Transpose/Image"
2131 
2132  CacheView
2133  *image_view,
2134  *transpose_view;
2135 
2136  Image
2137  *transpose_image;
2138 
2140  status;
2141 
2143  progress;
2144 
2146  page;
2147 
2148  ssize_t
2149  y;
2150 
2151  assert(image != (const Image *) NULL);
2152  assert(image->signature == MagickCoreSignature);
2153  if (image->debug != MagickFalse)
2154  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2155  assert(exception != (ExceptionInfo *) NULL);
2156  assert(exception->signature == MagickCoreSignature);
2157  transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2158  exception);
2159  if (transpose_image == (Image *) NULL)
2160  return((Image *) NULL);
2161  /*
2162  Transpose image.
2163  */
2164  status=MagickTrue;
2165  progress=0;
2166  image_view=AcquireVirtualCacheView(image,exception);
2167  transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
2168 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2169  #pragma omp parallel for schedule(static) shared(progress,status) \
2170  magick_number_threads(image,transpose_image,image->rows,1)
2171 #endif
2172  for (y=0; y < (ssize_t) image->rows; y++)
2173  {
2174  register const Quantum
2175  *magick_restrict p;
2176 
2177  register Quantum
2178  *magick_restrict q;
2179 
2180  register ssize_t
2181  x;
2182 
2183  if (status == MagickFalse)
2184  continue;
2185  p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
2186  image->columns,1,exception);
2187  q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2188  0,1,transpose_image->rows,exception);
2189  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2190  {
2191  status=MagickFalse;
2192  continue;
2193  }
2194  for (x=0; x < (ssize_t) image->columns; x++)
2195  {
2196  register ssize_t
2197  i;
2198 
2199  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2200  {
2201  PixelChannel channel = GetPixelChannelChannel(image,i);
2202  PixelTrait traits = GetPixelChannelTraits(image,channel);
2203  PixelTrait transpose_traits=GetPixelChannelTraits(transpose_image,
2204  channel);
2205  if ((traits == UndefinedPixelTrait) ||
2206  (transpose_traits == UndefinedPixelTrait))
2207  continue;
2208  SetPixelChannel(transpose_image,channel,p[i],q);
2209  }
2210  p+=GetPixelChannels(image);
2211  q+=GetPixelChannels(transpose_image);
2212  }
2213  if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2214  status=MagickFalse;
2215  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2216  {
2218  proceed;
2219 
2220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2221  #pragma omp atomic
2222 #endif
2223  progress++;
2224  proceed=SetImageProgress(image,TransposeImageTag,progress,image->rows);
2225  if (proceed == MagickFalse)
2226  status=MagickFalse;
2227  }
2228  }
2229  transpose_view=DestroyCacheView(transpose_view);
2230  image_view=DestroyCacheView(image_view);
2231  transpose_image->type=image->type;
2232  page=transpose_image->page;
2233  Swap(page.width,page.height);
2234  Swap(page.x,page.y);
2235  transpose_image->page=page;
2236  if (status == MagickFalse)
2237  transpose_image=DestroyImage(transpose_image);
2238  return(transpose_image);
2239 }
2240 
2241 /*
2242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % %
2244 % %
2245 % %
2246 % T r a n s v e r s e I m a g e %
2247 % %
2248 % %
2249 % %
2250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251 %
2252 % TransverseImage() creates a vertical mirror image by reflecting the pixels
2253 % around the central x-axis while rotating them by 270 degrees.
2254 %
2255 % The format of the TransverseImage method is:
2256 %
2257 % Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2258 %
2259 % A description of each parameter follows:
2260 %
2261 % o image: the image.
2262 %
2263 % o exception: return any errors or warnings in this structure.
2264 %
2265 */
2267 {
2268 #define TransverseImageTag "Transverse/Image"
2269 
2270  CacheView
2271  *image_view,
2272  *transverse_view;
2273 
2274  Image
2275  *transverse_image;
2276 
2278  status;
2279 
2281  progress;
2282 
2284  page;
2285 
2286  ssize_t
2287  y;
2288 
2289  assert(image != (const Image *) NULL);
2290  assert(image->signature == MagickCoreSignature);
2291  if (image->debug != MagickFalse)
2292  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2293  assert(exception != (ExceptionInfo *) NULL);
2294  assert(exception->signature == MagickCoreSignature);
2295  transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2296  exception);
2297  if (transverse_image == (Image *) NULL)
2298  return((Image *) NULL);
2299  /*
2300  Transverse image.
2301  */
2302  status=MagickTrue;
2303  progress=0;
2304  image_view=AcquireVirtualCacheView(image,exception);
2305  transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
2306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2307  #pragma omp parallel for schedule(static) shared(progress,status) \
2308  magick_number_threads(image,transverse_image,image->rows,1)
2309 #endif
2310  for (y=0; y < (ssize_t) image->rows; y++)
2311  {
2313  sync;
2314 
2315  register const Quantum
2316  *magick_restrict p;
2317 
2318  register Quantum
2319  *magick_restrict q;
2320 
2321  register ssize_t
2322  x;
2323 
2324  if (status == MagickFalse)
2325  continue;
2326  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2327  q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2328  0,1,transverse_image->rows,exception);
2329  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2330  {
2331  status=MagickFalse;
2332  continue;
2333  }
2334  q+=GetPixelChannels(transverse_image)*image->columns;
2335  for (x=0; x < (ssize_t) image->columns; x++)
2336  {
2337  register ssize_t
2338  i;
2339 
2340  q-=GetPixelChannels(transverse_image);
2341  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2342  {
2343  PixelChannel channel = GetPixelChannelChannel(image,i);
2344  PixelTrait traits = GetPixelChannelTraits(image,channel);
2345  PixelTrait transverse_traits=GetPixelChannelTraits(transverse_image,
2346  channel);
2347  if ((traits == UndefinedPixelTrait) ||
2348  (transverse_traits == UndefinedPixelTrait))
2349  continue;
2350  SetPixelChannel(transverse_image,channel,p[i],q);
2351  }
2352  p+=GetPixelChannels(image);
2353  }
2354  sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2355  if (sync == MagickFalse)
2356  status=MagickFalse;
2357  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2358  {
2360  proceed;
2361 
2362 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2363  #pragma omp atomic
2364 #endif
2365  progress++;
2366  proceed=SetImageProgress(image,TransverseImageTag,progress,image->rows);
2367  if (proceed == MagickFalse)
2368  status=MagickFalse;
2369  }
2370  }
2371  transverse_view=DestroyCacheView(transverse_view);
2372  image_view=DestroyCacheView(image_view);
2373  transverse_image->type=image->type;
2374  page=transverse_image->page;
2375  Swap(page.width,page.height);
2376  Swap(page.x,page.y);
2377  if (page.width != 0)
2378  page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
2379  if (page.height != 0)
2380  page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
2381  transverse_image->page=page;
2382  if (status == MagickFalse)
2383  transverse_image=DestroyImage(transverse_image);
2384  return(transverse_image);
2385 }
2386 
2387 /*
2388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389 % %
2390 % %
2391 % %
2392 % T r i m I m a g e %
2393 % %
2394 % %
2395 % %
2396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397 %
2398 % TrimImage() trims pixels from the image edges. It allocates the memory
2399 % necessary for the new Image structure and returns a pointer to the new
2400 % image.
2401 %
2402 % The format of the TrimImage method is:
2403 %
2404 % Image *TrimImage(const Image *image,ExceptionInfo *exception)
2405 %
2406 % A description of each parameter follows:
2407 %
2408 % o image: the image.
2409 %
2410 % o exception: return any errors or warnings in this structure.
2411 %
2412 */
2414 {
2416  geometry;
2417 
2418  assert(image != (const Image *) NULL);
2419  assert(image->signature == MagickCoreSignature);
2420  if (image->debug != MagickFalse)
2421  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2422  geometry=GetImageBoundingBox(image,exception);
2423  if ((geometry.width == 0) || (geometry.height == 0))
2424  {
2425  Image
2426  *crop_image;
2427 
2428  crop_image=CloneImage(image,1,1,MagickTrue,exception);
2429  if (crop_image == (Image *) NULL)
2430  return((Image *) NULL);
2433  (void) SetImageBackgroundColor(crop_image,exception);
2434  crop_image->page=image->page;
2435  crop_image->page.x=(-1);
2436  crop_image->page.y=(-1);
2437  return(crop_image);
2438  }
2439  geometry.x+=image->page.x;
2440  geometry.y+=image->page.y;
2441  return(CropImage(image,&geometry,exception));
2442 }
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:1196
#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:1331
MagickExport Image * TransposeImage(const Image *image, ExceptionInfo *exception)
Definition: transform.c:2128
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:2050
#define OpaqueAlpha
Definition: image.h:25
MagickExport MagickBooleanType SetImageAlpha(Image *image, const Quantum alpha, ExceptionInfo *exception)
Definition: image.c:2316
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:2266
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:130
#define ChopImageTag
MagickExport Image * CropImageToTiles(const Image *image, const char *crop_geometry, ExceptionInfo *exception)
Definition: transform.c:789
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:123
static double ConstrainPixelOffset(double x)
Definition: transform.c:770
#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:574
MagickBooleanType
Definition: magick-type.h:169
MagickExport Image * NewImageList(void)
Definition: list.c:951
unsigned int MagickStatusType
Definition: magick-type.h:125
static ssize_t PixelRoundOffset(double x)
Definition: transform.c:779
double y
Definition: geometry.h:123
MagickExport Image * SpliceImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:1701
GravityType gravity
Definition: image.h:231
MagickExport const StringInfo * GetImageProfile(const Image *image, const char *name)
Definition: profile.c:259
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:1548
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:2950
MagickExport MagickBooleanType SetImageBackgroundColor(Image *image, ExceptionInfo *exception)
Definition: image.c:2395
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:988
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
ssize_t x
Definition: geometry.h:134
size_t height
Definition: geometry.h:130
static void SetPixelMagenta(const Image *magick_restrict image, const Quantum magenta, Quantum *magick_restrict pixel)
#define FlipImageTag
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2595
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
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:1312
MagickExport Image * ExtentImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:1128
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:784
MagickExport Image * ShaveImage(const Image *image, const RectangleInfo *shave_info, ExceptionInfo *exception)
Definition: transform.c:1641
MagickPrivate void Update8BIMClipPath(const StringInfo *, const size_t, const size_t, const RectangleInfo *)
Definition: profile.c:2471
#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:1689
#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: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:2413
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:1472
#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: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:709
#define ExcerptImageTag
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1160
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:775
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)