blob: b0b6c89f65b25618780e7df2a5d47e1f5c85c7a6 [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% %
20% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% 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*/
42#include "magick/studio.h"
43#include "magick/cache.h"
44#include "magick/cache-view.h"
45#include "magick/color.h"
46#include "magick/color-private.h"
47#include "magick/colorspace-private.h"
48#include "magick/composite.h"
49#include "magick/effect.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
52#include "magick/geometry.h"
53#include "magick/image.h"
54#include "magick/memory_.h"
55#include "magick/layer.h"
56#include "magick/list.h"
57#include "magick/monitor.h"
58#include "magick/monitor-private.h"
59#include "magick/pixel-private.h"
60#include "magick/resource_.h"
61#include "magick/resize.h"
62#include "magick/statistic.h"
63#include "magick/string_.h"
64#include "magick/transform.h"
65
66/*
67%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68% %
69% %
70% %
71% C h o p I m a g e %
72% %
73% %
74% %
75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76%
77% Chop() removes a region of an image and collapses the image to occupy the
78% removed portion.
79%
80% The format of the ChopImage method is:
81%
82% Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
83% ExceptionInfo *exception)
84%
85% A description of each parameter follows:
86%
87% o image: the image.
88%
89% o chop_info: Define the region of the image to chop.
90%
91% o exception: return any errors or warnings in this structure.
92%
93*/
94MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
95 ExceptionInfo *exception)
96{
97#define ChopImageTag "Chop/Image"
98
99 Image
100 *chop_image;
101
102 long
103 j,
104 y;
105
106 MagickBooleanType
107 proceed;
108
109 RectangleInfo
110 extent;
111
112 register long
113 i;
114
115 CacheView
116 *chop_view,
117 *image_view;
118
119 /*
120 Check chop geometry.
121 */
122 assert(image != (const Image *) NULL);
123 assert(image->signature == MagickSignature);
124 if (image->debug != MagickFalse)
125 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
126 assert(exception != (ExceptionInfo *) NULL);
127 assert(exception->signature == MagickSignature);
128 assert(chop_info != (RectangleInfo *) NULL);
129 if (((chop_info->x+(long) chop_info->width) < 0) ||
130 ((chop_info->y+(long) chop_info->height) < 0) ||
131 (chop_info->x > (long) image->columns) ||
132 (chop_info->y > (long) image->rows))
133 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
134 extent=(*chop_info);
135 if ((extent.x+(long) extent.width) > (long) image->columns)
136 extent.width=(unsigned long) ((long) image->columns-extent.x);
137 if ((extent.y+(long) extent.height) > (long) image->rows)
138 extent.height=(unsigned long) ((long) image->rows-extent.y);
139 if (extent.x < 0)
140 {
141 extent.width-=(unsigned long) (-extent.x);
142 extent.x=0;
143 }
144 if (extent.y < 0)
145 {
146 extent.height-=(unsigned long) (-extent.y);
147 extent.y=0;
148 }
149 chop_image=CloneImage(image,image->columns-extent.width,image->rows-
150 extent.height,MagickTrue,exception);
151 if (chop_image == (Image *) NULL)
152 return((Image *) NULL);
153 /*
154 Extract chop image.
155 */
156 i=0;
157 j=0;
158 image_view=AcquireCacheView(image);
159 chop_view=AcquireCacheView(chop_image);
160 for (y=0; y < (long) extent.y; y++)
161 {
162 register const PixelPacket
163 *__restrict p;
164
165 register IndexPacket
166 *__restrict chop_indexes,
167 *__restrict indexes;
168
169 register long
170 x;
171
172 register PixelPacket
173 *__restrict q;
174
175 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
176 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
177 exception);
178 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
179 break;
180 indexes=GetCacheViewAuthenticIndexQueue(image_view);
181 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
182 for (x=0; x < (long) image->columns; x++)
183 {
184 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
185 {
186 *q=(*p);
187 if (indexes != (IndexPacket *) NULL)
188 {
189 if (chop_indexes != (IndexPacket *) NULL)
190 *chop_indexes++=indexes[x];
191 }
192 q++;
193 }
194 p++;
195 }
196 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
197 break;
198 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
199 if (proceed == MagickFalse)
200 break;
201 }
202 /*
203 Extract chop image.
204 */
205 i+=extent.height;
206 for (y=0; y < (long) (image->rows-(extent.y+extent.height)); y++)
207 {
208 register const PixelPacket
209 *__restrict p;
210
211 register IndexPacket
212 *__restrict chop_indexes,
213 *__restrict indexes;
214
215 register long
216 x;
217
218 register PixelPacket
219 *__restrict q;
220
221 p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,exception);
222 q=QueueCacheViewAuthenticPixels(chop_view,0,j++,chop_image->columns,1,
223 exception);
224 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
225 break;
226 indexes=GetCacheViewAuthenticIndexQueue(image_view);
227 chop_indexes=GetCacheViewAuthenticIndexQueue(chop_view);
228 for (x=0; x < (long) image->columns; x++)
229 {
230 if ((x < extent.x) || (x >= (long) (extent.x+extent.width)))
231 {
232 *q=(*p);
233 if (indexes != (IndexPacket *) NULL)
234 {
235 if (chop_indexes != (IndexPacket *) NULL)
236 *chop_indexes++=indexes[x];
237 }
238 q++;
239 }
240 p++;
241 }
242 if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
243 break;
244 proceed=SetImageProgress(image,ChopImageTag,y,chop_image->rows);
245 if (proceed == MagickFalse)
246 break;
247 }
248 chop_view=DestroyCacheView(chop_view);
249 image_view=DestroyCacheView(image_view);
250 chop_image->type=image->type;
251 return(chop_image);
252}
253
254/*
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256% %
257% %
258% %
259+ C o n s o l i d a t e C M Y K I m a g e %
260% %
261% %
262% %
263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264%
265% ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
266% single image.
267%
268% The format of the ConsolidateCMYKImage method is:
269%
270% Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
271%
272% A description of each parameter follows:
273%
274% o image: the image sequence.
275%
276% o exception: return any errors or warnings in this structure.
277%
278*/
279MagickExport Image *ConsolidateCMYKImages(const Image *images,
280 ExceptionInfo *exception)
281{
282 Image
283 *cmyk_image,
284 *cmyk_images;
285
286 long
287 y;
288
289 register long
290 i;
291
292 /*
293 Consolidate separate C, M, Y, and K planes into a single image.
294 */
295 assert(images != (Image *) NULL);
296 assert(images->signature == MagickSignature);
297 if (images->debug != MagickFalse)
298 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
299 assert(exception != (ExceptionInfo *) NULL);
300 assert(exception->signature == MagickSignature);
301 cmyk_images=NewImageList();
302 for (i=0; i < (long) GetImageListLength(images); i+=4)
303 {
304 cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
305 exception);
306 if (cmyk_image == (Image *) NULL)
307 break;
308 if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
309 break;
310 (void) SetImageColorspace(cmyk_image,CMYKColorspace);
311 for (y=0; y < (long) images->rows; y++)
312 {
313 register const PixelPacket
314 *__restrict p;
315
316 register long
317 x;
318
319 register PixelPacket
320 *__restrict q;
321
322 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
323 q=QueueAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
324 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
325 break;
326 for (x=0; x < (long) images->columns; x++)
327 {
328 q->red=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
329 p++;
330 q++;
331 }
332 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
333 break;
334 }
335 images=GetNextImageInList(images);
336 if (images == (Image *) NULL)
337 break;
338 for (y=0; y < (long) images->rows; y++)
339 {
340 register const PixelPacket
341 *__restrict p;
342
343 register long
344 x;
345
346 register PixelPacket
347 *__restrict q;
348
349 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
350 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
351 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
352 break;
353 for (x=0; x < (long) images->columns; x++)
354 {
355 q->green=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
356 p++;
357 q++;
358 }
359 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
360 break;
361 }
362 images=GetNextImageInList(images);
363 if (images == (Image *) NULL)
364 break;
365 for (y=0; y < (long) images->rows; y++)
366 {
367 register const PixelPacket
368 *__restrict p;
369
370 register long
371 x;
372
373 register PixelPacket
374 *__restrict q;
375
376 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
377 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
378 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
379 break;
380 for (x=0; x < (long) images->columns; x++)
381 {
382 q->blue=(Quantum) (QuantumRange-PixelIntensityToQuantum(p));
383 p++;
384 q++;
385 }
386 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
387 break;
388 }
389 images=GetNextImageInList(images);
390 if (images == (Image *) NULL)
391 break;
392 for (y=0; y < (long) images->rows; y++)
393 {
394 register const PixelPacket
395 *__restrict p;
396
397 register IndexPacket
398 *__restrict indexes;
399
400 register long
401 x;
402
403 register PixelPacket
404 *__restrict q;
405
406 p=GetVirtualPixels(images,0,y,images->columns,1,exception);
407 q=GetAuthenticPixels(cmyk_image,0,y,cmyk_image->columns,1,exception);
408 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
409 break;
410 indexes=GetAuthenticIndexQueue(cmyk_image);
411 for (x=0; x < (long) images->columns; x++)
412 {
413 indexes[x]=(IndexPacket) (QuantumRange-PixelIntensityToQuantum(p));
414 p++;
415 }
416 if (SyncAuthenticPixels(cmyk_image,exception) == MagickFalse)
417 break;
418 }
419 AppendImageToList(&cmyk_images,cmyk_image);
420 images=GetNextImageInList(images);
421 if (images == (Image *) NULL)
422 break;
423 }
424 return(cmyk_images);
425}
426
427/*
428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429% %
430% %
431% %
432% C r o p I m a g e %
433% %
434% %
435% %
436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437%
438% CropImage() extracts a region of the image starting at the offset defined
439% by geometry.
440%
441% The format of the CropImage method is:
442%
443% Image *CropImage(const Image *image,const RectangleInfo *geometry,
444% ExceptionInfo *exception)
445%
446% A description of each parameter follows:
447%
448% o image: the image.
449%
450% o geometry: Define the region of the image to crop with members
451% x, y, width, and height.
452%
453% o exception: return any errors or warnings in this structure.
454%
455*/
456MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
457 ExceptionInfo *exception)
458{
459#define CropImageTag "Crop/Image"
460
461 Image
462 *crop_image;
463
464 long
465 progress,
466 y;
467
468 MagickBooleanType
469 status;
470
471 RectangleInfo
472 bounding_box,
473 page;
474
475 CacheView
476 *crop_view,
477 *image_view;
478
479 /*
480 Check crop geometry.
481 */
482 assert(image != (const Image *) NULL);
483 assert(image->signature == MagickSignature);
484 if (image->debug != MagickFalse)
485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
486 assert(geometry != (const RectangleInfo *) NULL);
487 assert(exception != (ExceptionInfo *) NULL);
488 assert(exception->signature == MagickSignature);
489 bounding_box=image->page;
490 if ((bounding_box.width == 0) || (bounding_box.height == 0))
491 {
492 bounding_box.width=image->columns;
493 bounding_box.height=image->rows;
494 }
495 page=(*geometry);
496 if (page.width == 0)
497 page.width=bounding_box.width;
498 if (page.height == 0)
499 page.height=bounding_box.height;
500 if (((bounding_box.x-page.x) >= (long) page.width) ||
501 ((bounding_box.y-page.y) >= (long) page.height) ||
502 ((page.x-bounding_box.x) > (long) image->columns) ||
503 ((page.y-bounding_box.y) > (long) image->rows))
504 {
505 /*
506 Crop is not within virtual canvas, return 1 pixel transparent image.
507 */
508 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
509 "GeometryDoesNotContainImage","`%s'",image->filename);
510 crop_image=CloneImage(image,1,1,MagickTrue,exception);
511 if (crop_image == (Image *) NULL)
512 return((Image *) NULL);
513 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
514 (void) SetImageBackgroundColor(crop_image);
515 crop_image->page=bounding_box;
516 crop_image->page.x=(-1);
517 crop_image->page.y=(-1);
518 if (crop_image->dispose == BackgroundDispose)
519 crop_image->dispose=NoneDispose;
520 return(crop_image);
521 }
522 if ((page.x < 0) && (bounding_box.x >= 0))
523 {
524 page.width+=page.x-bounding_box.x;
525 page.x=0;
526 }
527 else
528 {
529 page.width-=bounding_box.x-page.x;
530 page.x-=bounding_box.x;
531 if (page.x < 0)
532 page.x=0;
533 }
534 if ((page.y < 0) && (bounding_box.y >= 0))
535 {
536 page.height+=page.y-bounding_box.y;
537 page.y=0;
538 }
539 else
540 {
541 page.height-=bounding_box.y-page.y;
542 page.y-=bounding_box.y;
543 if (page.y < 0)
544 page.y=0;
545 }
546 if ((unsigned long) (page.x+page.width) > image->columns)
547 page.width=image->columns-page.x;
548 if (geometry->width != 0)
549 if (page.width > geometry->width)
550 page.width=geometry->width;
551 if ((unsigned long) (page.y+page.height) > image->rows)
552 page.height=image->rows-page.y;
553 if (geometry->height != 0)
554 if (page.height > geometry->height)
555 page.height=geometry->height;
556 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,
561 "GeometryDoesNotContainImage","`%s'",image->filename);
562 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;
572 if (((long) (bounding_box.x+bounding_box.width) > (long) image->page.width) ||
573 ((long) (bounding_box.y+bounding_box.height) > (long) image->page.height))
574 {
575 crop_image->page.width=bounding_box.width;
576 crop_image->page.height=bounding_box.height;
577 }
578 crop_image->page.x=bounding_box.x;
579 crop_image->page.y=bounding_box.y;
580 /*
581 Crop image.
582 */
583 status=MagickTrue;
584 progress=0;
585 image_view=AcquireCacheView(image);
586 crop_view=AcquireCacheView(crop_image);
cristy629a6c72009-09-13 23:28:22 +0000587#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +0000588 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000589#endif
590 for (y=0; y < (long) crop_image->rows; y++)
591 {
592 register const IndexPacket
593 *__restrict indexes;
594
595 register const PixelPacket
596 *__restrict p;
597
598 register IndexPacket
599 *__restrict crop_indexes;
600
601 register PixelPacket
602 *__restrict q;
603
604 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);
610 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
611 {
612 status=MagickFalse;
613 continue;
614 }
615 (void) CopyMagickMemory(q,p,(size_t) crop_image->columns*sizeof(*q));
616 indexes=GetCacheViewVirtualIndexQueue(image_view);
617 if (indexes != (IndexPacket *) NULL)
618 {
619 crop_indexes=GetCacheViewAuthenticIndexQueue(crop_view);
620 if (crop_indexes != (IndexPacket *) NULL)
621 (void) CopyMagickMemory(crop_indexes,indexes,(size_t)
622 crop_image->columns*sizeof(*crop_indexes));
623 }
624 if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
625 status=MagickFalse;
626 if (image->progress_monitor != (MagickProgressMonitor) NULL)
627 {
628 MagickBooleanType
629 proceed;
630
cristy629a6c72009-09-13 23:28:22 +0000631#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +0000632 #pragma omp critical (MagickCore_CropImage)
633#endif
634 proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
635 if (proceed == MagickFalse)
636 status=MagickFalse;
637 }
638 }
639 crop_view=DestroyCacheView(crop_view);
640 image_view=DestroyCacheView(image_view);
641 crop_image->type=image->type;
642 if (status == MagickFalse)
643 crop_image=DestroyImage(crop_image);
644 return(crop_image);
645}
646
647/*
648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649% %
650% %
651% %
652% E x c e r p t I m a g e %
653% %
654% %
655% %
656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657%
658% ExcerptImage() returns a excerpt of the image as defined by the geometry.
659%
660% The format of the ExcerptImage method is:
661%
662% Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
663% ExceptionInfo *exception)
664%
665% A description of each parameter follows:
666%
667% o image: the image.
668%
669% o geometry: Define the region of the image to extend with members
670% x, y, width, and height.
671%
672% o exception: return any errors or warnings in this structure.
673%
674*/
675MagickExport Image *ExcerptImage(const Image *image,
676 const RectangleInfo *geometry,ExceptionInfo *exception)
677{
678#define ExcerptImageTag "Excerpt/Image"
679
680 Image
681 *excerpt_image;
682
683 long
684 progress,
685 y;
686
687 MagickBooleanType
688 status;
689
690 CacheView
691 *excerpt_view,
692 *image_view;
693
694 /*
695 Allocate excerpt image.
696 */
697 assert(image != (const Image *) NULL);
698 assert(image->signature == MagickSignature);
699 if (image->debug != MagickFalse)
700 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
701 assert(geometry != (const RectangleInfo *) NULL);
702 assert(exception != (ExceptionInfo *) NULL);
703 assert(exception->signature == MagickSignature);
704 excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
705 exception);
706 if (excerpt_image == (Image *) NULL)
707 return((Image *) NULL);
708 /*
709 Excerpt each row.
710 */
711 status=MagickTrue;
712 progress=0;
713 image_view=AcquireCacheView(image);
714 excerpt_view=AcquireCacheView(excerpt_image);
cristy629a6c72009-09-13 23:28:22 +0000715#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +0000716 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000717#endif
718 for (y=0; y < (long) excerpt_image->rows; y++)
719 {
720 register const PixelPacket
721 *__restrict p;
722
723 register IndexPacket
724 *__restrict excerpt_indexes,
725 *__restrict indexes;
726
727 register PixelPacket
728 *__restrict q;
729
730 if (status == MagickFalse)
731 continue;
732 p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
733 geometry->width,1,exception);
734 q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
735 exception);
736 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
737 {
738 status=MagickFalse;
739 continue;
740 }
741 (void) CopyMagickMemory(q,p,(size_t) excerpt_image->columns*sizeof(*q));
742 indexes=GetCacheViewAuthenticIndexQueue(image_view);
743 if (indexes != (IndexPacket *) NULL)
744 {
745 excerpt_indexes=GetCacheViewAuthenticIndexQueue(excerpt_view);
746 if (excerpt_indexes != (IndexPacket *) NULL)
747 (void) CopyMagickMemory(excerpt_indexes,indexes,(size_t)
748 excerpt_image->columns*sizeof(*excerpt_indexes));
749 }
750 if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
751 status=MagickFalse;
752 if (image->progress_monitor != (MagickProgressMonitor) NULL)
753 {
754 MagickBooleanType
755 proceed;
756
cristy629a6c72009-09-13 23:28:22 +0000757#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +0000758 #pragma omp critical (MagickCore_ExcerptImage)
759#endif
760 proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
761 if (proceed == MagickFalse)
762 status=MagickFalse;
763 }
764 }
765 excerpt_view=DestroyCacheView(excerpt_view);
766 image_view=DestroyCacheView(image_view);
767 excerpt_image->type=image->type;
768 if (status == MagickFalse)
769 excerpt_image=DestroyImage(excerpt_image);
770 return(excerpt_image);
771}
772
773/*
774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775% %
776% %
777% %
778% E x t e n t I m a g e %
779% %
780% %
781% %
782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
783%
784% ExtentImage() extends the image as defined by the geometry, gravity, and
785% image background color. Set the (x,y) offset of the geometry to move the
786% original image relative to the extended image.
787%
788% The format of the ExtentImage method is:
789%
790% Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
791% ExceptionInfo *exception)
792%
793% A description of each parameter follows:
794%
795% o image: the image.
796%
797% o geometry: Define the region of the image to extend with members
798% x, y, width, and height.
799%
800% o exception: return any errors or warnings in this structure.
801%
802*/
803MagickExport Image *ExtentImage(const Image *image,
804 const RectangleInfo *geometry,ExceptionInfo *exception)
805{
806 Image
807 *extent_image;
808
809 /*
810 Allocate extent image.
811 */
812 assert(image != (const Image *) NULL);
813 assert(image->signature == MagickSignature);
814 if (image->debug != MagickFalse)
815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
816 assert(geometry != (const RectangleInfo *) NULL);
817 assert(exception != (ExceptionInfo *) NULL);
818 assert(exception->signature == MagickSignature);
819 extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
820 exception);
821 if (extent_image == (Image *) NULL)
822 return((Image *) NULL);
823 if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
824 {
825 InheritException(exception,&extent_image->exception);
826 extent_image=DestroyImage(extent_image);
827 return((Image *) NULL);
828 }
829 if (extent_image->background_color.opacity != OpaqueOpacity)
830 extent_image->matte=MagickTrue;
831 (void) SetImageBackgroundColor(extent_image);
832 (void) CompositeImage(extent_image,image->compose,image,geometry->x,
833 geometry->y);
834 return(extent_image);
835}
836
837/*
838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
839% %
840% %
841% %
842% F l i p I m a g e %
843% %
844% %
845% %
846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847%
848% FlipImage() creates a vertical mirror image by reflecting the pixels
849% around the central x-axis.
850%
851% The format of the FlipImage method is:
852%
853% Image *FlipImage(const Image *image,ExceptionInfo *exception)
854%
855% A description of each parameter follows:
856%
857% o image: the image.
858%
859% o exception: return any errors or warnings in this structure.
860%
861*/
862MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
863{
864#define FlipImageTag "Flip/Image"
865
866 Image
867 *flip_image;
868
869 long
870 progress,
871 y;
872
873 MagickBooleanType
874 status;
875
876 CacheView
877 *flip_view,
878 *image_view;
879
880 assert(image != (const Image *) NULL);
881 assert(image->signature == MagickSignature);
882 if (image->debug != MagickFalse)
883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
884 assert(exception != (ExceptionInfo *) NULL);
885 assert(exception->signature == MagickSignature);
886 flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
887 if (flip_image == (Image *) NULL)
888 return((Image *) NULL);
889 /*
890 Flip image.
891 */
892 status=MagickTrue;
893 progress=0;
894 image_view=AcquireCacheView(image);
895 flip_view=AcquireCacheView(flip_image);
cristy629a6c72009-09-13 23:28:22 +0000896#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +0000897 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +0000898#endif
899 for (y=0; y < (long) flip_image->rows; y++)
900 {
901 register const IndexPacket
902 *__restrict indexes;
903
904 register const PixelPacket
905 *__restrict p;
906
907 register IndexPacket
908 *__restrict flip_indexes;
909
910 register PixelPacket
911 *__restrict q;
912
913 if (status == MagickFalse)
914 continue;
915 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
916 q=QueueCacheViewAuthenticPixels(flip_view,0,(long) (flip_image->rows-y-1),
917 flip_image->columns,1,exception);
918 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
919 {
920 status=MagickFalse;
921 continue;
922 }
923 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
924 indexes=GetCacheViewVirtualIndexQueue(image_view);
925 if (indexes != (const IndexPacket *) NULL)
926 {
927 flip_indexes=GetCacheViewAuthenticIndexQueue(flip_view);
928 if (flip_indexes != (IndexPacket *) NULL)
929 (void) CopyMagickMemory(flip_indexes,indexes,(size_t) image->columns*
930 sizeof(*flip_indexes));
931 }
932 if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
933 status=MagickFalse;
934 if (image->progress_monitor != (MagickProgressMonitor) NULL)
935 {
936 MagickBooleanType
937 proceed;
938
cristy629a6c72009-09-13 23:28:22 +0000939#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +0000940 #pragma omp critical (MagickCore_FlipImage)
941#endif
942 proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
943 if (proceed == MagickFalse)
944 status=MagickFalse;
945 }
946 }
947 flip_view=DestroyCacheView(flip_view);
948 image_view=DestroyCacheView(image_view);
949 flip_image->type=image->type;
950 if (status == MagickFalse)
951 flip_image=DestroyImage(flip_image);
952 return(flip_image);
953}
954
955/*
956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957% %
958% %
959% %
960% F l o p I m a g e %
961% %
962% %
963% %
964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965%
966% FlopImage() creates a horizontal mirror image by reflecting the pixels
967% around the central y-axis.
968%
969% The format of the FlopImage method is:
970%
971% Image *FlopImage(const Image *image,ExceptionInfo *exception)
972%
973% A description of each parameter follows:
974%
975% o image: the image.
976%
977% o exception: return any errors or warnings in this structure.
978%
979*/
980MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
981{
982#define FlopImageTag "Flop/Image"
983
984 Image
985 *flop_image;
986
987 long
988 progress,
989 y;
990
991 MagickBooleanType
992 status;
993
994 CacheView
995 *flop_view,
996 *image_view;
997
998 assert(image != (const Image *) NULL);
999 assert(image->signature == MagickSignature);
1000 if (image->debug != MagickFalse)
1001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1002 assert(exception != (ExceptionInfo *) NULL);
1003 assert(exception->signature == MagickSignature);
1004 flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1005 if (flop_image == (Image *) NULL)
1006 return((Image *) NULL);
1007 /*
1008 Flop each row.
1009 */
1010 status=MagickTrue;
1011 progress=0;
1012 image_view=AcquireCacheView(image);
1013 flop_view=AcquireCacheView(flop_image);
cristy629a6c72009-09-13 23:28:22 +00001014#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00001015 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001016#endif
1017 for (y=0; y < (long) flop_image->rows; y++)
1018 {
1019 register const IndexPacket
1020 *__restrict indexes;
1021
1022 register const PixelPacket
1023 *__restrict p;
1024
1025 register IndexPacket
1026 *__restrict flop_indexes;
1027
1028 register long
1029 x;
1030
1031 register PixelPacket
1032 *__restrict q;
1033
1034 if (status == MagickFalse)
1035 continue;
1036 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1037 q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
1038 exception);
1039 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1040 {
1041 status=MagickFalse;
1042 continue;
1043 }
1044 q+=flop_image->columns;
1045 indexes=GetCacheViewVirtualIndexQueue(image_view);
1046 flop_indexes=GetCacheViewAuthenticIndexQueue(flop_view);
1047 for (x=0; x < (long) flop_image->columns; x++)
1048 {
1049 (*--q)=(*p++);
1050 if ((indexes != (const IndexPacket *) NULL) &&
1051 (flop_indexes != (IndexPacket *) NULL))
1052 flop_indexes[flop_image->columns-x-1]=indexes[x];
1053 }
1054 if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
1055 status=MagickFalse;
1056 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1057 {
1058 MagickBooleanType
1059 proceed;
1060
cristy629a6c72009-09-13 23:28:22 +00001061#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +00001062 #pragma omp critical (MagickCore_FlopImage)
1063#endif
1064 proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
1065 if (proceed == MagickFalse)
1066 status=MagickFalse;
1067 }
1068 }
1069 flop_view=DestroyCacheView(flop_view);
1070 image_view=DestroyCacheView(image_view);
1071 flop_image->type=image->type;
1072 if (status == MagickFalse)
1073 flop_image=DestroyImage(flop_image);
1074 return(flop_image);
1075}
1076
1077/*
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079% %
1080% %
1081% %
1082% R o l l I m a g e %
1083% %
1084% %
1085% %
1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087%
1088% RollImage() offsets an image as defined by x_offset and y_offset.
1089%
1090% The format of the RollImage method is:
1091%
1092% Image *RollImage(const Image *image,const long x_offset,
1093% const long y_offset,ExceptionInfo *exception)
1094%
1095% A description of each parameter follows:
1096%
1097% o image: the image.
1098%
1099% o x_offset: the number of columns to roll in the horizontal direction.
1100%
1101% o y_offset: the number of rows to roll in the vertical direction.
1102%
1103% o exception: return any errors or warnings in this structure.
1104%
1105*/
1106
1107static inline MagickBooleanType CopyImageRegion(Image *destination,
1108 const Image *source,const unsigned long columns,const unsigned long rows,
1109 const long sx,const long sy,const long dx,const long dy,
1110 ExceptionInfo *exception)
1111{
1112 long
1113 y;
1114
1115 MagickBooleanType
1116 status;
1117
1118 CacheView
1119 *source_view,
1120 *destination_view;
1121
1122 status=MagickTrue;
1123 source_view=AcquireCacheView(source);
1124 destination_view=AcquireCacheView(destination);
cristy629a6c72009-09-13 23:28:22 +00001125#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00001126 #pragma omp parallel for shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001127#endif
1128 for (y=0; y < (long) rows; y++)
1129 {
1130 MagickBooleanType
1131 sync;
1132
1133 register const PixelPacket
1134 *__restrict p;
1135
1136 register IndexPacket
1137 *__restrict indexes,
1138 *__restrict destination_indexes;
1139
1140 register long
1141 x;
1142
1143 register PixelPacket
1144 *__restrict q;
1145
1146 /*
1147 Transfer scanline.
1148 */
1149 if (status == MagickFalse)
1150 continue;
1151 p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
1152 q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
1153 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1154 {
1155 status=MagickFalse;
1156 continue;
1157 }
1158 indexes=GetCacheViewAuthenticIndexQueue(source_view);
1159 for (x=0; x < (long) columns; x++)
1160 *q++=(*p++);
1161 if (indexes != (IndexPacket *) NULL)
1162 {
1163 destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
1164 for (x=0; x < (long) columns; x++)
1165 destination_indexes[x]=indexes[x];
1166 }
1167 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1168 if (sync == MagickFalse)
1169 status=MagickFalse;
1170 }
1171 destination_view=DestroyCacheView(destination_view);
1172 source_view=DestroyCacheView(source_view);
1173 return(status);
1174}
1175
1176MagickExport Image *RollImage(const Image *image,const long x_offset,
1177 const long y_offset,ExceptionInfo *exception)
1178{
1179#define RollImageTag "Roll/Image"
1180
1181 Image
1182 *roll_image;
1183
1184 MagickStatusType
1185 status;
1186
1187 RectangleInfo
1188 offset;
1189
1190 /*
1191 Initialize roll image attributes.
1192 */
1193 assert(image != (const Image *) NULL);
1194 assert(image->signature == MagickSignature);
1195 if (image->debug != MagickFalse)
1196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1197 assert(exception != (ExceptionInfo *) NULL);
1198 assert(exception->signature == MagickSignature);
1199 roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1200 if (roll_image == (Image *) NULL)
1201 return((Image *) NULL);
1202 offset.x=x_offset;
1203 offset.y=y_offset;
1204 while (offset.x < 0)
1205 offset.x+=image->columns;
1206 while (offset.x >= (long) image->columns)
1207 offset.x-=image->columns;
1208 while (offset.y < 0)
1209 offset.y+=image->rows;
1210 while (offset.y >= (long) image->rows)
1211 offset.y-=image->rows;
1212 /*
1213 Roll image.
1214 */
1215 status=CopyImageRegion(roll_image,image,(unsigned long) offset.x,
1216 (unsigned long) offset.y,(long) image->columns-offset.x,(long) image->rows-
1217 offset.y,0,0,exception);
1218 (void) SetImageProgress(image,RollImageTag,0,3);
1219 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
1220 (unsigned long) offset.y,0,(long) image->rows-offset.y,offset.x,0,
1221 exception);
1222 (void) SetImageProgress(image,RollImageTag,1,3);
1223 status|=CopyImageRegion(roll_image,image,(unsigned long) offset.x,image->rows-
1224 offset.y,(long) image->columns-offset.x,0,0,offset.y,exception);
1225 (void) SetImageProgress(image,RollImageTag,2,3);
1226 status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
1227 offset.y,0,0,offset.x,offset.y,exception);
1228 (void) SetImageProgress(image,RollImageTag,3,3);
1229 roll_image->type=image->type;
1230 if (status == MagickFalse)
1231 roll_image=DestroyImage(roll_image);
1232 return(roll_image);
1233}
1234
1235/*
1236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237% %
1238% %
1239% %
1240% S h a v e I m a g e %
1241% %
1242% %
1243% %
1244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245%
1246% ShaveImage() shaves pixels from the image edges. It allocates the memory
1247% necessary for the new Image structure and returns a pointer to the new
1248% image.
1249%
1250% The format of the ShaveImage method is:
1251%
1252% Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1253% ExceptionInfo *exception)
1254%
1255% A description of each parameter follows:
1256%
1257% o shave_image: Method ShaveImage returns a pointer to the shaved
1258% image. A null image is returned if there is a memory shortage or
1259% if the image width or height is zero.
1260%
1261% o image: the image.
1262%
1263% o shave_info: Specifies a pointer to a RectangleInfo which defines the
1264% region of the image to crop.
1265%
1266% o exception: return any errors or warnings in this structure.
1267%
1268*/
1269MagickExport Image *ShaveImage(const Image *image,
1270 const RectangleInfo *shave_info,ExceptionInfo *exception)
1271{
1272 Image
1273 *shave_image;
1274
1275 RectangleInfo
1276 geometry;
1277
1278 assert(image != (const Image *) NULL);
1279 assert(image->signature == MagickSignature);
1280 if (image->debug != MagickFalse)
1281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1282 if (((2*shave_info->width) >= image->columns) ||
1283 ((2*shave_info->height) >= image->rows))
1284 ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
1285 SetGeometry(image,&geometry);
1286 geometry.width-=2*shave_info->width;
1287 geometry.height-=2*shave_info->height;
1288 geometry.x=(long) shave_info->width+image->page.x;
1289 geometry.y=(long) shave_info->height+image->page.y;
1290 shave_image=CropImage(image,&geometry,exception);
1291 if (shave_image == (Image *) NULL)
1292 return((Image *) NULL);
1293 shave_image->page.width-=2*shave_info->width;
1294 shave_image->page.height-=2*shave_info->height;
1295 shave_image->page.x-=shave_info->width;
1296 shave_image->page.y-=shave_info->height;
1297 return(shave_image);
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305% S p l i c e I m a g e %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% SpliceImage() splices a solid color into the image as defined by the
1312% geometry.
1313%
1314% The format of the SpliceImage method is:
1315%
1316% Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
1317% ExceptionInfo *exception)
1318%
1319% A description of each parameter follows:
1320%
1321% o image: the image.
1322%
1323% o geometry: Define the region of the image to splice with members
1324% x, y, width, and height.
1325%
1326% o exception: return any errors or warnings in this structure.
1327%
1328*/
1329MagickExport Image *SpliceImage(const Image *image,
1330 const RectangleInfo *geometry,ExceptionInfo *exception)
1331{
1332#define SpliceImageTag "Splice/Image"
1333
1334 Image
1335 *splice_image;
1336
1337 long
1338 progress,
1339 y;
1340
1341 MagickBooleanType
1342 proceed,
1343 status;
1344
1345 RectangleInfo
1346 splice_geometry;
1347
1348 register long
1349 i;
1350
1351 CacheView
1352 *image_view,
1353 *splice_view;
1354
1355 /*
1356 Allocate splice image.
1357 */
1358 assert(image != (const Image *) NULL);
1359 assert(image->signature == MagickSignature);
1360 if (image->debug != MagickFalse)
1361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1362 assert(geometry != (const RectangleInfo *) NULL);
1363 assert(exception != (ExceptionInfo *) NULL);
1364 assert(exception->signature == MagickSignature);
1365 splice_geometry=(*geometry);
1366 splice_image=CloneImage(image,image->columns+splice_geometry.width,
1367 image->rows+splice_geometry.height,MagickTrue,exception);
1368 if (splice_image == (Image *) NULL)
1369 return((Image *) NULL);
1370 if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
1371 {
1372 InheritException(exception,&splice_image->exception);
1373 splice_image=DestroyImage(splice_image);
1374 return((Image *) NULL);
1375 }
1376 (void) SetImageBackgroundColor(splice_image);
1377 /*
1378 Respect image geometry.
1379 */
1380 switch (image->gravity)
1381 {
1382 default:
1383 case UndefinedGravity:
1384 case NorthWestGravity:
1385 break;
1386 case NorthGravity:
1387 {
1388 splice_geometry.x+=splice_geometry.width/2;
1389 break;
1390 }
1391 case NorthEastGravity:
1392 {
1393 splice_geometry.x+=splice_geometry.width;
1394 break;
1395 }
1396 case WestGravity:
1397 {
1398 splice_geometry.y+=splice_geometry.width/2;
1399 break;
1400 }
1401 case StaticGravity:
1402 case CenterGravity:
1403 {
1404 splice_geometry.x+=splice_geometry.width/2;
1405 splice_geometry.y+=splice_geometry.height/2;
1406 break;
1407 }
1408 case EastGravity:
1409 {
1410 splice_geometry.x+=splice_geometry.width;
1411 splice_geometry.y+=splice_geometry.height/2;
1412 break;
1413 }
1414 case SouthWestGravity:
1415 {
1416 splice_geometry.y+=splice_geometry.height;
1417 break;
1418 }
1419 case SouthGravity:
1420 {
1421 splice_geometry.x+=splice_geometry.width/2;
1422 splice_geometry.y+=splice_geometry.height;
1423 break;
1424 }
1425 case SouthEastGravity:
1426 {
1427 splice_geometry.x+=splice_geometry.width;
1428 splice_geometry.y+=splice_geometry.height;
1429 break;
1430 }
1431 }
1432 /*
1433 Splice image.
1434 */
1435 status=MagickTrue;
1436 i=0;
1437 progress=0;
1438 image_view=AcquireCacheView(image);
1439 splice_view=AcquireCacheView(splice_image);
cristy629a6c72009-09-13 23:28:22 +00001440#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00001441 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001442#endif
1443 for (y=0; y < (long) splice_geometry.y; y++)
1444 {
1445 register const PixelPacket
1446 *__restrict p;
1447
1448 register IndexPacket
1449 *__restrict indexes,
1450 *__restrict splice_indexes;
1451
1452 register long
1453 x;
1454
1455 register PixelPacket
1456 *__restrict q;
1457
1458 if (status == MagickFalse)
1459 continue;
1460 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1461 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1462 exception);
1463 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1464 {
1465 status=MagickFalse;
1466 continue;
1467 }
1468 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1469 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1470 for (x=0; x < splice_geometry.x; x++)
1471 {
1472 q->red=p->red;
1473 q->green=p->green;
1474 q->blue=p->blue;
1475 q->opacity=OpaqueOpacity;
1476 if (image->matte != MagickFalse)
1477 q->opacity=p->opacity;
1478 if (image->colorspace == CMYKColorspace)
1479 splice_indexes[x]=(*indexes++);
1480 p++;
1481 q++;
1482 }
1483 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1484 q++;
1485 for ( ; x < (long) splice_image->columns; x++)
1486 {
1487 q->red=p->red;
1488 q->green=p->green;
1489 q->blue=p->blue;
1490 q->opacity=OpaqueOpacity;
1491 if (image->matte != MagickFalse)
1492 q->opacity=p->opacity;
1493 if (image->colorspace == CMYKColorspace)
1494 splice_indexes[x]=(*indexes++);
1495 p++;
1496 q++;
1497 }
1498 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1499 status=MagickFalse;
1500 proceed=SetImageProgress(image,SpliceImageTag,y,splice_image->rows);
1501 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1502 {
1503 MagickBooleanType
1504 proceed;
1505
cristy629a6c72009-09-13 23:28:22 +00001506#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +00001507 #pragma omp critical (MagickCore_TransposeImage)
1508#endif
1509 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1510 splice_image->rows);
1511 if (proceed == MagickFalse)
1512 status=MagickFalse;
1513 }
1514 }
cristy629a6c72009-09-13 23:28:22 +00001515#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00001516 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001517#endif
1518 for (y=(long) (splice_geometry.y+splice_geometry.height);
1519 y < (long) splice_image->rows; y++)
1520 {
1521 register const PixelPacket
1522 *__restrict p;
1523
1524 register IndexPacket
1525 *__restrict indexes,
1526 *__restrict splice_indexes;
1527
1528 register long
1529 x;
1530
1531 register PixelPacket
1532 *__restrict q;
1533
1534 if (status == MagickFalse)
1535 continue;
1536 p=GetCacheViewVirtualPixels(image_view,0,y-splice_geometry.height,
1537 image->columns,1,exception);
1538 q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
1539 exception);
1540 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1541 {
1542 status=MagickFalse;
1543 continue;
1544 }
1545 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1546 splice_indexes=GetCacheViewAuthenticIndexQueue(splice_view);
1547 for (x=0; x < splice_geometry.x; x++)
1548 {
1549 q->red=p->red;
1550 q->green=p->green;
1551 q->blue=p->blue;
1552 q->opacity=OpaqueOpacity;
1553 if (image->matte != MagickFalse)
1554 q->opacity=p->opacity;
1555 if (image->colorspace == CMYKColorspace)
1556 splice_indexes[x]=(*indexes++);
1557 p++;
1558 q++;
1559 }
1560 for ( ; x < (long) (splice_geometry.x+splice_geometry.width); x++)
1561 q++;
1562 for ( ; x < (long) splice_image->columns; x++)
1563 {
1564 q->red=p->red;
1565 q->green=p->green;
1566 q->blue=p->blue;
1567 q->opacity=OpaqueOpacity;
1568 if (image->matte != MagickFalse)
1569 q->opacity=p->opacity;
1570 if (image->colorspace == CMYKColorspace)
1571 splice_indexes[x]=(*indexes++);
1572 p++;
1573 q++;
1574 }
1575 if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
1576 status=MagickFalse;
1577 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1578 {
1579 MagickBooleanType
1580 proceed;
1581
cristy629a6c72009-09-13 23:28:22 +00001582#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +00001583 #pragma omp critical (MagickCore_TransposeImage)
1584#endif
1585 proceed=SetImageProgress(image,SpliceImageTag,progress++,
1586 splice_image->rows);
1587 if (proceed == MagickFalse)
1588 status=MagickFalse;
1589 }
1590 }
1591 splice_view=DestroyCacheView(splice_view);
1592 image_view=DestroyCacheView(image_view);
1593 if (status == MagickFalse)
1594 splice_image=DestroyImage(splice_image);
1595 return(splice_image);
1596}
1597
1598/*
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600% %
1601% %
1602% %
1603% T r a n s f o r m I m a g e %
1604% %
1605% %
1606% %
1607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608%
1609% TransformImage() is a convenience method that behaves like ResizeImage() or
1610% CropImage() but accepts scaling and/or cropping information as a region
1611% geometry specification. If the operation fails, the original image handle
1612% is returned.
1613%
1614% The format of the TransformImage method is:
1615%
1616% MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
1617% const char *image_geometry)
1618%
1619% A description of each parameter follows:
1620%
1621% o image: the image The transformed image is returned as this parameter.
1622%
1623% o crop_geometry: A crop geometry string. This geometry defines a
1624% subregion of the image to crop.
1625%
1626% o image_geometry: An image geometry string. This geometry defines the
1627% final size of the image.
1628%
1629*/
1630MagickExport MagickBooleanType TransformImage(Image **image,
1631 const char *crop_geometry,const char *image_geometry)
1632{
1633 Image
1634 *resize_image,
1635 *transform_image;
1636
1637 MagickStatusType
1638 flags;
1639
1640 RectangleInfo
1641 geometry;
1642
1643 assert(image != (Image **) NULL);
1644 assert((*image)->signature == MagickSignature);
1645 if ((*image)->debug != MagickFalse)
1646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1647 transform_image=(*image);
1648 if (crop_geometry != (const char *) NULL)
1649 {
1650 Image
1651 *crop_image;
1652
1653 RectangleInfo
1654 geometry;
1655
1656 /*
1657 Crop image to a user specified size.
1658 */
1659 crop_image=NewImageList();
1660 flags=ParseGravityGeometry(transform_image,crop_geometry,&geometry,
1661 &(*image)->exception);
1662 if (((geometry.width == 0) && (geometry.height == 0)) ||
1663 ((flags & XValue) != 0) || ((flags & YValue) != 0))
1664 {
1665 crop_image=CropImage(transform_image,&geometry,&(*image)->exception);
1666 if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
1667 {
1668 crop_image->page.width=geometry.width;
1669 crop_image->page.height=geometry.height;
1670 crop_image->page.x-=geometry.x;
1671 crop_image->page.y-=geometry.y;
1672 }
1673 }
1674 else
1675 if ((transform_image->columns > geometry.width) ||
1676 (transform_image->rows > geometry.height))
1677 {
1678 Image
1679 *next;
1680
1681 long
1682 y;
1683
1684 register long
1685 x;
1686
1687 unsigned long
1688 height,
1689 width;
1690
1691 /*
1692 Crop repeatedly to create uniform scenes.
1693 */
1694 if (transform_image->page.width == 0)
1695 transform_image->page.width=transform_image->columns;
1696 if (transform_image->page.height == 0)
1697 transform_image->page.height=transform_image->rows;
1698 width=geometry.width;
1699 if (width == 0)
1700 width=transform_image->page.width;
1701 height=geometry.height;
1702 if (height == 0)
1703 height=transform_image->page.height;
1704 next=NewImageList();
1705 for (y=0; y < (long) transform_image->page.height; y+=height)
1706 {
1707 for (x=0; x < (long) transform_image->page.width; x+=width)
1708 {
1709 geometry.width=width;
1710 geometry.height=height;
1711 geometry.x=x;
1712 geometry.y=y;
1713 next=CropImage(transform_image,&geometry,&(*image)->exception);
1714 if (next == (Image *) NULL)
1715 break;
1716 AppendImageToList(&crop_image,next);
1717 }
1718 if (next == (Image *) NULL)
1719 break;
1720 }
1721 }
1722 if (crop_image == (Image *) NULL)
1723 transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
1724 else
1725 {
1726 transform_image=DestroyImage(transform_image);
1727 transform_image=GetFirstImageInList(crop_image);
1728 }
1729 *image=transform_image;
1730 }
1731 if (image_geometry == (const char *) NULL)
1732 return(MagickTrue);
1733 /*
1734 Scale image to a user specified size.
1735 */
1736 flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
1737 &(*image)->exception);
1738 if ((transform_image->columns == geometry.width) &&
1739 (transform_image->rows == geometry.height))
1740 return(MagickTrue);
1741 resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1742 &(*image)->exception);
1743 if (resize_image == (Image *) NULL)
1744 return(MagickFalse);
1745 transform_image=DestroyImage(transform_image);
1746 transform_image=resize_image;
1747 *image=transform_image;
1748 return(MagickTrue);
1749}
1750
1751/*
1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753% %
1754% %
1755% %
1756% T r a n s f o r m I m a g e s %
1757% %
1758% %
1759% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760%
1761% TransformImages() calls TransformImage() on each image of a sequence.
1762%
1763% The format of the TransformImage method is:
1764%
1765% MagickBooleanType TransformImages(Image **image,
1766% const char *crop_geometry,const char *image_geometry)
1767%
1768% A description of each parameter follows:
1769%
1770% o image: the image The transformed image is returned as this parameter.
1771%
1772% o crop_geometry: A crop geometry string. This geometry defines a
1773% subregion of the image to crop.
1774%
1775% o image_geometry: An image geometry string. This geometry defines the
1776% final size of the image.
1777%
1778*/
1779MagickExport MagickBooleanType TransformImages(Image **images,
1780 const char *crop_geometry,const char *image_geometry)
1781{
1782 Image
1783 *image,
1784 **image_list,
1785 *transform_images;
1786
1787 MagickStatusType
1788 status;
1789
1790 register long
1791 i;
1792
1793 assert(images != (Image **) NULL);
1794 assert((*images)->signature == MagickSignature);
1795 if ((*images)->debug != MagickFalse)
1796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1797 (*images)->filename);
1798 image_list=ImageListToArray(*images,&(*images)->exception);
1799 if (image_list == (Image **) NULL)
1800 return(MagickFalse);
1801 status=MagickTrue;
1802 transform_images=NewImageList();
1803 for (i=0; image_list[i] != (Image *) NULL; i++)
1804 {
1805 image=image_list[i];
1806 status|=TransformImage(&image,crop_geometry,image_geometry);
1807 AppendImageToList(&transform_images,image);
1808 }
1809 *images=transform_images;
1810 image_list=(Image **) RelinquishMagickMemory(image_list);
1811 return(status != 0 ? MagickTrue : MagickFalse);
1812}
1813
1814/*
1815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1816% %
1817% %
1818% %
1819% T r a n s p o s e I m a g e %
1820% %
1821% %
1822% %
1823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1824%
1825% TransposeImage() creates a horizontal mirror image by reflecting the pixels
1826% around the central y-axis while rotating them by 90 degrees.
1827%
1828% The format of the TransposeImage method is:
1829%
1830% Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1831%
1832% A description of each parameter follows:
1833%
1834% o image: the image.
1835%
1836% o exception: return any errors or warnings in this structure.
1837%
1838*/
1839MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
1840{
1841#define TransposeImageTag "Transpose/Image"
1842
1843 Image
1844 *transpose_image;
1845
1846 long
1847 progress,
1848 y;
1849
1850 MagickBooleanType
1851 status;
1852
1853 RectangleInfo
1854 page;
1855
1856 CacheView
1857 *image_view,
1858 *transpose_view;
1859
1860 assert(image != (const Image *) NULL);
1861 assert(image->signature == MagickSignature);
1862 if (image->debug != MagickFalse)
1863 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1864 assert(exception != (ExceptionInfo *) NULL);
1865 assert(exception->signature == MagickSignature);
1866 transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
1867 exception);
1868 if (transpose_image == (Image *) NULL)
1869 return((Image *) NULL);
1870 /*
1871 Transpose image.
1872 */
1873 status=MagickTrue;
1874 progress=0;
1875 image_view=AcquireCacheView(image);
1876 transpose_view=AcquireCacheView(transpose_image);
cristy629a6c72009-09-13 23:28:22 +00001877#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00001878 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001879#endif
1880 for (y=0; y < (long) image->rows; y++)
1881 {
1882 register const PixelPacket
1883 *__restrict p;
1884
1885 register IndexPacket
1886 *__restrict transpose_indexes,
1887 *__restrict indexes;
1888
1889 register PixelPacket
1890 *__restrict q;
1891
1892 if (status == MagickFalse)
1893 continue;
1894 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-y-1,
1895 image->columns,1,exception);
1896 q=QueueCacheViewAuthenticPixels(transpose_view,(long) (image->rows-y-1),0,
1897 1,transpose_image->rows,exception);
1898 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1899 {
1900 status=MagickFalse;
1901 continue;
1902 }
1903 (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q));
1904 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1905 if (indexes != (IndexPacket *) NULL)
1906 {
1907 transpose_indexes=GetCacheViewAuthenticIndexQueue(transpose_view);
1908 if (transpose_indexes != (IndexPacket *) NULL)
1909 (void) CopyMagickMemory(transpose_indexes,indexes,(size_t)
1910 image->columns*sizeof(*transpose_indexes));
1911 }
1912 if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
1913 status=MagickFalse;
1914 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1915 {
1916 MagickBooleanType
1917 proceed;
1918
cristy629a6c72009-09-13 23:28:22 +00001919#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +00001920 #pragma omp critical (MagickCore_TransposeImage)
1921#endif
1922 proceed=SetImageProgress(image,TransposeImageTag,progress++,
1923 image->rows);
1924 if (proceed == MagickFalse)
1925 status=MagickFalse;
1926 }
1927 }
1928 transpose_view=DestroyCacheView(transpose_view);
1929 image_view=DestroyCacheView(image_view);
1930 transpose_image->type=image->type;
1931 page=transpose_image->page;
1932 Swap(page.width,page.height);
1933 Swap(page.x,page.y);
1934 if (page.width != 0)
1935 page.x=(long) (page.width-transpose_image->columns-page.x);
1936 transpose_image->page=page;
1937 if (status == MagickFalse)
1938 transpose_image=DestroyImage(transpose_image);
1939 return(transpose_image);
1940}
1941
1942/*
1943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944% %
1945% %
1946% %
1947% T r a n s v e r s e I m a g e %
1948% %
1949% %
1950% %
1951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1952%
1953% TransverseImage() creates a vertical mirror image by reflecting the pixels
1954% around the central x-axis while rotating them by 270 degrees.
1955%
1956% The format of the TransverseImage method is:
1957%
1958% Image *TransverseImage(const Image *image,ExceptionInfo *exception)
1959%
1960% A description of each parameter follows:
1961%
1962% o image: the image.
1963%
1964% o exception: return any errors or warnings in this structure.
1965%
1966*/
1967MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
1968{
1969#define TransverseImageTag "Transverse/Image"
1970
1971 Image
1972 *transverse_image;
1973
1974 long
1975 progress,
1976 y;
1977
1978 MagickBooleanType
1979 status;
1980
1981 RectangleInfo
1982 page;
1983
1984 CacheView
1985 *image_view,
1986 *transverse_view;
1987
1988 assert(image != (const Image *) NULL);
1989 assert(image->signature == MagickSignature);
1990 if (image->debug != MagickFalse)
1991 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1992 assert(exception != (ExceptionInfo *) NULL);
1993 assert(exception->signature == MagickSignature);
1994 transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
1995 exception);
1996 if (transverse_image == (Image *) NULL)
1997 return((Image *) NULL);
1998 /*
1999 Transverse image.
2000 */
2001 status=MagickTrue;
2002 progress=0;
2003 image_view=AcquireCacheView(image);
2004 transverse_view=AcquireCacheView(transverse_image);
cristy629a6c72009-09-13 23:28:22 +00002005#if defined(_OPENMP) && (_OPENMP >= 200203)
cristye0f584d2009-10-11 00:59:14 +00002006 #pragma omp parallel for shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002007#endif
2008 for (y=0; y < (long) image->rows; y++)
2009 {
2010 MagickBooleanType
2011 sync;
2012
2013 register const PixelPacket
2014 *__restrict p;
2015
2016 register IndexPacket
2017 *__restrict transverse_indexes,
2018 *__restrict indexes;
2019
2020 register long
2021 x;
2022
2023 register PixelPacket
2024 *__restrict q;
2025
2026 if (status == MagickFalse)
2027 continue;
2028 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2029 q=QueueCacheViewAuthenticPixels(transverse_view,(long) (image->rows-y-
2030 1),0,1,transverse_image->rows,exception);
2031 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
2032 {
2033 status=MagickFalse;
2034 continue;
2035 }
2036 q+=image->columns;
2037 for (x=0; x < (long) image->columns; x++)
2038 *--q=(*p++);
2039 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2040 if (indexes != (IndexPacket *) NULL)
2041 {
2042 transverse_indexes=GetCacheViewAuthenticIndexQueue(transverse_view);
2043 if (transverse_indexes != (IndexPacket *) NULL)
2044 for (x=0; x < (long) image->columns; x++)
2045 transverse_indexes[image->columns-x-1]=indexes[x];
2046 }
2047 sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
2048 if (sync == MagickFalse)
2049 status=MagickFalse;
2050 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2051 {
2052 MagickBooleanType
2053 proceed;
2054
cristy629a6c72009-09-13 23:28:22 +00002055#if defined(_OPENMP) && (_OPENMP >= 200203)
cristy3ed852e2009-09-05 21:47:34 +00002056 #pragma omp critical (MagickCore_TransverseImage)
2057#endif
2058 proceed=SetImageProgress(image,TransverseImageTag,progress++,
2059 image->rows);
2060 if (proceed == MagickFalse)
2061 status=MagickFalse;
2062 }
2063 }
2064 transverse_view=DestroyCacheView(transverse_view);
2065 image_view=DestroyCacheView(image_view);
2066 transverse_image->type=image->type;
2067 page=transverse_image->page;
2068 Swap(page.width,page.height);
2069 Swap(page.x,page.y);
2070 if (page.height != 0)
2071 page.y=(long) (page.height-transverse_image->rows-page.y);
2072 transverse_image->page=page;
2073 if (status == MagickFalse)
2074 transverse_image=DestroyImage(transverse_image);
2075 return(transverse_image);
2076}
2077
2078/*
2079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2080% %
2081% %
2082% %
2083% T r i m I m a g e %
2084% %
2085% %
2086% %
2087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2088%
2089% TrimImage() trims pixels from the image edges. It allocates the memory
2090% necessary for the new Image structure and returns a pointer to the new
2091% image.
2092%
2093% The format of the TrimImage method is:
2094%
2095% Image *TrimImage(const Image *image,ExceptionInfo *exception)
2096%
2097% A description of each parameter follows:
2098%
2099% o image: the image.
2100%
2101% o exception: return any errors or warnings in this structure.
2102%
2103*/
2104MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
2105{
2106 RectangleInfo
2107 geometry;
2108
2109 assert(image != (const Image *) NULL);
2110 assert(image->signature == MagickSignature);
2111 if (image->debug != MagickFalse)
2112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2113 geometry=GetImageBoundingBox(image,exception);
2114 if ((geometry.width == 0) || (geometry.height == 0))
2115 {
2116 Image
2117 *crop_image;
2118
2119 crop_image=CloneImage(image,1,1,MagickTrue,exception);
2120 if (crop_image == (Image *) NULL)
2121 return((Image *) NULL);
2122 crop_image->background_color.opacity=(Quantum) TransparentOpacity;
2123 (void) SetImageBackgroundColor(crop_image);
2124 crop_image->page=image->page;
2125 crop_image->page.x=(-1);
2126 crop_image->page.y=(-1);
2127 return(crop_image);
2128 }
2129 geometry.x+=image->page.x;
2130 geometry.y+=image->page.y;
2131 return(CropImage(image,&geometry,exception));
2132}