blob: e900e93d52f98e6a253343e5350d7968f267ea43 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
47#include "MagickCore/color-private.h"
48#include "MagickCore/colorspace-private.h"
49#include "MagickCore/composite.h"
50#include "MagickCore/draw.h"
51#include "MagickCore/effect.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/geometry.h"
55#include "MagickCore/image.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/layer.h"
58#include "MagickCore/list.h"
59#include "MagickCore/monitor.h"
60#include "MagickCore/monitor-private.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/resize.h"
64#include "MagickCore/statistic.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/thread-private.h"
67#include "MagickCore/transform.h"
cristy3ed852e2009-09-05 21:47:34 +000068
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71% %
72% %
73% %
74% C h o p I m a g e %
75% %
76% %
77% %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
cristy00f95372010-02-13 16:39:29 +000080% ChopImage() removes a region of an image and collapses the image to occupy
81% the removed portion.
cristy3ed852e2009-09-05 21:47:34 +000082%
83% The format of the ChopImage method is:
84%
85% Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
86% ExceptionInfo *exception)
87%
88% A description of each parameter follows:
89%
90% o image: the image.
91%
92% o chop_info: Define the region of the image to chop.
93%
94% o exception: return any errors or warnings in this structure.
95%
96*/
97MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
98 ExceptionInfo *exception)
99{
100#define ChopImageTag "Chop/Image"
101
cristyc4c8d132010-01-07 01:58:38 +0000102 CacheView
103 *chop_view,
104 *image_view;
105
cristy3ed852e2009-09-05 21:47:34 +0000106 Image
107 *chop_image;
108
cristy3ed852e2009-09-05 21:47:34 +0000109 MagickBooleanType
cristy00f95372010-02-13 16:39:29 +0000110 status;
cristy3ed852e2009-09-05 21:47:34 +0000111
cristyc2b1fb82010-10-25 13:01:28 +0000112 MagickOffsetType
113 progress;
114
cristy3ed852e2009-09-05 21:47:34 +0000115 RectangleInfo
116 extent;
117
cristy9d314ff2011-03-09 01:30:28 +0000118 ssize_t
119 y;
120
cristy3ed852e2009-09-05 21:47:34 +0000121 /*
122 Check chop geometry.
123 */
124 assert(image != (const Image *) NULL);
125 assert(image->signature == MagickSignature);
126 if (image->debug != MagickFalse)
127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
128 assert(exception != (ExceptionInfo *) NULL);
129 assert(exception->signature == MagickSignature);
130 assert(chop_info != (RectangleInfo *) NULL);
cristybb503372010-05-27 20:51:26 +0000131 if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
132 ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
133 (chop_info->x > (ssize_t) image->columns) ||
134 (chop_info->y > (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000135 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
136 extent=(*chop_info);
cristybb503372010-05-27 20:51:26 +0000137 if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
138 extent.width=(size_t) ((ssize_t) image->columns-extent.x);
139 if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
140 extent.height=(size_t) ((ssize_t) image->rows-extent.y);
cristy3ed852e2009-09-05 21:47:34 +0000141 if (extent.x < 0)
142 {
cristybb503372010-05-27 20:51:26 +0000143 extent.width-=(size_t) (-extent.x);
cristy3ed852e2009-09-05 21:47:34 +0000144 extent.x=0;
145 }
146 if (extent.y < 0)
147 {
cristybb503372010-05-27 20:51:26 +0000148 extent.height-=(size_t) (-extent.y);
cristy3ed852e2009-09-05 21:47:34 +0000149 extent.y=0;
150 }
151 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
152 extent.height,MagickTrue,exception);
153 if (chop_image == (Image *) NULL)
154 return((Image *) NULL);
155 /*
156 Extract chop image.
157 */
cristy00f95372010-02-13 16:39:29 +0000158 status=MagickTrue;
cristyc2b1fb82010-10-25 13:01:28 +0000159 progress=0;
cristydb070952012-04-20 14:33:00 +0000160 image_view=AcquireVirtualCacheView(image,exception);
161 chop_view=AcquireAuthenticCacheView(chop_image,exception);
cristy9a5a52f2012-10-09 14:40:31 +0000162#if defined(MAGICKCORE_OPENMP_SUPPORT) && !defined(NoBenefitFromParallelism)
163 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000164 dynamic_number_threads(image,image->columns,image->rows,1)
cristy09d81172010-10-21 16:15:05 +0000165#endif
cristybb503372010-05-27 20:51:26 +0000166 for (y=0; y < (ssize_t) extent.y; y++)
cristy3ed852e2009-09-05 21:47:34 +0000167 {
cristy4c08aed2011-07-01 19:47:50 +0000168 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000169 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000170
cristybb503372010-05-27 20:51:26 +0000171 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000172 x;
173
cristy4c08aed2011-07-01 19:47:50 +0000174 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000175 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000176
cristy00f95372010-02-13 16:39:29 +0000177 if (status == MagickFalse)
178 continue;
cristyc2b1fb82010-10-25 13:01:28 +0000179 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
180 q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
cristy3ed852e2009-09-05 21:47:34 +0000181 exception);
cristy4c08aed2011-07-01 19:47:50 +0000182 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy00f95372010-02-13 16:39:29 +0000183 {
184 status=MagickFalse;
185 continue;
186 }
cristybb503372010-05-27 20:51:26 +0000187 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000188 {
cristybb503372010-05-27 20:51:26 +0000189 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
cristy3ed852e2009-09-05 21:47:34 +0000190 {
cristyd000c802011-09-20 02:03:18 +0000191 register ssize_t
192 i;
193
194 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
195 {
196 PixelChannel
197 channel;
198
199 PixelTrait
200 chop_traits,
201 traits;
202
cristycf1296e2012-08-26 23:40:49 +0000203 channel=GetPixelChannelChannel(image,i);
204 traits=GetPixelChannelTraits(image,channel);
205 chop_traits=GetPixelChannelTraits(chop_image,channel);
cristyd000c802011-09-20 02:03:18 +0000206 if ((traits == UndefinedPixelTrait) ||
207 (chop_traits == UndefinedPixelTrait))
208 continue;
cristy0beccfa2011-09-25 20:47:53 +0000209 SetPixelChannel(chop_image,channel,p[i],q);
cristyd000c802011-09-20 02:03:18 +0000210 }
cristyed231572011-07-14 02:18:59 +0000211 q+=GetPixelChannels(chop_image);
cristy3ed852e2009-09-05 21:47:34 +0000212 }
cristyed231572011-07-14 02:18:59 +0000213 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000214 }
215 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
cristy00f95372010-02-13 16:39:29 +0000216 status=MagickFalse;
cristyc2b1fb82010-10-25 13:01:28 +0000217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
218 {
219 MagickBooleanType
220 proceed;
221
cristy9a5a52f2012-10-09 14:40:31 +0000222#if defined(MAGICKCORE_OPENMP_SUPPORT) && !defined(NoBenefitFromParallelism)
cristya5ab7ad2012-01-21 23:49:58 +0000223 #pragma omp critical (MagickCore_ChopImage)
cristyc2b1fb82010-10-25 13:01:28 +0000224#endif
225 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
226 if (proceed == MagickFalse)
227 status=MagickFalse;
228 }
cristy3ed852e2009-09-05 21:47:34 +0000229 }
230 /*
231 Extract chop image.
232 */
cristy9a5a52f2012-10-09 14:40:31 +0000233#if defined(MAGICKCORE_OPENMP_SUPPORT) && !defined(NoBenefitFromParallelism)
234 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000235 dynamic_number_threads(image,image->columns,image->rows,1)
cristy09d81172010-10-21 16:15:05 +0000236#endif
cristybb503372010-05-27 20:51:26 +0000237 for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
cristy3ed852e2009-09-05 21:47:34 +0000238 {
cristy4c08aed2011-07-01 19:47:50 +0000239 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000240 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000241
cristybb503372010-05-27 20:51:26 +0000242 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000243 x;
244
cristy4c08aed2011-07-01 19:47:50 +0000245 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000246 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000247
cristy00f95372010-02-13 16:39:29 +0000248 if (status == MagickFalse)
249 continue;
cristyc2b1fb82010-10-25 13:01:28 +0000250 p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
251 image->columns,1,exception);
252 q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
253 1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000254 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy00f95372010-02-13 16:39:29 +0000255 {
256 status=MagickFalse;
257 continue;
258 }
cristybb503372010-05-27 20:51:26 +0000259 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000260 {
cristybb503372010-05-27 20:51:26 +0000261 if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristyd000c802011-09-20 02:03:18 +0000263 register ssize_t
264 i;
265
266 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
267 {
268 PixelChannel
269 channel;
270
271 PixelTrait
272 chop_traits,
273 traits;
274
cristycf1296e2012-08-26 23:40:49 +0000275 channel=GetPixelChannelChannel(image,i);
276 traits=GetPixelChannelTraits(image,channel);
277 chop_traits=GetPixelChannelTraits(chop_image,channel);
cristyd000c802011-09-20 02:03:18 +0000278 if ((traits == UndefinedPixelTrait) ||
279 (chop_traits == UndefinedPixelTrait))
280 continue;
cristy0beccfa2011-09-25 20:47:53 +0000281 SetPixelChannel(chop_image,channel,p[i],q);
cristyd000c802011-09-20 02:03:18 +0000282 }
cristyed231572011-07-14 02:18:59 +0000283 q+=GetPixelChannels(chop_image);
cristy3ed852e2009-09-05 21:47:34 +0000284 }
cristyed231572011-07-14 02:18:59 +0000285 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000286 }
287 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
cristy00f95372010-02-13 16:39:29 +0000288 status=MagickFalse;
cristyc2b1fb82010-10-25 13:01:28 +0000289 if (image->progress_monitor != (MagickProgressMonitor) NULL)
290 {
291 MagickBooleanType
292 proceed;
293
cristy9a5a52f2012-10-09 14:40:31 +0000294#if defined(MAGICKCORE_OPENMP_SUPPORT) && !defined(NoBenefitFromParallelism)
cristya5ab7ad2012-01-21 23:49:58 +0000295 #pragma omp critical (MagickCore_ChopImage)
cristyc2b1fb82010-10-25 13:01:28 +0000296#endif
297 proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
298 if (proceed == MagickFalse)
299 status=MagickFalse;
300 }
cristy3ed852e2009-09-05 21:47:34 +0000301 }
302 chop_view=DestroyCacheView(chop_view);
303 image_view=DestroyCacheView(image_view);
304 chop_image->type=image->type;
305 return(chop_image);
306}
307
308/*
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310% %
311% %
312% %
313+ C o n s o l i d a t e C M Y K I m a g e %
314% %
315% %
316% %
317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318%
319% ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
320% single image.
321%
322% The format of the ConsolidateCMYKImage method is:
323%
324% Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
325%
326% A description of each parameter follows:
327%
328% o image: the image sequence.
329%
330% o exception: return any errors or warnings in this structure.
331%
332*/
333MagickExport Image *ConsolidateCMYKImages(const Image *images,
334 ExceptionInfo *exception)
335{
cristyc5c6f662010-09-22 14:23:02 +0000336 CacheView
337 *cmyk_view,
338 *image_view;
cristy2224dcd2010-11-15 00:49:30 +0000339
cristy3ed852e2009-09-05 21:47:34 +0000340 Image
341 *cmyk_image,
342 *cmyk_images;
343
cristybb503372010-05-27 20:51:26 +0000344 register ssize_t
cristyd000c802011-09-20 02:03:18 +0000345 j;
cristy3ed852e2009-09-05 21:47:34 +0000346
cristy2224dcd2010-11-15 00:49:30 +0000347 ssize_t
348 y;
349
cristy3ed852e2009-09-05 21:47:34 +0000350 /*
351 Consolidate separate C, M, Y, and K planes into a single image.
352 */
353 assert(images != (Image *) NULL);
354 assert(images->signature == MagickSignature);
355 if (images->debug != MagickFalse)
356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
357 assert(exception != (ExceptionInfo *) NULL);
358 assert(exception->signature == MagickSignature);
359 cmyk_images=NewImageList();
cristyd000c802011-09-20 02:03:18 +0000360 for (j=0; j < (ssize_t) GetImageListLength(images); j+=4)
cristy3ed852e2009-09-05 21:47:34 +0000361 {
cristyd000c802011-09-20 02:03:18 +0000362 register ssize_t
363 i;
364
cristy3ed852e2009-09-05 21:47:34 +0000365 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
366 exception);
367 if (cmyk_image == (Image *) NULL)
368 break;
cristy574cc262011-08-05 01:23:58 +0000369 if (SetImageStorageClass(cmyk_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000370 break;
cristy63240882011-08-05 19:05:27 +0000371 (void) SetImageColorspace(cmyk_image,CMYKColorspace,exception);
cristyd000c802011-09-20 02:03:18 +0000372 for (i=0; i < 4; i++)
cristy3ed852e2009-09-05 21:47:34 +0000373 {
cristydb070952012-04-20 14:33:00 +0000374 image_view=AcquireVirtualCacheView(images,exception);
375 cmyk_view=AcquireAuthenticCacheView(cmyk_image,exception);
cristyd000c802011-09-20 02:03:18 +0000376 for (y=0; y < (ssize_t) images->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000377 {
cristyd000c802011-09-20 02:03:18 +0000378 register const Quantum
379 *restrict p;
380
381 register ssize_t
382 x;
383
384 register Quantum
385 *restrict q;
386
387 p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
388 q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
389 exception);
390 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
391 break;
392 for (x=0; x < (ssize_t) images->columns; x++)
393 {
394 Quantum
395 pixel;
396
397 pixel=QuantumRange-GetPixelIntensity(images,p);
398 switch (i)
399 {
400 case 0: SetPixelCyan(cmyk_image,pixel,q); break;
401 case 1: SetPixelMagenta(cmyk_image,pixel,q); break;
402 case 2: SetPixelYellow(cmyk_image,pixel,q); break;
403 case 3: SetPixelBlack(cmyk_image,pixel,q); break;
404 default: break;
405 }
406 p+=GetPixelChannels(images);
407 q+=GetPixelChannels(cmyk_image);
408 }
409 if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
410 break;
cristy3ed852e2009-09-05 21:47:34 +0000411 }
cristyd000c802011-09-20 02:03:18 +0000412 cmyk_view=DestroyCacheView(cmyk_view);
413 image_view=DestroyCacheView(image_view);
414 images=GetNextImageInList(images);
415 if (images == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000416 break;
417 }
cristy3ed852e2009-09-05 21:47:34 +0000418 AppendImageToList(&cmyk_images,cmyk_image);
cristy3ed852e2009-09-05 21:47:34 +0000419 }
420 return(cmyk_images);
421}
422
423/*
424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425% %
426% %
427% %
428% C r o p I m a g e %
429% %
430% %
431% %
432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433%
434% CropImage() extracts a region of the image starting at the offset defined
anthony9f4f0342011-03-28 11:47:22 +0000435% by geometry. Region must be fully defined, and no special handling of
436% geometry flags is performed.
cristy3ed852e2009-09-05 21:47:34 +0000437%
438% The format of the CropImage method is:
439%
440% Image *CropImage(const Image *image,const RectangleInfo *geometry,
441% ExceptionInfo *exception)
442%
443% A description of each parameter follows:
444%
445% o image: the image.
446%
447% o geometry: Define the region of the image to crop with members
448% x, y, width, and height.
449%
450% o exception: return any errors or warnings in this structure.
451%
452*/
453MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
454 ExceptionInfo *exception)
455{
456#define CropImageTag "Crop/Image"
457
cristyc4c8d132010-01-07 01:58:38 +0000458 CacheView
459 *crop_view,
460 *image_view;
461
cristy3ed852e2009-09-05 21:47:34 +0000462 Image
463 *crop_image;
464
cristy3ed852e2009-09-05 21:47:34 +0000465 MagickBooleanType
466 status;
467
cristybb503372010-05-27 20:51:26 +0000468 MagickOffsetType
469 progress;
470
cristy010d7d12011-08-31 01:02:48 +0000471 OffsetInfo
472 offset;
473
cristy3ed852e2009-09-05 21:47:34 +0000474 RectangleInfo
475 bounding_box,
476 page;
477
cristybb503372010-05-27 20:51:26 +0000478 ssize_t
479 y;
480
cristy3ed852e2009-09-05 21:47:34 +0000481 /*
482 Check crop geometry.
483 */
484 assert(image != (const Image *) NULL);
485 assert(image->signature == MagickSignature);
486 if (image->debug != MagickFalse)
487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
488 assert(geometry != (const RectangleInfo *) NULL);
489 assert(exception != (ExceptionInfo *) NULL);
490 assert(exception->signature == MagickSignature);
491 bounding_box=image->page;
492 if ((bounding_box.width == 0) || (bounding_box.height == 0))
493 {
494 bounding_box.width=image->columns;
495 bounding_box.height=image->rows;
496 }
497 page=(*geometry);
498 if (page.width == 0)
499 page.width=bounding_box.width;
500 if (page.height == 0)
501 page.height=bounding_box.height;
cristybb503372010-05-27 20:51:26 +0000502 if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
503 ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
504 ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
505 ((page.y-bounding_box.y) > (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000506 {
507 /*
508 Crop is not within virtual canvas, return 1 pixel transparent image.
509 */
510 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
anthonye5b39652012-04-21 05:37:29 +0000511 "GeometryDoesNotContainImage","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000512 crop_image=CloneImage(image,1,1,MagickTrue,exception);
513 if (crop_image == (Image *) NULL)
514 return((Image *) NULL);
cristy4c08aed2011-07-01 19:47:50 +0000515 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
cristyea1a8aa2011-10-20 13:24:06 +0000516 (void) SetImageBackgroundColor(crop_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000517 crop_image->page=bounding_box;
518 crop_image->page.x=(-1);
519 crop_image->page.y=(-1);
520 if (crop_image->dispose == BackgroundDispose)
521 crop_image->dispose=NoneDispose;
522 return(crop_image);
523 }
524 if ((page.x < 0) && (bounding_box.x >= 0))
525 {
526 page.width+=page.x-bounding_box.x;
527 page.x=0;
528 }
529 else
530 {
531 page.width-=bounding_box.x-page.x;
532 page.x-=bounding_box.x;
533 if (page.x < 0)
534 page.x=0;
535 }
536 if ((page.y < 0) && (bounding_box.y >= 0))
537 {
538 page.height+=page.y-bounding_box.y;
539 page.y=0;
540 }
541 else
542 {
543 page.height-=bounding_box.y-page.y;
544 page.y-=bounding_box.y;
545 if (page.y < 0)
546 page.y=0;
547 }
cristybb503372010-05-27 20:51:26 +0000548 if ((size_t) (page.x+page.width) > image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000549 page.width=image->columns-page.x;
cristy1e4aa462010-02-15 00:04:18 +0000550 if ((geometry->width != 0) && (page.width > geometry->width))
551 page.width=geometry->width;
cristybb503372010-05-27 20:51:26 +0000552 if ((size_t) (page.y+page.height) > image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000553 page.height=image->rows-page.y;
cristy1e4aa462010-02-15 00:04:18 +0000554 if ((geometry->height != 0) && (page.height > geometry->height))
555 page.height=geometry->height;
cristy3ed852e2009-09-05 21:47:34 +0000556 bounding_box.x+=page.x;
557 bounding_box.y+=page.y;
558 if ((page.width == 0) || (page.height == 0))
559 {
560 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
anthonye5b39652012-04-21 05:37:29 +0000561 "GeometryDoesNotContainImage","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000562 return((Image *) NULL);
563 }
564 /*
565 Initialize crop image attributes.
566 */
567 crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
568 if (crop_image == (Image *) NULL)
569 return((Image *) NULL);
570 crop_image->page.width=image->page.width;
571 crop_image->page.height=image->page.height;
cristy010d7d12011-08-31 01:02:48 +0000572 offset.x=(ssize_t) (bounding_box.x+bounding_box.width);
573 offset.y=(ssize_t) (bounding_box.y+bounding_box.height);
574 if ((offset.x > (ssize_t) image->page.width) ||
575 (offset.y > (ssize_t) image->page.height))
cristy3ed852e2009-09-05 21:47:34 +0000576 {
577 crop_image->page.width=bounding_box.width;
578 crop_image->page.height=bounding_box.height;
579 }
580 crop_image->page.x=bounding_box.x;
581 crop_image->page.y=bounding_box.y;
582 /*
583 Crop image.
584 */
585 status=MagickTrue;
586 progress=0;
cristydb070952012-04-20 14:33:00 +0000587 image_view=AcquireVirtualCacheView(image,exception);
588 crop_view=AcquireAuthenticCacheView(crop_image,exception);
cristy2224dcd2010-11-15 00:49:30 +0000589#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9056d642012-10-09 01:33:00 +0000590 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000591 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +0000592#endif
cristybb503372010-05-27 20:51:26 +0000593 for (y=0; y < (ssize_t) crop_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000594 {
cristy4c08aed2011-07-01 19:47:50 +0000595 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000596 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000597
cristy4c08aed2011-07-01 19:47:50 +0000598 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000599 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000600
cristy5ce8df82011-07-07 14:52:23 +0000601 register ssize_t
cristy4c08aed2011-07-01 19:47:50 +0000602 x;
603
cristy3ed852e2009-09-05 21:47:34 +0000604 if (status == MagickFalse)
605 continue;
606 p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
607 1,exception);
608 q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
609 exception);
cristy4c08aed2011-07-01 19:47:50 +0000610 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000611 {
612 status=MagickFalse;
613 continue;
614 }
cristy4c08aed2011-07-01 19:47:50 +0000615 for (x=0; x < (ssize_t) crop_image->columns; x++)
616 {
cristy010d7d12011-08-31 01:02:48 +0000617 register ssize_t
618 i;
619
cristy10a6c612012-01-29 21:41:05 +0000620 if (GetPixelMask(image,p) != 0)
621 {
622 p+=GetPixelChannels(image);
623 q+=GetPixelChannels(crop_image);
624 continue;
625 }
cristy010d7d12011-08-31 01:02:48 +0000626 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
627 {
628 PixelChannel
629 channel;
630
631 PixelTrait
632 crop_traits,
633 traits;
634
cristycf1296e2012-08-26 23:40:49 +0000635 channel=GetPixelChannelChannel(image,i);
636 traits=GetPixelChannelTraits(image,channel);
637 crop_traits=GetPixelChannelTraits(crop_image,channel);
cristy010d7d12011-08-31 01:02:48 +0000638 if ((traits == UndefinedPixelTrait) ||
639 (crop_traits == UndefinedPixelTrait))
640 continue;
cristy0beccfa2011-09-25 20:47:53 +0000641 SetPixelChannel(crop_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +0000642 }
cristyed231572011-07-14 02:18:59 +0000643 p+=GetPixelChannels(image);
644 q+=GetPixelChannels(crop_image);
cristy4c08aed2011-07-01 19:47:50 +0000645 }
cristy3ed852e2009-09-05 21:47:34 +0000646 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
647 status=MagickFalse;
648 if (image->progress_monitor != (MagickProgressMonitor) NULL)
649 {
650 MagickBooleanType
651 proceed;
652
cristy2224dcd2010-11-15 00:49:30 +0000653#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +0000654 #pragma omp critical (MagickCore_CropImage)
cristy3ed852e2009-09-05 21:47:34 +0000655#endif
656 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
657 if (proceed == MagickFalse)
658 status=MagickFalse;
659 }
660 }
661 crop_view=DestroyCacheView(crop_view);
662 image_view=DestroyCacheView(image_view);
663 crop_image->type=image->type;
664 if (status == MagickFalse)
665 crop_image=DestroyImage(crop_image);
666 return(crop_image);
667}
668
669/*
670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671% %
672% %
673% %
anthony9f4f0342011-03-28 11:47:22 +0000674% C r o p I m a g e T o T i l e s %
675% %
676% %
677% %
678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
679%
cristyfaf49552011-09-16 01:37:07 +0000680% CropImageToTiles() crops a single image, into a possible list of tiles.
anthony9f4f0342011-03-28 11:47:22 +0000681% This may include a single sub-region of the image. This basically applies
682% all the normal geometry flags for Crop.
683%
cristyfaf49552011-09-16 01:37:07 +0000684% Image *CropImageToTiles(const Image *image,
685% const RectangleInfo *crop_geometry, ExceptionInfo *exception)
anthony9f4f0342011-03-28 11:47:22 +0000686%
687% A description of each parameter follows:
688%
689% o image: the image The transformed image is returned as this parameter.
690%
691% o crop_geometry: A crop geometry string.
692%
693% o exception: return any errors or warnings in this structure.
694%
695*/
cristyfde3fa52011-07-22 17:49:35 +0000696
cristya19f1d72012-08-07 18:24:38 +0000697static inline ssize_t MagickRound(double x)
anthony9f4f0342011-03-28 11:47:22 +0000698{
699 /*
700 Round the fraction to nearest integer.
701 */
702 if (x >= 0.0)
703 return((ssize_t) (x+0.5));
704 return((ssize_t) (x-0.5));
705}
706
707MagickExport Image *CropImageToTiles(const Image *image,
cristy9ec43c12012-03-03 15:11:08 +0000708 const char *crop_geometry,ExceptionInfo *exception)
anthony9f4f0342011-03-28 11:47:22 +0000709{
710 Image
711 *next,
712 *crop_image;
713
714 MagickStatusType
715 flags;
716
717 RectangleInfo
718 geometry;
719
720 assert(image != (Image *) NULL);
721 assert(image->signature == MagickSignature);
722 if (image->debug != MagickFalse)
723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
anthony9f4f0342011-03-28 11:47:22 +0000724 crop_image=NewImageList();
725 next=NewImageList();
726 flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
anthony9f4f0342011-03-28 11:47:22 +0000727 if ((flags & AreaValue) != 0)
728 {
anthony9f4f0342011-03-28 11:47:22 +0000729 PointInfo
730 delta,
731 offset;
732
733 RectangleInfo
734 crop;
735
cristyfde3fa52011-07-22 17:49:35 +0000736 size_t
737 height,
738 width;
739
anthony9f4f0342011-03-28 11:47:22 +0000740 /*
cristyfde3fa52011-07-22 17:49:35 +0000741 Crop into NxM tiles (@ flag).
anthony9f4f0342011-03-28 11:47:22 +0000742 */
743 width=image->columns;
744 height=image->rows;
745 if (geometry.width == 0)
746 geometry.width=1;
747 if (geometry.height == 0)
748 geometry.height=1;
749 if ((flags & AspectValue) == 0)
750 {
751 width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
752 height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
753 }
754 else
755 {
756 width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
757 height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
758 }
cristy240ae872011-12-02 12:05:20 +0000759 delta.x=(double) width/geometry.width;
760 delta.y=(double) height/geometry.height;
cristy9ec43c12012-03-03 15:11:08 +0000761 if (delta.x < 1.0)
762 delta.x=1.0;
763 if (delta.y < 1.0)
764 delta.y=1.0;
anthony9f4f0342011-03-28 11:47:22 +0000765 for (offset.y=0; offset.y < (double) height; )
766 {
767 if ((flags & AspectValue) == 0)
768 {
cristya19f1d72012-08-07 18:24:38 +0000769 crop.y=(ssize_t) MagickRound((double) (offset.y-
cristyfde3fa52011-07-22 17:49:35 +0000770 (geometry.y > 0 ? 0 : geometry.y)));
anthony9f4f0342011-03-28 11:47:22 +0000771 offset.y+=delta.y; /* increment now to find width */
cristya19f1d72012-08-07 18:24:38 +0000772 crop.height=(size_t) MagickRound((double) (offset.y+
cristyfde3fa52011-07-22 17:49:35 +0000773 (geometry.y < 0 ? 0 : geometry.y)));
anthony9f4f0342011-03-28 11:47:22 +0000774 }
775 else
776 {
cristya19f1d72012-08-07 18:24:38 +0000777 crop.y=(ssize_t) MagickRound((double) (offset.y-
cristyfde3fa52011-07-22 17:49:35 +0000778 (geometry.y > 0 ? geometry.y : 0)));
anthony9f4f0342011-03-28 11:47:22 +0000779 offset.y+=delta.y; /* increment now to find width */
cristya19f1d72012-08-07 18:24:38 +0000780 crop.height=(size_t) MagickRound((double)
cristyfde3fa52011-07-22 17:49:35 +0000781 (offset.y+(geometry.y < -1 ? geometry.y : 0)));
anthony9f4f0342011-03-28 11:47:22 +0000782 }
783 crop.height-=crop.y;
784 crop.y+=image->page.y;
785 for (offset.x=0; offset.x < (double) width; )
786 {
anthony9f4f0342011-03-28 11:47:22 +0000787 if ((flags & AspectValue) == 0)
788 {
cristya19f1d72012-08-07 18:24:38 +0000789 crop.x=(ssize_t) MagickRound((double) (offset.x-
cristyfde3fa52011-07-22 17:49:35 +0000790 (geometry.x > 0 ? 0 : geometry.x)));
791 offset.x+=delta.x; /* increment now to find height */
cristya19f1d72012-08-07 18:24:38 +0000792 crop.width=(size_t) MagickRound((double) (offset.x+
cristyfde3fa52011-07-22 17:49:35 +0000793 (geometry.x < 0 ? 0 : geometry.x)));
anthony9f4f0342011-03-28 11:47:22 +0000794 }
795 else
796 {
cristya19f1d72012-08-07 18:24:38 +0000797 crop.x=(ssize_t) MagickRound((double) (offset.x-
anthony9f4f0342011-03-28 11:47:22 +0000798 (geometry.x > 0 ? geometry.x : 0)));
cristyfde3fa52011-07-22 17:49:35 +0000799 offset.x+=delta.x; /* increment now to find height */
cristya19f1d72012-08-07 18:24:38 +0000800 crop.width=(size_t) MagickRound((double) (offset.x+
cristyfde3fa52011-07-22 17:49:35 +0000801 (geometry.x < 0 ? geometry.x : 0)));
anthony9f4f0342011-03-28 11:47:22 +0000802 }
803 crop.width-=crop.x;
804 crop.x+=image->page.x;
cristybf46f102011-08-01 18:00:16 +0000805 next=CropImage(image,&crop,exception);
806 if (next == (Image *) NULL)
807 break;
808 AppendImageToList(&crop_image,next);
anthony9f4f0342011-03-28 11:47:22 +0000809 }
810 if (next == (Image *) NULL)
811 break;
anthony9f4f0342011-03-28 11:47:22 +0000812 }
cristy52224bf2011-08-01 18:17:07 +0000813 ClearMagickException(exception);
anthony9f4f0342011-03-28 11:47:22 +0000814 return(crop_image);
815 }
anthony9f4f0342011-03-28 11:47:22 +0000816 if (((geometry.width == 0) && (geometry.height == 0)) ||
817 ((flags & XValue) != 0) || ((flags & YValue) != 0))
818 {
819 /*
820 Crop a single region at +X+Y.
821 */
822 crop_image=CropImage(image,&geometry,exception);
823 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
824 {
825 crop_image->page.width=geometry.width;
826 crop_image->page.height=geometry.height;
827 crop_image->page.x-=geometry.x;
828 crop_image->page.y-=geometry.y;
829 }
830 return(crop_image);
cristy9ec43c12012-03-03 15:11:08 +0000831 }
cristyfde3fa52011-07-22 17:49:35 +0000832 if ((image->columns > geometry.width) || (image->rows > geometry.height))
anthony9f4f0342011-03-28 11:47:22 +0000833 {
cristyfde3fa52011-07-22 17:49:35 +0000834 RectangleInfo
835 page;
anthony9f4f0342011-03-28 11:47:22 +0000836
anthony9f4f0342011-03-28 11:47:22 +0000837 size_t
838 height,
839 width;
840
841 ssize_t
842 x,
843 y;
844
anthony9f4f0342011-03-28 11:47:22 +0000845 /*
846 Crop into tiles of fixed size WxH.
847 */
anthony9f4f0342011-03-28 11:47:22 +0000848 page=image->page;
849 if (page.width == 0)
850 page.width=image->columns;
anthony5ea220b2011-04-22 13:15:46 +0000851 if (page.height == 0)
anthony9f4f0342011-03-28 11:47:22 +0000852 page.height=image->rows;
anthony5ea220b2011-04-22 13:15:46 +0000853 width=geometry.width;
854 if (width == 0)
855 width=page.width;
856 height=geometry.height;
857 if (height == 0)
858 height=page.height;
anthony9f4f0342011-03-28 11:47:22 +0000859 next=NewImageList();
anthony9f4f0342011-03-28 11:47:22 +0000860 for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
861 {
862 for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
863 {
anthony9f4f0342011-03-28 11:47:22 +0000864 geometry.width=width;
865 geometry.height=height;
866 geometry.x=x;
867 geometry.y=y;
868 next=CropImage(image,&geometry,exception);
anthony9f4f0342011-03-28 11:47:22 +0000869 if (next == (Image *) NULL)
870 break;
anthony9f4f0342011-03-28 11:47:22 +0000871 AppendImageToList(&crop_image,next);
872 }
873 if (next == (Image *) NULL)
874 break;
anthony9f4f0342011-03-28 11:47:22 +0000875 }
876 return(crop_image);
877 }
anthony9f4f0342011-03-28 11:47:22 +0000878 return(CloneImage(image,0,0,MagickTrue,exception));
879}
880
881/*
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883% %
884% %
885% %
cristy3ed852e2009-09-05 21:47:34 +0000886% E x c e r p t I m a g e %
887% %
888% %
889% %
890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891%
892% ExcerptImage() returns a excerpt of the image as defined by the geometry.
893%
894% The format of the ExcerptImage method is:
895%
896% Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
897% ExceptionInfo *exception)
898%
899% A description of each parameter follows:
900%
901% o image: the image.
902%
903% o geometry: Define the region of the image to extend with members
904% x, y, width, and height.
905%
906% o exception: return any errors or warnings in this structure.
907%
908*/
909MagickExport Image *ExcerptImage(const Image *image,
910 const RectangleInfo *geometry,ExceptionInfo *exception)
911{
912#define ExcerptImageTag "Excerpt/Image"
913
cristyc4c8d132010-01-07 01:58:38 +0000914 CacheView
915 *excerpt_view,
916 *image_view;
917
cristy3ed852e2009-09-05 21:47:34 +0000918 Image
919 *excerpt_image;
920
cristy3ed852e2009-09-05 21:47:34 +0000921 MagickBooleanType
922 status;
923
cristybb503372010-05-27 20:51:26 +0000924 MagickOffsetType
925 progress;
926
927 ssize_t
928 y;
929
cristy3ed852e2009-09-05 21:47:34 +0000930 /*
931 Allocate excerpt image.
932 */
933 assert(image != (const Image *) NULL);
934 assert(image->signature == MagickSignature);
935 if (image->debug != MagickFalse)
936 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
937 assert(geometry != (const RectangleInfo *) NULL);
938 assert(exception != (ExceptionInfo *) NULL);
939 assert(exception->signature == MagickSignature);
940 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
941 exception);
942 if (excerpt_image == (Image *) NULL)
943 return((Image *) NULL);
944 /*
945 Excerpt each row.
946 */
947 status=MagickTrue;
948 progress=0;
cristydb070952012-04-20 14:33:00 +0000949 image_view=AcquireVirtualCacheView(image,exception);
950 excerpt_view=AcquireAuthenticCacheView(excerpt_image,exception);
cristyb5d5f722009-11-04 03:03:49 +0000951#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000952 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000953 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +0000954#endif
cristybb503372010-05-27 20:51:26 +0000955 for (y=0; y < (ssize_t) excerpt_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000956 {
cristy4c08aed2011-07-01 19:47:50 +0000957 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000958 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000959
cristy4c08aed2011-07-01 19:47:50 +0000960 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000961 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000962
cristy4c08aed2011-07-01 19:47:50 +0000963 register ssize_t
964 x;
965
cristy3ed852e2009-09-05 21:47:34 +0000966 if (status == MagickFalse)
967 continue;
968 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
969 geometry->width,1,exception);
970 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
971 exception);
cristy4c08aed2011-07-01 19:47:50 +0000972 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000973 {
974 status=MagickFalse;
975 continue;
976 }
cristy4c08aed2011-07-01 19:47:50 +0000977 for (x=0; x < (ssize_t) excerpt_image->columns; x++)
978 {
cristy010d7d12011-08-31 01:02:48 +0000979 register ssize_t
980 i;
981
cristy10a6c612012-01-29 21:41:05 +0000982 if (GetPixelMask(image,p) != 0)
983 {
984 p+=GetPixelChannels(image);
985 q+=GetPixelChannels(excerpt_image);
986 continue;
987 }
cristy010d7d12011-08-31 01:02:48 +0000988 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
989 {
990 PixelChannel
991 channel;
992
993 PixelTrait
994 excerpt_traits,
995 traits;
996
cristycf1296e2012-08-26 23:40:49 +0000997 channel=GetPixelChannelChannel(image,i);
998 traits=GetPixelChannelTraits(image,channel);
999 excerpt_traits=GetPixelChannelTraits(excerpt_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001000 if ((traits == UndefinedPixelTrait) ||
1001 (excerpt_traits == UndefinedPixelTrait))
1002 continue;
cristy0beccfa2011-09-25 20:47:53 +00001003 SetPixelChannel(excerpt_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001004 }
cristyed231572011-07-14 02:18:59 +00001005 p+=GetPixelChannels(image);
1006 q+=GetPixelChannels(excerpt_image);
cristy4c08aed2011-07-01 19:47:50 +00001007 }
cristy3ed852e2009-09-05 21:47:34 +00001008 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
1009 status=MagickFalse;
1010 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1011 {
1012 MagickBooleanType
1013 proceed;
1014
cristyb5d5f722009-11-04 03:03:49 +00001015#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00001016 #pragma omp critical (MagickCore_ExcerptImage)
cristy3ed852e2009-09-05 21:47:34 +00001017#endif
1018 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
1019 if (proceed == MagickFalse)
1020 status=MagickFalse;
1021 }
1022 }
1023 excerpt_view=DestroyCacheView(excerpt_view);
1024 image_view=DestroyCacheView(image_view);
1025 excerpt_image->type=image->type;
1026 if (status == MagickFalse)
1027 excerpt_image=DestroyImage(excerpt_image);
1028 return(excerpt_image);
1029}
1030
1031/*
1032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033% %
1034% %
1035% %
1036% E x t e n t I m a g e %
1037% %
1038% %
1039% %
1040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041%
1042% ExtentImage() extends the image as defined by the geometry, gravity, and
1043% image background color. Set the (x,y) offset of the geometry to move the
1044% original image relative to the extended image.
1045%
1046% The format of the ExtentImage method is:
1047%
1048% Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
1049% ExceptionInfo *exception)
1050%
1051% A description of each parameter follows:
1052%
1053% o image: the image.
1054%
1055% o geometry: Define the region of the image to extend with members
1056% x, y, width, and height.
1057%
1058% o exception: return any errors or warnings in this structure.
1059%
1060*/
1061MagickExport Image *ExtentImage(const Image *image,
1062 const RectangleInfo *geometry,ExceptionInfo *exception)
1063{
1064 Image
1065 *extent_image;
1066
1067 /*
1068 Allocate extent image.
1069 */
1070 assert(image != (const Image *) NULL);
1071 assert(image->signature == MagickSignature);
1072 if (image->debug != MagickFalse)
1073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1074 assert(geometry != (const RectangleInfo *) NULL);
1075 assert(exception != (ExceptionInfo *) NULL);
1076 assert(exception->signature == MagickSignature);
1077 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
1078 exception);
1079 if (extent_image == (Image *) NULL)
1080 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00001081 if (SetImageStorageClass(extent_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001082 {
cristy3ed852e2009-09-05 21:47:34 +00001083 extent_image=DestroyImage(extent_image);
1084 return((Image *) NULL);
1085 }
cristy4c08aed2011-07-01 19:47:50 +00001086 if (extent_image->background_color.alpha != OpaqueAlpha)
cristy8a46d822012-08-28 23:32:39 +00001087 extent_image->alpha_trait=BlendPixelTrait;
cristyea1a8aa2011-10-20 13:24:06 +00001088 (void) SetImageBackgroundColor(extent_image,exception);
cristy39172402012-03-30 13:04:39 +00001089 (void) CompositeImage(extent_image,image,image->compose,MagickTrue,
cristyfeb3e962012-03-29 17:25:55 +00001090 -geometry->x,-geometry->y,exception);
cristy3ed852e2009-09-05 21:47:34 +00001091 return(extent_image);
1092}
1093
1094/*
1095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096% %
1097% %
1098% %
1099% F l i p I m a g e %
1100% %
1101% %
1102% %
1103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104%
1105% FlipImage() creates a vertical mirror image by reflecting the pixels
1106% around the central x-axis.
1107%
1108% The format of the FlipImage method is:
1109%
1110% Image *FlipImage(const Image *image,ExceptionInfo *exception)
1111%
1112% A description of each parameter follows:
1113%
1114% o image: the image.
1115%
1116% o exception: return any errors or warnings in this structure.
1117%
1118*/
1119MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
1120{
1121#define FlipImageTag "Flip/Image"
1122
cristyc4c8d132010-01-07 01:58:38 +00001123 CacheView
1124 *flip_view,
1125 *image_view;
1126
cristy3ed852e2009-09-05 21:47:34 +00001127 Image
1128 *flip_image;
1129
cristy3ed852e2009-09-05 21:47:34 +00001130 MagickBooleanType
1131 status;
1132
cristybb503372010-05-27 20:51:26 +00001133 MagickOffsetType
1134 progress;
1135
cristy74ea2cd2010-12-08 02:54:25 +00001136 RectangleInfo
1137 page;
1138
cristybb503372010-05-27 20:51:26 +00001139 ssize_t
1140 y;
1141
cristy3ed852e2009-09-05 21:47:34 +00001142 assert(image != (const Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 assert(exception != (ExceptionInfo *) NULL);
1147 assert(exception->signature == MagickSignature);
1148 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1149 if (flip_image == (Image *) NULL)
1150 return((Image *) NULL);
1151 /*
1152 Flip image.
1153 */
1154 status=MagickTrue;
1155 progress=0;
cristy74ea2cd2010-12-08 02:54:25 +00001156 page=image->page;
cristydb070952012-04-20 14:33:00 +00001157 image_view=AcquireVirtualCacheView(image,exception);
1158 flip_view=AcquireAuthenticCacheView(flip_image,exception);
cristy5db1f092010-06-07 13:07:26 +00001159#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00001160 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001161 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001162#endif
cristybb503372010-05-27 20:51:26 +00001163 for (y=0; y < (ssize_t) flip_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001164 {
cristy4c08aed2011-07-01 19:47:50 +00001165 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001166 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001167
cristy4c08aed2011-07-01 19:47:50 +00001168 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001169 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001170
cristy4c08aed2011-07-01 19:47:50 +00001171 register ssize_t
1172 x;
1173
cristy3ed852e2009-09-05 21:47:34 +00001174 if (status == MagickFalse)
1175 continue;
1176 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy5db1f092010-06-07 13:07:26 +00001177 q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
1178 1),flip_image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001179 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001180 {
1181 status=MagickFalse;
1182 continue;
1183 }
cristy4c08aed2011-07-01 19:47:50 +00001184 for (x=0; x < (ssize_t) flip_image->columns; x++)
1185 {
cristy010d7d12011-08-31 01:02:48 +00001186 register ssize_t
1187 i;
1188
cristy10a6c612012-01-29 21:41:05 +00001189 if (GetPixelMask(image,p) != 0)
1190 {
1191 p+=GetPixelChannels(image);
1192 q+=GetPixelChannels(flip_image);
1193 continue;
1194 }
cristy010d7d12011-08-31 01:02:48 +00001195 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1196 {
1197 PixelChannel
1198 channel;
1199
1200 PixelTrait
1201 flip_traits,
1202 traits;
1203
cristycf1296e2012-08-26 23:40:49 +00001204 channel=GetPixelChannelChannel(image,i);
1205 traits=GetPixelChannelTraits(image,channel);
1206 flip_traits=GetPixelChannelTraits(flip_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001207 if ((traits == UndefinedPixelTrait) ||
1208 (flip_traits == UndefinedPixelTrait))
1209 continue;
cristy0beccfa2011-09-25 20:47:53 +00001210 SetPixelChannel(flip_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001211 }
cristyed231572011-07-14 02:18:59 +00001212 p+=GetPixelChannels(image);
1213 q+=GetPixelChannels(flip_image);
cristy4c08aed2011-07-01 19:47:50 +00001214 }
cristy3ed852e2009-09-05 21:47:34 +00001215 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
1216 status=MagickFalse;
1217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1218 {
1219 MagickBooleanType
1220 proceed;
1221
cristy2224dcd2010-11-15 00:49:30 +00001222#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00001223 #pragma omp critical (MagickCore_FlipImage)
cristy3ed852e2009-09-05 21:47:34 +00001224#endif
1225 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
1226 if (proceed == MagickFalse)
1227 status=MagickFalse;
1228 }
1229 }
1230 flip_view=DestroyCacheView(flip_view);
1231 image_view=DestroyCacheView(image_view);
1232 flip_image->type=image->type;
anthony37a1b912010-12-10 12:45:59 +00001233 if (page.height != 0)
1234 page.y=(ssize_t) (page.height-flip_image->rows-page.y);
cristy74ea2cd2010-12-08 02:54:25 +00001235 flip_image->page=page;
cristy3ed852e2009-09-05 21:47:34 +00001236 if (status == MagickFalse)
1237 flip_image=DestroyImage(flip_image);
1238 return(flip_image);
1239}
1240
1241/*
1242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1243% %
1244% %
1245% %
1246% F l o p I m a g e %
1247% %
1248% %
1249% %
1250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1251%
1252% FlopImage() creates a horizontal mirror image by reflecting the pixels
1253% around the central y-axis.
1254%
1255% The format of the FlopImage method is:
1256%
1257% Image *FlopImage(const Image *image,ExceptionInfo *exception)
1258%
1259% A description of each parameter follows:
1260%
1261% o image: the image.
1262%
1263% o exception: return any errors or warnings in this structure.
1264%
1265*/
1266MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
1267{
1268#define FlopImageTag "Flop/Image"
1269
cristyc4c8d132010-01-07 01:58:38 +00001270 CacheView
1271 *flop_view,
1272 *image_view;
1273
cristy3ed852e2009-09-05 21:47:34 +00001274 Image
1275 *flop_image;
1276
cristy3ed852e2009-09-05 21:47:34 +00001277 MagickBooleanType
1278 status;
1279
cristybb503372010-05-27 20:51:26 +00001280 MagickOffsetType
1281 progress;
1282
cristy74ea2cd2010-12-08 02:54:25 +00001283 RectangleInfo
1284 page;
1285
cristybb503372010-05-27 20:51:26 +00001286 ssize_t
1287 y;
1288
cristy3ed852e2009-09-05 21:47:34 +00001289 assert(image != (const Image *) NULL);
1290 assert(image->signature == MagickSignature);
1291 if (image->debug != MagickFalse)
1292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1293 assert(exception != (ExceptionInfo *) NULL);
1294 assert(exception->signature == MagickSignature);
1295 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1296 if (flop_image == (Image *) NULL)
1297 return((Image *) NULL);
1298 /*
1299 Flop each row.
1300 */
1301 status=MagickTrue;
1302 progress=0;
cristy74ea2cd2010-12-08 02:54:25 +00001303 page=image->page;
cristydb070952012-04-20 14:33:00 +00001304 image_view=AcquireVirtualCacheView(image,exception);
1305 flop_view=AcquireAuthenticCacheView(flop_image,exception);
cristy5db1f092010-06-07 13:07:26 +00001306#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00001307 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001308 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001309#endif
cristybb503372010-05-27 20:51:26 +00001310 for (y=0; y < (ssize_t) flop_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001311 {
cristy4c08aed2011-07-01 19:47:50 +00001312 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001313 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001314
cristybb503372010-05-27 20:51:26 +00001315 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001316 x;
1317
cristy4c08aed2011-07-01 19:47:50 +00001318 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001319 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001320
1321 if (status == MagickFalse)
1322 continue;
1323 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1324 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1325 exception);
cristy4c08aed2011-07-01 19:47:50 +00001326 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001327 {
1328 status=MagickFalse;
1329 continue;
1330 }
cristyed231572011-07-14 02:18:59 +00001331 q+=GetPixelChannels(flop_image)*flop_image->columns;
cristybb503372010-05-27 20:51:26 +00001332 for (x=0; x < (ssize_t) flop_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001333 {
cristy010d7d12011-08-31 01:02:48 +00001334 register ssize_t
1335 i;
1336
cristyed231572011-07-14 02:18:59 +00001337 q-=GetPixelChannels(flop_image);
cristy10a6c612012-01-29 21:41:05 +00001338 if (GetPixelMask(image,p) != 0)
1339 {
1340 p+=GetPixelChannels(image);
1341 continue;
1342 }
cristy010d7d12011-08-31 01:02:48 +00001343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1344 {
1345 PixelChannel
1346 channel;
1347
1348 PixelTrait
1349 flop_traits,
1350 traits;
1351
cristycf1296e2012-08-26 23:40:49 +00001352 channel=GetPixelChannelChannel(image,i);
1353 traits=GetPixelChannelTraits(image,channel);
1354 flop_traits=GetPixelChannelTraits(flop_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001355 if ((traits == UndefinedPixelTrait) ||
1356 (flop_traits == UndefinedPixelTrait))
1357 continue;
cristy0beccfa2011-09-25 20:47:53 +00001358 SetPixelChannel(flop_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001359 }
cristyed231572011-07-14 02:18:59 +00001360 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001361 }
1362 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1363 status=MagickFalse;
1364 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1365 {
1366 MagickBooleanType
1367 proceed;
1368
cristyb5d5f722009-11-04 03:03:49 +00001369#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00001370 #pragma omp critical (MagickCore_FlopImage)
cristy3ed852e2009-09-05 21:47:34 +00001371#endif
1372 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1373 if (proceed == MagickFalse)
1374 status=MagickFalse;
1375 }
1376 }
1377 flop_view=DestroyCacheView(flop_view);
1378 image_view=DestroyCacheView(image_view);
1379 flop_image->type=image->type;
anthony37a1b912010-12-10 12:45:59 +00001380 if (page.width != 0)
1381 page.x=(ssize_t) (page.width-flop_image->columns-page.x);
cristy74ea2cd2010-12-08 02:54:25 +00001382 flop_image->page=page;
cristy3ed852e2009-09-05 21:47:34 +00001383 if (status == MagickFalse)
1384 flop_image=DestroyImage(flop_image);
1385 return(flop_image);
1386}
1387
1388/*
1389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390% %
1391% %
1392% %
1393% R o l l I m a g e %
1394% %
1395% %
1396% %
1397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398%
1399% RollImage() offsets an image as defined by x_offset and y_offset.
1400%
1401% The format of the RollImage method is:
1402%
cristybb503372010-05-27 20:51:26 +00001403% Image *RollImage(const Image *image,const ssize_t x_offset,
1404% const ssize_t y_offset,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001405%
1406% A description of each parameter follows:
1407%
1408% o image: the image.
1409%
1410% o x_offset: the number of columns to roll in the horizontal direction.
1411%
1412% o y_offset: the number of rows to roll in the vertical direction.
1413%
1414% o exception: return any errors or warnings in this structure.
1415%
1416*/
1417
1418static inline MagickBooleanType CopyImageRegion(Image *destination,
cristybb503372010-05-27 20:51:26 +00001419 const Image *source,const size_t columns,const size_t rows,
1420 const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
cristy3ed852e2009-09-05 21:47:34 +00001421 ExceptionInfo *exception)
1422{
cristyc4c8d132010-01-07 01:58:38 +00001423 CacheView
1424 *source_view,
1425 *destination_view;
1426
cristy3ed852e2009-09-05 21:47:34 +00001427 MagickBooleanType
1428 status;
1429
cristy9d314ff2011-03-09 01:30:28 +00001430 ssize_t
1431 y;
1432
cristy3ed852e2009-09-05 21:47:34 +00001433 status=MagickTrue;
cristydb070952012-04-20 14:33:00 +00001434 source_view=AcquireVirtualCacheView(source,exception);
1435 destination_view=AcquireAuthenticCacheView(destination,exception);
cristyb5d5f722009-11-04 03:03:49 +00001436#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +00001437 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001438 dynamic_number_threads(source,columns,rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001439#endif
cristybb503372010-05-27 20:51:26 +00001440 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001441 {
1442 MagickBooleanType
1443 sync;
1444
cristy4c08aed2011-07-01 19:47:50 +00001445 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001446 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001447
cristy4c08aed2011-07-01 19:47:50 +00001448 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001449 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001450
cristy4c08aed2011-07-01 19:47:50 +00001451 register ssize_t
1452 x;
1453
cristy3ed852e2009-09-05 21:47:34 +00001454 /*
1455 Transfer scanline.
1456 */
1457 if (status == MagickFalse)
1458 continue;
1459 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1460 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001461 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001462 {
1463 status=MagickFalse;
1464 continue;
1465 }
cristy4c08aed2011-07-01 19:47:50 +00001466 for (x=0; x < (ssize_t) columns; x++)
1467 {
cristy010d7d12011-08-31 01:02:48 +00001468 register ssize_t
1469 i;
1470
cristy10a6c612012-01-29 21:41:05 +00001471 if (GetPixelMask(source,p) != 0)
1472 {
1473 p+=GetPixelChannels(source);
1474 q+=GetPixelChannels(destination);
1475 continue;
1476 }
cristy010d7d12011-08-31 01:02:48 +00001477 for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
1478 {
1479 PixelChannel
1480 channel;
1481
1482 PixelTrait
1483 destination_traits,
1484 source_traits;
1485
cristycf1296e2012-08-26 23:40:49 +00001486 channel=GetPixelChannelChannel(source,i);
1487 source_traits=GetPixelChannelTraits(source,channel);
1488 destination_traits=GetPixelChannelTraits(destination,channel);
cristy010d7d12011-08-31 01:02:48 +00001489 if ((source_traits == UndefinedPixelTrait) ||
1490 (destination_traits == UndefinedPixelTrait))
1491 continue;
cristy0beccfa2011-09-25 20:47:53 +00001492 SetPixelChannel(destination,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001493 }
cristyed231572011-07-14 02:18:59 +00001494 p+=GetPixelChannels(source);
1495 q+=GetPixelChannels(destination);
cristy4c08aed2011-07-01 19:47:50 +00001496 }
cristy3ed852e2009-09-05 21:47:34 +00001497 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1498 if (sync == MagickFalse)
1499 status=MagickFalse;
1500 }
1501 destination_view=DestroyCacheView(destination_view);
1502 source_view=DestroyCacheView(source_view);
1503 return(status);
1504}
1505
cristybb503372010-05-27 20:51:26 +00001506MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
1507 const ssize_t y_offset,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001508{
1509#define RollImageTag "Roll/Image"
1510
1511 Image
1512 *roll_image;
1513
1514 MagickStatusType
1515 status;
1516
1517 RectangleInfo
1518 offset;
1519
1520 /*
1521 Initialize roll image attributes.
1522 */
1523 assert(image != (const Image *) NULL);
1524 assert(image->signature == MagickSignature);
1525 if (image->debug != MagickFalse)
1526 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1527 assert(exception != (ExceptionInfo *) NULL);
1528 assert(exception->signature == MagickSignature);
1529 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1530 if (roll_image == (Image *) NULL)
1531 return((Image *) NULL);
1532 offset.x=x_offset;
1533 offset.y=y_offset;
1534 while (offset.x < 0)
cristyeaedf062010-05-29 22:36:02 +00001535 offset.x+=(ssize_t) image->columns;
cristybb503372010-05-27 20:51:26 +00001536 while (offset.x >= (ssize_t) image->columns)
cristyeaedf062010-05-29 22:36:02 +00001537 offset.x-=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +00001538 while (offset.y < 0)
cristyeaedf062010-05-29 22:36:02 +00001539 offset.y+=(ssize_t) image->rows;
cristybb503372010-05-27 20:51:26 +00001540 while (offset.y >= (ssize_t) image->rows)
cristyeaedf062010-05-29 22:36:02 +00001541 offset.y-=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001542 /*
1543 Roll image.
1544 */
cristybb503372010-05-27 20:51:26 +00001545 status=CopyImageRegion(roll_image,image,(size_t) offset.x,
1546 (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
cristy3ed852e2009-09-05 21:47:34 +00001547 offset.y,0,0,exception);
1548 (void) SetImageProgress(image,RollImageTag,0,3);
1549 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
cristybb503372010-05-27 20:51:26 +00001550 (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
cristy3ed852e2009-09-05 21:47:34 +00001551 exception);
1552 (void) SetImageProgress(image,RollImageTag,1,3);
cristybb503372010-05-27 20:51:26 +00001553 status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
1554 offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
cristy3ed852e2009-09-05 21:47:34 +00001555 (void) SetImageProgress(image,RollImageTag,2,3);
1556 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1557 offset.y,0,0,offset.x,offset.y,exception);
1558 (void) SetImageProgress(image,RollImageTag,3,3);
1559 roll_image->type=image->type;
1560 if (status == MagickFalse)
1561 roll_image=DestroyImage(roll_image);
1562 return(roll_image);
1563}
1564
1565/*
1566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567% %
1568% %
1569% %
1570% S h a v e I m a g e %
1571% %
1572% %
1573% %
1574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575%
1576% ShaveImage() shaves pixels from the image edges. It allocates the memory
1577% necessary for the new Image structure and returns a pointer to the new
1578% image.
1579%
1580% The format of the ShaveImage method is:
1581%
1582% Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1583% ExceptionInfo *exception)
1584%
1585% A description of each parameter follows:
1586%
1587% o shave_image: Method ShaveImage returns a pointer to the shaved
1588% image. A null image is returned if there is a memory shortage or
1589% if the image width or height is zero.
1590%
1591% o image: the image.
1592%
1593% o shave_info: Specifies a pointer to a RectangleInfo which defines the
1594% region of the image to crop.
1595%
1596% o exception: return any errors or warnings in this structure.
1597%
1598*/
1599MagickExport Image *ShaveImage(const Image *image,
1600 const RectangleInfo *shave_info,ExceptionInfo *exception)
1601{
1602 Image
1603 *shave_image;
1604
1605 RectangleInfo
1606 geometry;
1607
1608 assert(image != (const Image *) NULL);
1609 assert(image->signature == MagickSignature);
1610 if (image->debug != MagickFalse)
1611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1612 if (((2*shave_info->width) >= image->columns) ||
1613 ((2*shave_info->height) >= image->rows))
1614 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1615 SetGeometry(image,&geometry);
1616 geometry.width-=2*shave_info->width;
1617 geometry.height-=2*shave_info->height;
cristybb503372010-05-27 20:51:26 +00001618 geometry.x=(ssize_t) shave_info->width+image->page.x;
1619 geometry.y=(ssize_t) shave_info->height+image->page.y;
cristy3ed852e2009-09-05 21:47:34 +00001620 shave_image=CropImage(image,&geometry,exception);
1621 if (shave_image == (Image *) NULL)
1622 return((Image *) NULL);
1623 shave_image->page.width-=2*shave_info->width;
1624 shave_image->page.height-=2*shave_info->height;
cristyeaedf062010-05-29 22:36:02 +00001625 shave_image->page.x-=(ssize_t) shave_info->width;
1626 shave_image->page.y-=(ssize_t) shave_info->height;
cristy3ed852e2009-09-05 21:47:34 +00001627 return(shave_image);
1628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635% S p l i c e I m a g e %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% SpliceImage() splices a solid color into the image as defined by the
1642% geometry.
1643%
1644% The format of the SpliceImage method is:
1645%
1646% Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1647% ExceptionInfo *exception)
1648%
1649% A description of each parameter follows:
1650%
1651% o image: the image.
1652%
1653% o geometry: Define the region of the image to splice with members
1654% x, y, width, and height.
1655%
1656% o exception: return any errors or warnings in this structure.
1657%
1658*/
1659MagickExport Image *SpliceImage(const Image *image,
1660 const RectangleInfo *geometry,ExceptionInfo *exception)
1661{
1662#define SpliceImageTag "Splice/Image"
1663
cristyc4c8d132010-01-07 01:58:38 +00001664 CacheView
1665 *image_view,
1666 *splice_view;
1667
cristy3ed852e2009-09-05 21:47:34 +00001668 Image
1669 *splice_image;
1670
cristy3ed852e2009-09-05 21:47:34 +00001671 MagickBooleanType
cristy3ed852e2009-09-05 21:47:34 +00001672 status;
1673
cristybb503372010-05-27 20:51:26 +00001674 MagickOffsetType
1675 progress;
1676
cristy3ed852e2009-09-05 21:47:34 +00001677 RectangleInfo
1678 splice_geometry;
1679
cristybb503372010-05-27 20:51:26 +00001680 ssize_t
1681 y;
1682
cristy3ed852e2009-09-05 21:47:34 +00001683 /*
1684 Allocate splice image.
1685 */
1686 assert(image != (const Image *) NULL);
1687 assert(image->signature == MagickSignature);
1688 if (image->debug != MagickFalse)
1689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1690 assert(geometry != (const RectangleInfo *) NULL);
1691 assert(exception != (ExceptionInfo *) NULL);
1692 assert(exception->signature == MagickSignature);
1693 splice_geometry=(*geometry);
1694 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1695 image->rows+splice_geometry.height,MagickTrue,exception);
1696 if (splice_image == (Image *) NULL)
1697 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00001698 if (SetImageStorageClass(splice_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001699 {
cristy3ed852e2009-09-05 21:47:34 +00001700 splice_image=DestroyImage(splice_image);
1701 return((Image *) NULL);
1702 }
cristyea1a8aa2011-10-20 13:24:06 +00001703 (void) SetImageBackgroundColor(splice_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001704 /*
1705 Respect image geometry.
1706 */
1707 switch (image->gravity)
1708 {
1709 default:
1710 case UndefinedGravity:
1711 case NorthWestGravity:
1712 break;
1713 case NorthGravity:
1714 {
cristyeaedf062010-05-29 22:36:02 +00001715 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
cristy3ed852e2009-09-05 21:47:34 +00001716 break;
1717 }
1718 case NorthEastGravity:
1719 {
cristyeaedf062010-05-29 22:36:02 +00001720 splice_geometry.x+=(ssize_t) splice_geometry.width;
cristy3ed852e2009-09-05 21:47:34 +00001721 break;
1722 }
1723 case WestGravity:
1724 {
cristyeaedf062010-05-29 22:36:02 +00001725 splice_geometry.y+=(ssize_t) splice_geometry.width/2;
cristy3ed852e2009-09-05 21:47:34 +00001726 break;
1727 }
cristy3ed852e2009-09-05 21:47:34 +00001728 case CenterGravity:
1729 {
cristyeaedf062010-05-29 22:36:02 +00001730 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1731 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
cristy3ed852e2009-09-05 21:47:34 +00001732 break;
1733 }
1734 case EastGravity:
1735 {
cristyeaedf062010-05-29 22:36:02 +00001736 splice_geometry.x+=(ssize_t) splice_geometry.width;
1737 splice_geometry.y+=(ssize_t) splice_geometry.height/2;
cristy3ed852e2009-09-05 21:47:34 +00001738 break;
1739 }
1740 case SouthWestGravity:
1741 {
cristyeaedf062010-05-29 22:36:02 +00001742 splice_geometry.y+=(ssize_t) splice_geometry.height;
cristy3ed852e2009-09-05 21:47:34 +00001743 break;
1744 }
1745 case SouthGravity:
1746 {
cristyeaedf062010-05-29 22:36:02 +00001747 splice_geometry.x+=(ssize_t) splice_geometry.width/2;
1748 splice_geometry.y+=(ssize_t) splice_geometry.height;
cristy3ed852e2009-09-05 21:47:34 +00001749 break;
1750 }
1751 case SouthEastGravity:
1752 {
cristyeaedf062010-05-29 22:36:02 +00001753 splice_geometry.x+=(ssize_t) splice_geometry.width;
1754 splice_geometry.y+=(ssize_t) splice_geometry.height;
cristy3ed852e2009-09-05 21:47:34 +00001755 break;
1756 }
1757 }
1758 /*
1759 Splice image.
1760 */
1761 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00001762 progress=0;
cristydb070952012-04-20 14:33:00 +00001763 image_view=AcquireVirtualCacheView(image,exception);
1764 splice_view=AcquireAuthenticCacheView(splice_image,exception);
cristyb5d5f722009-11-04 03:03:49 +00001765#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001766 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001767 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001768#endif
cristybb503372010-05-27 20:51:26 +00001769 for (y=0; y < (ssize_t) splice_geometry.y; y++)
cristy3ed852e2009-09-05 21:47:34 +00001770 {
cristy4c08aed2011-07-01 19:47:50 +00001771 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001772 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001773
cristybb503372010-05-27 20:51:26 +00001774 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001775 x;
1776
cristy4c08aed2011-07-01 19:47:50 +00001777 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001778 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001779
1780 if (status == MagickFalse)
1781 continue;
1782 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1783 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1784 exception);
cristy4c08aed2011-07-01 19:47:50 +00001785 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001786 {
1787 status=MagickFalse;
1788 continue;
1789 }
cristy3ed852e2009-09-05 21:47:34 +00001790 for (x=0; x < splice_geometry.x; x++)
1791 {
cristy010d7d12011-08-31 01:02:48 +00001792 register ssize_t
1793 i;
1794
cristy10a6c612012-01-29 21:41:05 +00001795 if (GetPixelMask(image,p) != 0)
1796 {
1797 p+=GetPixelChannels(image);
1798 q+=GetPixelChannels(splice_image);
1799 continue;
1800 }
cristy010d7d12011-08-31 01:02:48 +00001801 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1802 {
1803 PixelChannel
1804 channel;
1805
1806 PixelTrait
1807 splice_traits,
1808 traits;
1809
cristycf1296e2012-08-26 23:40:49 +00001810 channel=GetPixelChannelChannel(image,i);
1811 traits=GetPixelChannelTraits(image,channel);
1812 splice_traits=GetPixelChannelTraits(splice_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001813 if ((traits == UndefinedPixelTrait) ||
1814 (splice_traits == UndefinedPixelTrait))
1815 continue;
cristy0beccfa2011-09-25 20:47:53 +00001816 SetPixelChannel(splice_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001817 }
cristyed231572011-07-14 02:18:59 +00001818 p+=GetPixelChannels(image);
1819 q+=GetPixelChannels(splice_image);
cristy3ed852e2009-09-05 21:47:34 +00001820 }
cristybb503372010-05-27 20:51:26 +00001821 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
cristyed231572011-07-14 02:18:59 +00001822 q+=GetPixelChannels(splice_image);
cristybb503372010-05-27 20:51:26 +00001823 for ( ; x < (ssize_t) splice_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001824 {
cristy010d7d12011-08-31 01:02:48 +00001825 register ssize_t
1826 i;
1827
cristy10a6c612012-01-29 21:41:05 +00001828 if (GetPixelMask(image,p) != 0)
1829 {
1830 p+=GetPixelChannels(image);
1831 q+=GetPixelChannels(splice_image);
1832 continue;
1833 }
cristy010d7d12011-08-31 01:02:48 +00001834 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1835 {
1836 PixelChannel
1837 channel;
1838
1839 PixelTrait
1840 traits,
1841 splice_traits;
1842
cristycf1296e2012-08-26 23:40:49 +00001843 channel=GetPixelChannelChannel(image,i);
1844 traits=GetPixelChannelTraits(image,channel);
1845 splice_traits=GetPixelChannelTraits(splice_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001846 if ((traits == UndefinedPixelTrait) ||
1847 (splice_traits == UndefinedPixelTrait))
1848 continue;
cristy0beccfa2011-09-25 20:47:53 +00001849 SetPixelChannel(splice_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001850 }
cristyed231572011-07-14 02:18:59 +00001851 p+=GetPixelChannels(image);
1852 q+=GetPixelChannels(splice_image);
cristy3ed852e2009-09-05 21:47:34 +00001853 }
1854 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1855 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001856 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1857 {
1858 MagickBooleanType
1859 proceed;
1860
cristyb5d5f722009-11-04 03:03:49 +00001861#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00001862 #pragma omp critical (MagickCore_TransposeImage)
cristy3ed852e2009-09-05 21:47:34 +00001863#endif
1864 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1865 splice_image->rows);
1866 if (proceed == MagickFalse)
1867 status=MagickFalse;
1868 }
1869 }
cristyb5d5f722009-11-04 03:03:49 +00001870#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001871 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001872 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001873#endif
cristybb503372010-05-27 20:51:26 +00001874 for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
1875 y < (ssize_t) splice_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001876 {
cristy4c08aed2011-07-01 19:47:50 +00001877 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001878 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001879
cristybb503372010-05-27 20:51:26 +00001880 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001881 x;
1882
cristy4c08aed2011-07-01 19:47:50 +00001883 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001884 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001885
1886 if (status == MagickFalse)
1887 continue;
cristyeaedf062010-05-29 22:36:02 +00001888 p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
cristy3ed852e2009-09-05 21:47:34 +00001889 image->columns,1,exception);
cristy13d07042010-11-21 20:56:18 +00001890 if ((y < 0) || (y >= (ssize_t) splice_image->rows))
cristy2224dcd2010-11-15 00:49:30 +00001891 continue;
cristy3ed852e2009-09-05 21:47:34 +00001892 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1893 exception);
cristy4c08aed2011-07-01 19:47:50 +00001894 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001895 {
1896 status=MagickFalse;
1897 continue;
1898 }
cristy3ed852e2009-09-05 21:47:34 +00001899 for (x=0; x < splice_geometry.x; x++)
1900 {
cristy010d7d12011-08-31 01:02:48 +00001901 register ssize_t
1902 i;
1903
cristy10a6c612012-01-29 21:41:05 +00001904 if (GetPixelMask(image,q) != 0)
1905 {
1906 p+=GetPixelChannels(image);
1907 q+=GetPixelChannels(splice_image);
1908 continue;
1909 }
cristy010d7d12011-08-31 01:02:48 +00001910 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1911 {
1912 PixelChannel
1913 channel;
1914
1915 PixelTrait
1916 traits,
1917 splice_traits;
1918
cristycf1296e2012-08-26 23:40:49 +00001919 channel=GetPixelChannelChannel(image,i);
1920 traits=GetPixelChannelTraits(image,channel);
1921 splice_traits=GetPixelChannelTraits(splice_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001922 if ((traits == UndefinedPixelTrait) ||
1923 (splice_traits == UndefinedPixelTrait))
1924 continue;
cristy0beccfa2011-09-25 20:47:53 +00001925 SetPixelChannel(splice_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001926 }
cristyed231572011-07-14 02:18:59 +00001927 p+=GetPixelChannels(image);
1928 q+=GetPixelChannels(splice_image);
cristy3ed852e2009-09-05 21:47:34 +00001929 }
cristybb503372010-05-27 20:51:26 +00001930 for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
cristyed231572011-07-14 02:18:59 +00001931 q+=GetPixelChannels(splice_image);
cristybb503372010-05-27 20:51:26 +00001932 for ( ; x < (ssize_t) splice_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001933 {
cristy010d7d12011-08-31 01:02:48 +00001934 register ssize_t
1935 i;
1936
cristy10a6c612012-01-29 21:41:05 +00001937 if (GetPixelMask(image,q) != 0)
1938 {
1939 p+=GetPixelChannels(image);
1940 q+=GetPixelChannels(splice_image);
1941 continue;
1942 }
cristy010d7d12011-08-31 01:02:48 +00001943 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1944 {
1945 PixelChannel
1946 channel;
1947
1948 PixelTrait
1949 traits,
1950 splice_traits;
1951
cristycf1296e2012-08-26 23:40:49 +00001952 channel=GetPixelChannelChannel(image,i);
1953 traits=GetPixelChannelTraits(image,channel);
1954 splice_traits=GetPixelChannelTraits(splice_image,channel);
cristy010d7d12011-08-31 01:02:48 +00001955 if ((traits == UndefinedPixelTrait) ||
1956 (splice_traits == UndefinedPixelTrait))
1957 continue;
cristy0beccfa2011-09-25 20:47:53 +00001958 SetPixelChannel(splice_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00001959 }
cristyed231572011-07-14 02:18:59 +00001960 p+=GetPixelChannels(image);
1961 q+=GetPixelChannels(splice_image);
cristy3ed852e2009-09-05 21:47:34 +00001962 }
1963 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1964 status=MagickFalse;
1965 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1966 {
1967 MagickBooleanType
1968 proceed;
1969
cristyb5d5f722009-11-04 03:03:49 +00001970#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00001971 #pragma omp critical (MagickCore_TransposeImage)
cristy3ed852e2009-09-05 21:47:34 +00001972#endif
1973 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1974 splice_image->rows);
1975 if (proceed == MagickFalse)
1976 status=MagickFalse;
1977 }
1978 }
1979 splice_view=DestroyCacheView(splice_view);
1980 image_view=DestroyCacheView(image_view);
1981 if (status == MagickFalse)
1982 splice_image=DestroyImage(splice_image);
1983 return(splice_image);
1984}
1985
1986/*
1987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988% %
1989% %
1990% %
1991% T r a n s f o r m I m a g e %
1992% %
1993% %
1994% %
1995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1996%
1997% TransformImage() is a convenience method that behaves like ResizeImage() or
1998% CropImage() but accepts scaling and/or cropping information as a region
1999% geometry specification. If the operation fails, the original image handle
anthony9f4f0342011-03-28 11:47:22 +00002000% is left as is.
2001%
2002% This should only be used for single images.
cristy3ed852e2009-09-05 21:47:34 +00002003%
cristy010d7d12011-08-31 01:02:48 +00002004% This function destroys what it assumes to be a single image list.
2005% If the input image is part of a larger list, all other images in that list
2006% will be simply 'lost', not destroyed.
2007%
2008% Also if the crop generates a list of images only the first image is resized.
2009% And finally if the crop succeeds and the resize failed, you will get a
2010% cropped image, as well as a 'false' or 'failed' report.
2011%
2012% This function and should probably be depreciated in favor of direct calls
2013% to CropImageToTiles() or ResizeImage(), as appropriate.
2014%
cristy3ed852e2009-09-05 21:47:34 +00002015% The format of the TransformImage method is:
2016%
2017% MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
cristye941a752011-10-15 01:52:48 +00002018% const char *image_geometry,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002019%
2020% A description of each parameter follows:
2021%
2022% o image: the image The transformed image is returned as this parameter.
2023%
2024% o crop_geometry: A crop geometry string. This geometry defines a
2025% subregion of the image to crop.
2026%
2027% o image_geometry: An image geometry string. This geometry defines the
2028% final size of the image.
2029%
cristye941a752011-10-15 01:52:48 +00002030% o exception: return any errors or warnings in this structure.
2031%
cristy3ed852e2009-09-05 21:47:34 +00002032*/
2033MagickExport MagickBooleanType TransformImage(Image **image,
cristye941a752011-10-15 01:52:48 +00002034 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002035{
2036 Image
2037 *resize_image,
2038 *transform_image;
2039
2040 MagickStatusType
2041 flags;
2042
2043 RectangleInfo
2044 geometry;
2045
2046 assert(image != (Image **) NULL);
2047 assert((*image)->signature == MagickSignature);
2048 if ((*image)->debug != MagickFalse)
2049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2050 transform_image=(*image);
2051 if (crop_geometry != (const char *) NULL)
2052 {
2053 Image
2054 *crop_image;
2055
cristy3ed852e2009-09-05 21:47:34 +00002056 /*
2057 Crop image to a user specified size.
2058 */
cristye941a752011-10-15 01:52:48 +00002059 crop_image=CropImageToTiles(*image,crop_geometry,exception);
cristy3ed852e2009-09-05 21:47:34 +00002060 if (crop_image == (Image *) NULL)
cristye941a752011-10-15 01:52:48 +00002061 transform_image=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 else
2063 {
2064 transform_image=DestroyImage(transform_image);
2065 transform_image=GetFirstImageInList(crop_image);
2066 }
2067 *image=transform_image;
2068 }
2069 if (image_geometry == (const char *) NULL)
2070 return(MagickTrue);
anthony9f4f0342011-03-28 11:47:22 +00002071
cristy3ed852e2009-09-05 21:47:34 +00002072 /*
2073 Scale image to a user specified size.
2074 */
cristye941a752011-10-15 01:52:48 +00002075 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,exception);
cristy288b0802011-03-28 13:05:34 +00002076 (void) flags;
cristy3ed852e2009-09-05 21:47:34 +00002077 if ((transform_image->columns == geometry.width) &&
2078 (transform_image->rows == geometry.height))
2079 return(MagickTrue);
cristy15b98cd2010-09-12 19:42:50 +00002080 resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
cristyaa2c16c2012-03-25 22:21:35 +00002081 transform_image->filter,exception);
cristy3ed852e2009-09-05 21:47:34 +00002082 if (resize_image == (Image *) NULL)
2083 return(MagickFalse);
2084 transform_image=DestroyImage(transform_image);
2085 transform_image=resize_image;
2086 *image=transform_image;
2087 return(MagickTrue);
2088}
2089
2090/*
2091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2092% %
2093% %
2094% %
2095% T r a n s f o r m I m a g e s %
2096% %
2097% %
anthonybdaa5b32010-12-10 13:06:46 +00002098% %
2099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00002100%
2101% TransformImages() calls TransformImage() on each image of a sequence.
2102%
2103% The format of the TransformImage method is:
2104%
2105% MagickBooleanType TransformImages(Image **image,
cristye941a752011-10-15 01:52:48 +00002106% const char *crop_geometry,const char *image_geometry,
2107% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002108%
2109% A description of each parameter follows:
2110%
2111% o image: the image The transformed image is returned as this parameter.
2112%
2113% o crop_geometry: A crop geometry string. This geometry defines a
2114% subregion of the image to crop.
2115%
2116% o image_geometry: An image geometry string. This geometry defines the
2117% final size of the image.
2118%
cristye941a752011-10-15 01:52:48 +00002119% o exception: return any errors or warnings in this structure.
2120%
cristy3ed852e2009-09-05 21:47:34 +00002121*/
2122MagickExport MagickBooleanType TransformImages(Image **images,
cristye941a752011-10-15 01:52:48 +00002123 const char *crop_geometry,const char *image_geometry,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 Image
2126 *image,
2127 **image_list,
2128 *transform_images;
2129
2130 MagickStatusType
2131 status;
2132
cristybb503372010-05-27 20:51:26 +00002133 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002134 i;
2135
2136 assert(images != (Image **) NULL);
2137 assert((*images)->signature == MagickSignature);
2138 if ((*images)->debug != MagickFalse)
2139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2140 (*images)->filename);
cristye941a752011-10-15 01:52:48 +00002141 image_list=ImageListToArray(*images,exception);
cristy3ed852e2009-09-05 21:47:34 +00002142 if (image_list == (Image **) NULL)
2143 return(MagickFalse);
2144 status=MagickTrue;
2145 transform_images=NewImageList();
2146 for (i=0; image_list[i] != (Image *) NULL; i++)
2147 {
2148 image=image_list[i];
cristye941a752011-10-15 01:52:48 +00002149 status|=TransformImage(&image,crop_geometry,image_geometry,exception);
cristy3ed852e2009-09-05 21:47:34 +00002150 AppendImageToList(&transform_images,image);
2151 }
2152 *images=transform_images;
2153 image_list=(Image **) RelinquishMagickMemory(image_list);
2154 return(status != 0 ? MagickTrue : MagickFalse);
2155}
2156
2157/*
2158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159% %
2160% %
2161% %
2162% T r a n s p o s e I m a g e %
2163% %
2164% %
2165% %
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167%
2168% TransposeImage() creates a horizontal mirror image by reflecting the pixels
2169% around the central y-axis while rotating them by 90 degrees.
2170%
2171% The format of the TransposeImage method is:
2172%
2173% Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2174%
2175% A description of each parameter follows:
2176%
2177% o image: the image.
2178%
2179% o exception: return any errors or warnings in this structure.
2180%
2181*/
2182MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
2183{
2184#define TransposeImageTag "Transpose/Image"
2185
cristyc4c8d132010-01-07 01:58:38 +00002186 CacheView
2187 *image_view,
2188 *transpose_view;
2189
cristy3ed852e2009-09-05 21:47:34 +00002190 Image
2191 *transpose_image;
2192
cristy3ed852e2009-09-05 21:47:34 +00002193 MagickBooleanType
2194 status;
2195
cristybb503372010-05-27 20:51:26 +00002196 MagickOffsetType
2197 progress;
2198
cristy3ed852e2009-09-05 21:47:34 +00002199 RectangleInfo
2200 page;
2201
cristybb503372010-05-27 20:51:26 +00002202 ssize_t
2203 y;
2204
cristy3ed852e2009-09-05 21:47:34 +00002205 assert(image != (const Image *) NULL);
2206 assert(image->signature == MagickSignature);
2207 if (image->debug != MagickFalse)
2208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2209 assert(exception != (ExceptionInfo *) NULL);
2210 assert(exception->signature == MagickSignature);
2211 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2212 exception);
2213 if (transpose_image == (Image *) NULL)
2214 return((Image *) NULL);
2215 /*
2216 Transpose image.
2217 */
2218 status=MagickTrue;
2219 progress=0;
cristydb070952012-04-20 14:33:00 +00002220 image_view=AcquireVirtualCacheView(image,exception);
2221 transpose_view=AcquireAuthenticCacheView(transpose_image,exception);
cristyb5d5f722009-11-04 03:03:49 +00002222#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002223 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00002224 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00002225#endif
cristybb503372010-05-27 20:51:26 +00002226 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002227 {
cristy4c08aed2011-07-01 19:47:50 +00002228 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00002229 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002230
cristy4c08aed2011-07-01 19:47:50 +00002231 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002232 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002233
cristy4c08aed2011-07-01 19:47:50 +00002234 register ssize_t
2235 x;
2236
cristy3ed852e2009-09-05 21:47:34 +00002237 if (status == MagickFalse)
2238 continue;
cristybb503372010-05-27 20:51:26 +00002239 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
cristy3ed852e2009-09-05 21:47:34 +00002240 image->columns,1,exception);
cristy9af9b5d2010-08-15 17:04:28 +00002241 q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
2242 0,1,transpose_image->rows,exception);
cristy4c08aed2011-07-01 19:47:50 +00002243 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00002244 {
2245 status=MagickFalse;
2246 continue;
2247 }
cristy4c08aed2011-07-01 19:47:50 +00002248 for (x=0; x < (ssize_t) image->columns; x++)
2249 {
cristy010d7d12011-08-31 01:02:48 +00002250 register ssize_t
2251 i;
2252
cristy10a6c612012-01-29 21:41:05 +00002253 if (GetPixelMask(image,q) != 0)
2254 {
2255 p+=GetPixelChannels(image);
2256 q+=GetPixelChannels(transpose_image);
2257 continue;
2258 }
cristy010d7d12011-08-31 01:02:48 +00002259 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2260 {
2261 PixelChannel
2262 channel;
2263
2264 PixelTrait
2265 traits,
2266 transpose_traits;
2267
cristycf1296e2012-08-26 23:40:49 +00002268 channel=GetPixelChannelChannel(image,i);
2269 traits=GetPixelChannelTraits(image,channel);
2270 transpose_traits=GetPixelChannelTraits(transpose_image,channel);
cristy010d7d12011-08-31 01:02:48 +00002271 if ((traits == UndefinedPixelTrait) ||
2272 (transpose_traits == UndefinedPixelTrait))
2273 continue;
cristy0beccfa2011-09-25 20:47:53 +00002274 SetPixelChannel(transpose_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00002275 }
cristyed231572011-07-14 02:18:59 +00002276 p+=GetPixelChannels(image);
2277 q+=GetPixelChannels(transpose_image);
cristy4c08aed2011-07-01 19:47:50 +00002278 }
cristy3ed852e2009-09-05 21:47:34 +00002279 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
2280 status=MagickFalse;
2281 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2282 {
2283 MagickBooleanType
2284 proceed;
2285
cristyb5d5f722009-11-04 03:03:49 +00002286#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00002287 #pragma omp critical (MagickCore_TransposeImage)
cristy3ed852e2009-09-05 21:47:34 +00002288#endif
2289 proceed=SetImageProgress(image,TransposeImageTag,progress++,
2290 image->rows);
2291 if (proceed == MagickFalse)
2292 status=MagickFalse;
2293 }
2294 }
2295 transpose_view=DestroyCacheView(transpose_view);
2296 image_view=DestroyCacheView(image_view);
2297 transpose_image->type=image->type;
2298 page=transpose_image->page;
2299 Swap(page.width,page.height);
2300 Swap(page.x,page.y);
cristy3ed852e2009-09-05 21:47:34 +00002301 transpose_image->page=page;
2302 if (status == MagickFalse)
2303 transpose_image=DestroyImage(transpose_image);
2304 return(transpose_image);
2305}
2306
2307/*
2308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309% %
2310% %
2311% %
2312% T r a n s v e r s e I m a g e %
2313% %
2314% %
2315% %
2316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317%
2318% TransverseImage() creates a vertical mirror image by reflecting the pixels
2319% around the central x-axis while rotating them by 270 degrees.
2320%
2321% The format of the TransverseImage method is:
2322%
2323% Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2324%
2325% A description of each parameter follows:
2326%
2327% o image: the image.
2328%
2329% o exception: return any errors or warnings in this structure.
2330%
2331*/
2332MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
2333{
2334#define TransverseImageTag "Transverse/Image"
2335
cristyc4c8d132010-01-07 01:58:38 +00002336 CacheView
2337 *image_view,
2338 *transverse_view;
2339
cristy3ed852e2009-09-05 21:47:34 +00002340 Image
2341 *transverse_image;
2342
cristy3ed852e2009-09-05 21:47:34 +00002343 MagickBooleanType
2344 status;
2345
cristybb503372010-05-27 20:51:26 +00002346 MagickOffsetType
2347 progress;
2348
cristy3ed852e2009-09-05 21:47:34 +00002349 RectangleInfo
2350 page;
2351
cristybb503372010-05-27 20:51:26 +00002352 ssize_t
2353 y;
2354
cristy3ed852e2009-09-05 21:47:34 +00002355 assert(image != (const Image *) NULL);
2356 assert(image->signature == MagickSignature);
2357 if (image->debug != MagickFalse)
2358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2359 assert(exception != (ExceptionInfo *) NULL);
2360 assert(exception->signature == MagickSignature);
2361 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
2362 exception);
2363 if (transverse_image == (Image *) NULL)
2364 return((Image *) NULL);
2365 /*
2366 Transverse image.
2367 */
2368 status=MagickTrue;
2369 progress=0;
cristydb070952012-04-20 14:33:00 +00002370 image_view=AcquireVirtualCacheView(image,exception);
2371 transverse_view=AcquireAuthenticCacheView(transverse_image,exception);
cristyb5d5f722009-11-04 03:03:49 +00002372#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002373 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristy4ee2b0c2012-05-15 00:30:35 +00002374 dynamic_number_threads(image,image->columns,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00002375#endif
cristybb503372010-05-27 20:51:26 +00002376 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002377 {
2378 MagickBooleanType
2379 sync;
2380
cristy4c08aed2011-07-01 19:47:50 +00002381 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00002382 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002383
cristy4c08aed2011-07-01 19:47:50 +00002384 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002385 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002386
cristy010d7d12011-08-31 01:02:48 +00002387 register ssize_t
2388 x;
2389
cristy3ed852e2009-09-05 21:47:34 +00002390 if (status == MagickFalse)
2391 continue;
2392 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy010d7d12011-08-31 01:02:48 +00002393 q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-1),
2394 0,1,transverse_image->rows,exception);
cristy4c08aed2011-07-01 19:47:50 +00002395 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00002396 {
2397 status=MagickFalse;
2398 continue;
2399 }
cristyed231572011-07-14 02:18:59 +00002400 q+=GetPixelChannels(transverse_image)*image->columns;
cristybb503372010-05-27 20:51:26 +00002401 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002402 {
cristy010d7d12011-08-31 01:02:48 +00002403 register ssize_t
2404 i;
2405
cristyed231572011-07-14 02:18:59 +00002406 q-=GetPixelChannels(transverse_image);
cristy10a6c612012-01-29 21:41:05 +00002407 if (GetPixelMask(image,p) != 0)
2408 {
2409 p+=GetPixelChannels(image);
2410 continue;
2411 }
cristy010d7d12011-08-31 01:02:48 +00002412 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2413 {
2414 PixelChannel
2415 channel;
2416
2417 PixelTrait
2418 traits,
2419 transverse_traits;
2420
cristycf1296e2012-08-26 23:40:49 +00002421 channel=GetPixelChannelChannel(image,i);
2422 traits=GetPixelChannelTraits(image,channel);
2423 transverse_traits=GetPixelChannelTraits(transverse_image,channel);
cristy010d7d12011-08-31 01:02:48 +00002424 if ((traits == UndefinedPixelTrait) ||
2425 (transverse_traits == UndefinedPixelTrait))
2426 continue;
cristy0beccfa2011-09-25 20:47:53 +00002427 SetPixelChannel(transverse_image,channel,p[i],q);
cristy010d7d12011-08-31 01:02:48 +00002428 }
cristyed231572011-07-14 02:18:59 +00002429 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002430 }
cristy3ed852e2009-09-05 21:47:34 +00002431 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2432 if (sync == MagickFalse)
2433 status=MagickFalse;
2434 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2435 {
2436 MagickBooleanType
2437 proceed;
2438
cristyb5d5f722009-11-04 03:03:49 +00002439#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristya5ab7ad2012-01-21 23:49:58 +00002440 #pragma omp critical (MagickCore_TransverseImage)
cristy3ed852e2009-09-05 21:47:34 +00002441#endif
2442 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2443 image->rows);
2444 if (proceed == MagickFalse)
2445 status=MagickFalse;
2446 }
2447 }
2448 transverse_view=DestroyCacheView(transverse_view);
2449 image_view=DestroyCacheView(image_view);
2450 transverse_image->type=image->type;
2451 page=transverse_image->page;
2452 Swap(page.width,page.height);
2453 Swap(page.x,page.y);
anthonybdaa5b32010-12-10 13:06:46 +00002454 if (page.width != 0)
2455 page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
cristy3ed852e2009-09-05 21:47:34 +00002456 if (page.height != 0)
cristybb503372010-05-27 20:51:26 +00002457 page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
cristy3ed852e2009-09-05 21:47:34 +00002458 transverse_image->page=page;
2459 if (status == MagickFalse)
2460 transverse_image=DestroyImage(transverse_image);
2461 return(transverse_image);
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469% T r i m I m a g e %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
2475% TrimImage() trims pixels from the image edges. It allocates the memory
2476% necessary for the new Image structure and returns a pointer to the new
2477% image.
2478%
2479% The format of the TrimImage method is:
2480%
2481% Image *TrimImage(const Image *image,ExceptionInfo *exception)
2482%
2483% A description of each parameter follows:
2484%
2485% o image: the image.
2486%
2487% o exception: return any errors or warnings in this structure.
2488%
2489*/
2490MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2491{
2492 RectangleInfo
2493 geometry;
2494
2495 assert(image != (const Image *) NULL);
2496 assert(image->signature == MagickSignature);
2497 if (image->debug != MagickFalse)
2498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2499 geometry=GetImageBoundingBox(image,exception);
2500 if ((geometry.width == 0) || (geometry.height == 0))
2501 {
2502 Image
2503 *crop_image;
2504
2505 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2506 if (crop_image == (Image *) NULL)
2507 return((Image *) NULL);
cristy4c08aed2011-07-01 19:47:50 +00002508 crop_image->background_color.alpha=(Quantum) TransparentAlpha;
cristyea1a8aa2011-10-20 13:24:06 +00002509 (void) SetImageBackgroundColor(crop_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002510 crop_image->page=image->page;
2511 crop_image->page.x=(-1);
2512 crop_image->page.y=(-1);
2513 return(crop_image);
2514 }
2515 geometry.x+=image->page.x;
2516 geometry.y+=image->page.y;
2517 return(CropImage(image,&geometry,exception));
2518}