2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14
% TTTTT RRRR AAA N N SSSSS FFFFF OOO RRRR M M %
15
% T R R A A NN N SS F O O R R MM MM %
16
% T RRRR AAAAA N N N SSS FFF O O RRRR M M M %
17
% T R R A A N NN SS F O O R R M M %
18
% T R R A A N N SSSSS F OOO R R M M %
21
% GraphicsMagick Image Transform Methods %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
#include "magick/studio.h"
40
#include "magick/cache.h"
41
#include "magick/color.h"
42
#include "magick/composite.h"
43
#include "magick/monitor.h"
44
#include "magick/resize.h"
45
#include "magick/transform.h"
46
#include "magick/quantize.h"
47
#include "magick/utility.h"
48
#include "magick/log.h"
50
#if defined(HAVE_LCMS_LCMS_H)
51
#include <lcms/lcms.h>
58
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68
% Chop() removes a region of an image and collapses the image to occupy the
71
% The format of the ChopImage method is:
73
% Image *ChopImage(const Image *image,const RectangleInfo *chop_info
74
% ExceptionInfo *exception)
76
% A description of each parameter follows:
80
% o chop_info: Define the region of the image to chop.
82
% o exception: Return any errors or warnings in this structure.
86
MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
87
ExceptionInfo *exception)
89
#define ChopImageText " Chop image... "
101
register const PixelPacket
118
assert(image != (const Image *) NULL);
119
assert(image->signature == MagickSignature);
120
assert(exception != (ExceptionInfo *) NULL);
121
assert(exception->signature == MagickSignature);
122
assert(chop_info != (RectangleInfo *) NULL);
123
if (((chop_info->x+(long) chop_info->width) < 0) ||
124
((chop_info->y+(long) chop_info->height) < 0) ||
125
(chop_info->x > (long) image->columns) ||
126
(chop_info->y > (long) image->rows))
127
ThrowImageException3(OptionError,GeometryDoesNotContainImage,
129
clone_info=(*chop_info);
130
if ((clone_info.x+(long) clone_info.width) > (long) image->columns)
131
clone_info.width=(unsigned long) ((long) image->columns-clone_info.x);
132
if ((clone_info.y+(long) clone_info.height) > (long) image->rows)
133
clone_info.height=(unsigned long) ((long) image->rows-clone_info.y);
134
if (clone_info.x < 0)
136
clone_info.width-=(unsigned long) (-clone_info.x);
139
if (clone_info.y < 0)
141
clone_info.height-=(unsigned long) (-clone_info.y);
145
Initialize chop image attributes.
147
chop_image=CloneImage(image,image->columns-clone_info.width,
148
image->rows-clone_info.height,False,exception);
149
if (chop_image == (Image *) NULL)
150
return((Image *) NULL);
156
for (y=0; y < (long) clone_info.y; y++)
158
p=AcquireImagePixels(image,0,i++,image->columns,1,exception);
159
q=SetImagePixels(chop_image,0,j++,chop_image->columns,1);
160
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
162
indexes=GetIndexes(image);
163
chop_indexes=GetIndexes(chop_image);
164
for (x=0; x < (long) image->columns; x++)
166
if ((x < clone_info.x) || (x >= (long) (clone_info.x+clone_info.width)))
168
if ((indexes != (IndexPacket *) NULL) &&
169
(chop_indexes != (IndexPacket *) NULL))
170
*chop_indexes++=indexes[x];
176
if (!SyncImagePixels(chop_image))
178
if (QuantumTick(y,image->rows))
179
if (!MagickMonitor(ChopImageText,y,image->rows,exception))
185
i+=clone_info.height;
186
for (y=0; y < (long) (image->rows-(clone_info.y+clone_info.height)); y++)
188
p=AcquireImagePixels(image,0,i++,image->columns,1,exception);
189
q=SetImagePixels(chop_image,0,j++,chop_image->columns,1);
190
if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
192
indexes=GetIndexes(image);
193
chop_indexes=GetIndexes(chop_image);
194
for (x=0; x < (long) image->columns; x++)
196
if ((x < clone_info.x) || (x >= (long) (clone_info.x+clone_info.width)))
198
if ((indexes != (IndexPacket *) NULL) &&
199
(chop_indexes != (IndexPacket *) NULL))
200
*chop_indexes++=indexes[x];
206
if (!SyncImagePixels(chop_image))
208
if (QuantumTick(i,image->rows))
209
if (!MagickMonitor(ChopImageText,i,image->rows,exception))
212
chop_image->is_grayscale=image->is_grayscale;
217
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220
% C o a l e s c e I m a g e s %
224
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226
% CoalesceImages() composites a set of images while respecting any page
227
% offsets and disposal methods. GIF, MIFF, and MNG animation sequences
228
% typically start with an image background and each subsequent image
229
% varies in size and offset. CoalesceImages() returns a new sequence
230
% where each image in the sequence is the same size as the first and
231
% composited with the next image in the sequence.
233
% The format of the CoalesceImages method is:
235
% Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
237
% A description of each parameter follows:
239
% o image: The image sequence.
241
% o exception: Return any errors or warnings in this structure.
244
MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
254
Coalesce the image sequence.
256
assert(image != (Image *) NULL);
257
assert(image->signature == MagickSignature);
258
assert(exception != (ExceptionInfo *) NULL);
259
assert(exception->signature == MagickSignature);
260
if (image->next == (Image *) NULL)
261
ThrowImageException3(ImageError,ImageSequenceIsRequired,
262
UnableToCoalesceImage);
264
Clone first image in sequence.
266
coalesce_image=CloneImage(image,0,0,True,exception);
267
if (coalesce_image == (Image *) NULL)
268
return((Image *) NULL);
269
(void) memset(&coalesce_image->page,0,sizeof(RectangleInfo));
270
previous_image=coalesce_image;
274
for (next=image->next; next != (Image *) NULL; next=next->next)
276
switch (next->dispose)
278
case UndefinedDispose:
281
coalesce_image->next=CloneImage(coalesce_image,0,0,True,exception);
282
if (coalesce_image->next != (Image *) NULL)
283
previous_image=coalesce_image;
286
case BackgroundDispose:
288
coalesce_image->next=CloneImage(coalesce_image,0,0,True,exception);
289
if (coalesce_image->next != (Image *) NULL)
290
SetImage(coalesce_image->next,OpaqueOpacity);
293
case PreviousDispose:
296
coalesce_image->next=CloneImage(previous_image,0,0,True,exception);
300
if (coalesce_image->next == (Image *) NULL)
302
DestroyImageList(coalesce_image);
303
return((Image *) NULL);
305
coalesce_image->next->previous=coalesce_image;
306
coalesce_image=coalesce_image->next;
307
coalesce_image->delay=next->delay;
308
coalesce_image->start_loop=next->start_loop;
309
(void) CompositeImage(coalesce_image,next->matte ? OverCompositeOp :
310
CopyCompositeOp,next,next->page.x,next->page.y);
312
while (coalesce_image->previous != (Image *) NULL)
313
coalesce_image=coalesce_image->previous;
314
return(coalesce_image);
318
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322
% C r o p I m a g e %
326
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328
% Use CropImage() to extract a region of the image starting at the offset
329
% defined by geometry.
331
% The format of the CropImage method is:
333
% Image *CropImage(const Image *image,const RectangleInfo *geometry,
334
% ExceptionInfo *exception)
336
% A description of each parameter follows:
338
% o image: The image.
340
% o geometry: Define the region of the image to crop with members
341
% x, y, width, and height.
343
% o exception: Return any errors or warnings in this structure.
347
MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
348
ExceptionInfo *exception)
350
#define CropImageText " Crop image... "
361
register const PixelPacket
374
assert(image != (const Image *) NULL);
375
assert(image->signature == MagickSignature);
376
assert(geometry != (const RectangleInfo *) NULL);
377
assert(exception != (ExceptionInfo *) NULL);
378
assert(exception->signature == MagickSignature);
379
if ((geometry->width != 0) || (geometry->height != 0))
381
if (((geometry->x+(long) geometry->width) < 0) ||
382
((geometry->y+(long) geometry->height) < 0) ||
383
(geometry->x >= (long) image->columns) ||
384
(geometry->y >= (long) image->rows))
385
ThrowImageException(OptionError,GeometryDoesNotContainImage,
386
MagickMsg(ResourceLimitError,UnableToCropImage));
389
if ((page.width != 0) || (page.height != 0))
391
if ((page.x+(long) page.width) > (long) image->columns)
392
page.width=image->columns-page.x;
393
if ((page.y+(long) page.height) > (long) image->rows)
394
page.height=image->rows-page.y;
409
Set bounding box to the image dimensions.
411
page=GetImageBoundingBox(image,exception);
412
page.width+=geometry->x*2;
413
page.height+=geometry->y*2;
420
if ((((long) page.width+page.x) > (long) image->columns) ||
421
(((long) page.height+page.y) > (long) image->rows))
422
ThrowImageException(OptionError,GeometryDoesNotContainImage,
423
MagickMsg(ResourceLimitError,UnableToCropImage));
425
if ((page.width == 0) || (page.height == 0))
426
ThrowImageException(OptionError,GeometryDimensionsAreZero,
427
MagickMsg(ResourceLimitError,UnableToCropImage));
428
if ((page.width == image->columns) && (page.height == image->rows) &&
429
(page.x == 0) && (page.y == 0))
430
return(CloneImage(image,0,0,True,exception));
432
Initialize crop image attributes.
434
crop_image=CloneImage(image,page.width,page.height,True,exception);
435
if (crop_image == (Image *) NULL)
436
return((Image *) NULL);
440
crop_image->page=page;
441
if ((geometry->width == 0) || (geometry->height == 0))
442
memset(&crop_image->page,0,sizeof(RectangleInfo));
443
for (y=0; y < (long) crop_image->rows; y++)
445
p=AcquireImagePixels(image,page.x,page.y+y,crop_image->columns,1,exception);
446
q=SetImagePixels(crop_image,0,y,crop_image->columns,1);
447
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
449
(void) memcpy(q,p,crop_image->columns*sizeof(PixelPacket));
450
indexes=GetIndexes(image);
451
crop_indexes=GetIndexes(crop_image);
452
if ((indexes != (IndexPacket *) NULL) &&
453
(crop_indexes != (IndexPacket *) NULL))
454
(void) memcpy(crop_indexes,indexes,crop_image->columns*
455
sizeof(IndexPacket));
456
if (!SyncImagePixels(crop_image))
458
if (QuantumTick(y,crop_image->rows))
459
if (!MagickMonitor(CropImageText,y,crop_image->rows-1,exception))
462
if (y < (long) crop_image->rows)
464
DestroyImage(crop_image);
465
return((Image *) NULL);
467
crop_image->is_grayscale=image->is_grayscale;
472
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475
% D e c o n s t r u c t I m a g e s %
479
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481
% DeconstructImages() compares each image with the next in a sequence and
482
% returns the maximum bounding region of any pixel differences it discovers.
484
% The format of the DeconstructImages method is:
486
% Image *DeconstructImages(const Image *image,ExceptionInfo *exception)
488
% A description of each parameter follows:
490
% o image: The image.
492
% o exception: Return any errors or warnings in this structure.
496
MagickExport Image *DeconstructImages(const Image *image,
497
ExceptionInfo *exception)
513
register const PixelPacket
523
assert(image != (const Image *) NULL);
524
assert(image->signature == MagickSignature);
525
assert(exception != (ExceptionInfo *) NULL);
526
assert(exception->signature == MagickSignature);
527
if (image->next == (Image *) NULL)
528
ThrowImageException3(ImageError,ImageSequenceIsRequired,
529
UnableToDeconstructImageSequence);
531
Ensure the image are the same size.
533
for (next=image; next != (Image *) NULL; next=next->next)
535
if ((next->columns != image->columns) || (next->rows != image->rows))
536
ThrowImageException(OptionError,ImagesAreNotTheSameSize,
537
MagickMsg(ImageError,UnableToDeconstructImageSequence));
542
bounds=MagickAllocateMemory(RectangleInfo *,
543
GetImageListLength(image)*sizeof(RectangleInfo));
544
if (bounds == (RectangleInfo *) NULL)
545
ThrowImageException(ResourceLimitError,MemoryAllocationFailed,
546
MagickMsg(ImageError,UnableToDeconstructImageSequence));
548
Compute the bounding box for each next in the sequence.
551
for (next=image->next; next != (const Image *) NULL; next=next->next)
554
Set bounding box to the next dimensions.
556
for (x=0; x < (long) next->columns; x++)
558
p=AcquireImagePixels(next,x,0,1,next->rows,exception);
559
q=GetImagePixels(next->previous,x,0,1,next->previous->rows);
560
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
562
for (y=0; y < (long) next->rows; y++)
564
if (!FuzzyColorMatch(p,q,next->fuzz))
569
if (y < (long) next->rows)
573
for (y=0; y < (long) next->rows; y++)
575
p=AcquireImagePixels(next,0,y,next->columns,1,exception);
576
q=GetImagePixels(next->previous,0,y,next->previous->columns,1);
577
if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
579
for (x=0; x < (long) next->columns; x++)
581
if (!FuzzyColorMatch(p,q,next->fuzz))
586
if (x < (long) next->columns)
590
for (x=(long) next->columns-1; x >= 0; x--)
592
p=AcquireImagePixels(next,x,0,1,next->rows,exception);
593
q=GetImagePixels(next->previous,x,0,1,next->previous->rows);
594
if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
596
for (y=0; y < (long) next->rows; y++)
598
if (!FuzzyColorMatch(p,q,next->fuzz))
603
if (y < (long) next->rows)
606
bounds[i].width=x-bounds[i].x+1;
607
for (y=(long) next->rows-1; y >= 0; y--)
609
p=AcquireImagePixels(next,0,y,next->columns,1,exception);
610
q=GetImagePixels(next->previous,0,y,next->previous->columns,1);
611
if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
613
for (x=0; x < (long) next->columns; x++)
615
if (!FuzzyColorMatch(p,q,next->fuzz))
620
if (x < (long) next->columns)
623
bounds[i].height=y-bounds[i].y+1;
627
Clone first image in sequence.
629
deconstruct_image=CloneImage(image,0,0,True,exception);
630
if (deconstruct_image == (Image *) NULL)
632
MagickFreeMemory(bounds);
633
return((Image *) NULL);
636
Deconstruct the image sequence.
639
for (next=image->next; next != (Image *) NULL; next=next->next)
641
crop_image=CloneImage(next,0,0,True,exception);
642
if (crop_image == (Image *) NULL)
644
crop_next=CropImage(crop_image,&bounds[i++],exception);
645
DestroyImage(crop_image);
646
if (crop_next == (Image *) NULL)
648
deconstruct_image->next=crop_next;
649
crop_next->previous=deconstruct_image;
650
deconstruct_image=deconstruct_image->next;
652
MagickFreeMemory(bounds);
653
while (deconstruct_image->previous != (Image *) NULL)
654
deconstruct_image=deconstruct_image->previous;
655
if (next != (Image *) NULL)
657
DestroyImageList(deconstruct_image);
658
return((Image *) NULL);
660
return(deconstruct_image);
664
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
667
% F l a t t e n I m a g e %
671
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673
% Method FlattenImage merges a sequence of images. This is useful for
674
% combining Photoshop layers into a single image.
676
% The format of the FlattenImage method is:
678
% Image *FlattenImage(const Image *image,ExceptionInfo *exception)
680
% A description of each parameter follows:
682
% o image: The image sequence.
684
% o exception: Return any errors or warnings in this structure.
687
MagickExport Image *FlattenImages(const Image *image,ExceptionInfo *exception)
696
Flatten the image sequence.
698
assert(image != (Image *) NULL);
699
assert(image->signature == MagickSignature);
700
assert(exception != (ExceptionInfo *) NULL);
701
assert(exception->signature == MagickSignature);
702
if (image->next == (Image *) NULL)
703
ThrowImageException3(ImageError,ImageSequenceIsRequired,
704
UnableToFlattenImage);
706
Clone first image in sequence.
708
flatten_image=CloneImage(image,0,0,True,exception);
709
if (flatten_image == (Image *) NULL)
710
return((Image *) NULL);
714
for (next=image->next; next != (Image *) NULL; next=next->next)
715
(void) CompositeImage(flatten_image,next->compose,next,next->page.x,
717
return(flatten_image);
721
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725
% F l i p I m a g e %
729
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731
% FlipImage() creates a vertical mirror image by reflecting the pixels
732
% around the central x-axis.
734
% The format of the FlipImage method is:
736
% Image *FlipImage(const Image *image,ExceptionInfo *exception)
738
% A description of each parameter follows:
740
% o image: The image.
742
% o exception: Return any errors or warnings in this structure.
746
MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
748
#define FlipImageText " Flip image... "
756
register const PixelPacket
770
Initialize flip image attributes.
772
assert(image != (const Image *) NULL);
773
assert(image->signature == MagickSignature);
774
assert(exception != (ExceptionInfo *) NULL);
775
assert(exception->signature == MagickSignature);
776
flip_image=CloneImage(image,image->columns,image->rows,True,exception);
777
if (flip_image == (Image *) NULL)
778
return((Image *) NULL);
782
for (y=0; y < (long) flip_image->rows; y++)
784
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
785
q=GetImagePixels(flip_image,0,(long) (flip_image->rows-y-1),
786
flip_image->columns,1);
787
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
789
(void) memcpy(q,p,flip_image->columns*sizeof(PixelPacket));
790
indexes=GetIndexes(image);
791
flip_indexes=GetIndexes(flip_image);
792
if ((indexes != (IndexPacket *) NULL) &&
793
(flip_indexes != (IndexPacket *) NULL))
794
(void) memcpy(flip_indexes,indexes,image->columns*sizeof(IndexPacket));
795
status=SyncImagePixels(flip_image);
798
if (QuantumTick(y,flip_image->rows))
799
if (!MagickMonitor(FlipImageText,y,flip_image->rows,exception))
802
flip_image->is_grayscale=image->is_grayscale;
807
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811
% F l o p I m a g e %
815
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817
% FlopImage() creates a horizontal mirror image by reflecting the pixels
818
% around the central y-axis.
820
% The format of the FlopImage method is:
822
% Image *FlopImage(const Image *image,ExceptionInfo *exception)
824
% A description of each parameter follows:
826
% o image: The image.
828
% o exception: Return any errors or warnings in this structure.
832
MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
834
#define FlopImageText " Flop image... "
846
register const PixelPacket
859
Initialize flop image attributes.
861
assert(image != (const Image *) NULL);
862
assert(image->signature == MagickSignature);
863
assert(exception != (ExceptionInfo *) NULL);
864
assert(exception->signature == MagickSignature);
865
flop_image=CloneImage(image,image->columns,image->rows,True,exception);
866
if (flop_image == (Image *) NULL)
867
return((Image *) NULL);
871
for (y=0; y < (long) flop_image->rows; y++)
873
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
874
q=SetImagePixels(flop_image,0,y,flop_image->columns,1);
875
if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
877
indexes=GetIndexes(image);
878
flop_indexes=GetIndexes(flop_image);
879
q+=flop_image->columns;
880
for (x=0; x < (long) flop_image->columns; x++)
882
if ((indexes != (IndexPacket *) NULL) &&
883
(flop_indexes != (IndexPacket *) NULL))
884
flop_indexes[flop_image->columns-x-1]=indexes[x];
889
status=SyncImagePixels(flop_image);
892
if (QuantumTick(y,flop_image->rows))
893
if (!MagickMonitor(FlopImageText,y,flop_image->rows,exception))
896
flop_image->is_grayscale=image->is_grayscale;
901
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
905
% M o s a i c I m a g e s %
909
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911
% MosaicImages() inlays an image sequence to form a single coherent picture.
912
% It returns a single image with each image in the sequence composited at
913
% the location defined by the page member of the image structure.
915
% The format of the MosaicImage method is:
917
% Image *MosaicImages(const Image *image,ExceptionInfo *exception)
919
% A description of each parameter follows:
921
% o image: The image.
923
% o exception: Return any errors or warnings in this structure.
927
MagickExport Image *MosaicImages(const Image *image,ExceptionInfo *exception)
929
#define MosaicImageText " Create an image mosaic... "
945
Determine mosaic bounding box.
947
assert(image != (Image *) NULL);
948
assert(image->signature == MagickSignature);
949
assert(exception != (ExceptionInfo *) NULL);
950
assert(exception->signature == MagickSignature);
951
if (image->next == (Image *) NULL)
952
ThrowImageException3(ImageError,ImageSequenceIsRequired,
953
UnableToCreateImageMosaic);
954
page.width=image->columns;
955
page.height=image->rows;
958
for (next=image; next != (Image *) NULL; next=next->next)
962
if ((next->columns+page.x) > page.width)
963
page.width=next->columns+page.x;
964
if (next->page.width > page.width)
965
page.width=next->page.width;
966
if ((next->rows+page.y) > page.height)
967
page.height=next->rows+page.y;
968
if (next->page.height > page.height)
969
page.height=next->page.height;
972
Allocate mosaic image.
974
mosaic_image=AllocateImage((ImageInfo *) NULL);
975
if (mosaic_image == (Image *) NULL)
976
return((Image *) NULL);
977
mosaic_image->columns=page.width;
978
mosaic_image->rows=page.height;
979
SetImage(mosaic_image,OpaqueOpacity);
984
for (next=image; next != (Image *) NULL; next=next->next)
986
(void) CompositeImage(mosaic_image,CopyCompositeOp,next,next->page.x,
988
status=MagickMonitor(MosaicImageText,scene++,GetImageListLength(image),
993
return(mosaic_image);
997
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1001
% R o l l I m a g e %
1005
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007
% RollImage() offsets an image as defined by x_offset and y_offset.
1009
% The format of the RollImage method is:
1011
% Image *RollImage(const Image *image,const long x_offset,
1012
% const long y_offset,ExceptionInfo *exception)
1014
% A description of each parameter follows:
1016
% o image: The image.
1018
% o x_offset: The number of columns to roll in the horizontal direction.
1020
% o y_offset: The number of rows to roll in the vertical direction.
1022
% o exception: Return any errors or warnings in this structure.
1026
MagickExport Image *RollImage(const Image *image,const long x_offset,
1027
const long y_offset,ExceptionInfo *exception)
1029
#define RollImageText " Roll image... "
1037
register const PixelPacket
1040
register IndexPacket
1047
register PixelPacket
1054
Initialize roll image attributes.
1056
assert(image != (const Image *) NULL);
1057
assert(image->signature == MagickSignature);
1058
assert(exception != (ExceptionInfo *) NULL);
1059
assert(exception->signature == MagickSignature);
1060
roll_image=CloneImage(image,image->columns,image->rows,True,exception);
1061
if (roll_image == (Image *) NULL)
1062
return((Image *) NULL);
1068
while (offset.x < 0)
1069
offset.x+=image->columns;
1070
while (offset.x >= (long) image->columns)
1071
offset.x-=image->columns;
1072
while (offset.y < 0)
1073
offset.y+=image->rows;
1074
while (offset.y >= (long) image->rows)
1075
offset.y-=image->rows;
1076
for (y=0; y < (long) image->rows; y++)
1081
p=AcquireImagePixels(image,0,y,image->columns,1,exception);
1082
if (p == (const PixelPacket *) NULL)
1084
indexes=GetIndexes(image);
1085
for (x=0; x < (long) image->columns; x++)
1087
q=SetImagePixels(roll_image,(long) (offset.x+x) % image->columns,
1088
(long) (offset.y+y) % image->rows,1,1);
1089
if (q == (PixelPacket *) NULL)
1091
roll_indexes=GetIndexes(roll_image);
1092
if ((indexes != (IndexPacket *) NULL) &&
1093
(roll_indexes != (IndexPacket *) NULL))
1094
*roll_indexes=indexes[x];
1097
if (!SyncImagePixels(roll_image))
1100
if (QuantumTick(y,image->rows))
1101
if (!MagickMonitor(RollImageText,y,image->rows,exception))
1104
roll_image->is_grayscale=image->is_grayscale;
1109
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113
% S h a v e I m a g e %
1117
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119
% Method ShaveImage shaves pixels from the image edges. It allocates the
1120
% memory necessary for the new Image structure and returns a pointer to the
1123
% The format of the ShaveImage method is:
1125
% Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
1126
% ExceptionInfo *exception)
1128
% A description of each parameter follows:
1130
% o shave_image: Method ShaveImage returns a pointer to the shaved
1131
% image. A null image is returned if there is a memory shortage or
1132
% if the image width or height is zero.
1134
% o image: The image.
1136
% o shave_info: Specifies a pointer to a RectangleInfo which defines the
1137
% region of the image to crop.
1139
% o exception: Return any errors or warnings in this structure.
1143
MagickExport Image *ShaveImage(const Image *image,
1144
const RectangleInfo *shave_info,ExceptionInfo *exception)
1149
if (((2*shave_info->width) >= image->columns) ||
1150
((2*shave_info->height) >= image->rows))
1151
ThrowImageException(OptionError,GeometryDoesNotContainImage,
1152
MagickMsg(ResourceLimitError,UnableToShaveImage));
1153
SetGeometry(image,&geometry);
1154
geometry.width-=2*shave_info->width;
1155
geometry.height-=2*shave_info->height;
1156
geometry.x=(long) shave_info->width;
1157
geometry.y=(long) shave_info->height;
1158
return(CropImage(image,&geometry,exception));
1162
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166
% T r a n s f o r m I m a g e %
1170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172
% TransformImage() is a convenience method that behaves like ResizeImage() or
1173
% CropImage() but accepts scaling and/or cropping information as a region
1174
% geometry specification. If the operation fails, the original image handle
1177
% The format of the TransformImage method is:
1179
% void TransformImage(Image **image,const char *crop_geometry,
1180
% const char *image_geometry)
1182
% A description of each parameter follows:
1184
% o image: The image The transformed image is returned as this parameter.
1186
% o crop_geometry: A crop geometry string. This geometry defines a
1187
% subregion of the image to crop.
1189
% o image_geometry: An image geometry string. This geometry defines the
1190
% final size of the image.
1194
MagickExport void TransformImage(Image **image,const char *crop_geometry,
1195
const char *image_geometry)
1207
assert(image != (Image **) NULL);
1208
assert((*image)->signature == MagickSignature);
1209
transform_image=(*image);
1210
if (crop_geometry != (const char *) NULL)
1219
Crop image to a user specified size.
1221
crop_image=(Image *) NULL;
1222
flags=GetImageGeometry(transform_image,crop_geometry,False,&geometry);
1223
if ((geometry.width == 0) || (geometry.height == 0) ||
1224
((flags & XValue) != 0) || ((flags & YValue) != 0) ||
1225
(flags & PercentValue))
1226
crop_image=CropImage(transform_image,&geometry,&(*image)->exception);
1228
if ((transform_image->columns > geometry.width) ||
1229
(transform_image->rows > geometry.height))
1243
Crop repeatedly to create uniform subimages.
1245
width=geometry.width;
1246
height=geometry.height;
1247
next=(Image *) NULL;
1248
for (y=0; y < (long) transform_image->rows; y+=height)
1250
for (x=0; x < (long) transform_image->columns; x+=width)
1252
geometry.width=width;
1253
geometry.height=height;
1256
next=CropImage(transform_image,&geometry,&(*image)->exception);
1257
if (next == (Image *) NULL)
1259
if (crop_image == (Image *) NULL)
1263
next->previous=crop_image;
1264
crop_image->next=next;
1265
crop_image=crop_image->next;
1268
if (next == (Image *) NULL)
1272
if (crop_image != (Image *) NULL)
1274
DestroyImage(transform_image);
1275
while (crop_image->previous != (Image *) NULL)
1276
crop_image=crop_image->previous;
1277
transform_image=crop_image;
1279
*image=transform_image;
1281
if (image_geometry == (const char *) NULL)
1284
Scale image to a user specified size.
1286
SetGeometry(transform_image,&geometry);
1287
flags=GetMagickGeometry(image_geometry,&geometry.x,&geometry.y,
1288
&geometry.width,&geometry.height);
1289
if ((transform_image->columns == geometry.width) &&
1290
(transform_image->rows == geometry.height))
1295
resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
1296
&(*image)->exception);
1297
if (resize_image == (Image *) NULL)
1299
DestroyImage(transform_image);
1300
transform_image=resize_image;
1301
*image=transform_image;