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