~ubuntu-branches/ubuntu/intrepid/graphicsmagick/intrepid

« back to all changes in this revision

Viewing changes to magick/transform.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2006-05-06 16:28:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060506162808-vt2ni3r5nytcszms
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
% Copyright (C) 2003 GraphicsMagick Group
 
3
% Copyright (C) 2002 ImageMagick Studio
 
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
 
5
%
 
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.
 
9
%
 
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
11
%                                                                             %
 
12
%                                                                             %
 
13
%                                                                             %
 
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         %
 
19
%                                                                             %
 
20
%                                                                             %
 
21
%                   GraphicsMagick Image Transform Methods                    %
 
22
%                                                                             %
 
23
%                                                                             %
 
24
%                              Software Design                                %
 
25
%                                John Cristy                                  %
 
26
%                                 July 1992                                   %
 
27
%                                                                             %
 
28
%                                                                             %
 
29
%                                                                             %
 
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
31
%
 
32
%
 
33
%
 
34
*/
 
35
 
 
36
/*
 
37
  Include declarations.
 
38
*/
 
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"
 
49
#if defined(HasLCMS)
 
50
#if defined(HAVE_LCMS_LCMS_H)
 
51
#include <lcms/lcms.h>
 
52
#else
 
53
#include "lcms.h"
 
54
#endif
 
55
#endif
 
56
 
 
57
/*
 
58
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
59
%                                                                             %
 
60
%                                                                             %
 
61
%                                                                             %
 
62
%   C h o p I m a g e                                                         %
 
63
%                                                                             %
 
64
%                                                                             %
 
65
%                                                                             %
 
66
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
67
%
 
68
%  Chop() removes a region of an image and collapses the image to occupy the
 
69
%  removed portion.
 
70
%
 
71
%  The format of the ChopImage method is:
 
72
%
 
73
%      Image *ChopImage(const Image *image,const RectangleInfo *chop_info
 
74
%        ExceptionInfo *exception)
 
75
%
 
76
%  A description of each parameter follows:
 
77
%
 
78
%    o image: The image.
 
79
%
 
80
%    o chop_info: Define the region of the image to chop.
 
81
%
 
82
%    o exception: Return any errors or warnings in this structure.
 
83
%
 
84
%
 
85
*/
 
86
MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
 
87
  ExceptionInfo *exception)
 
88
{
 
89
#define ChopImageText  "  Chop image...  "
 
90
 
 
91
  Image
 
92
    *chop_image;
 
93
 
 
94
  long
 
95
    j,
 
96
    y;
 
97
 
 
98
  RectangleInfo
 
99
    clone_info;
 
100
 
 
101
  register const PixelPacket
 
102
    *p;
 
103
 
 
104
  register IndexPacket
 
105
    *chop_indexes,
 
106
    *indexes;
 
107
 
 
108
  register long
 
109
    i,
 
110
    x;
 
111
 
 
112
  register PixelPacket
 
113
    *q;
 
114
 
 
115
  /*
 
116
    Check chop geometry.
 
117
  */
 
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,
 
128
      UnableToChopImage);
 
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)
 
135
    {
 
136
      clone_info.width-=(unsigned long) (-clone_info.x);
 
137
      clone_info.x=0;
 
138
    }
 
139
  if (clone_info.y < 0)
 
140
    {
 
141
      clone_info.height-=(unsigned long) (-clone_info.y);
 
142
      clone_info.y=0;
 
143
    }
 
144
  /*
 
145
    Initialize chop image attributes.
 
146
  */
 
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);
 
151
  /*
 
152
    Extract chop image.
 
153
  */
 
154
  i=0;
 
155
  j=0;
 
156
  for (y=0; y < (long) clone_info.y; y++)
 
157
  {
 
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))
 
161
      break;
 
162
    indexes=GetIndexes(image);
 
163
    chop_indexes=GetIndexes(chop_image);
 
164
    for (x=0; x < (long) image->columns; x++)
 
165
    {
 
166
      if ((x < clone_info.x) || (x >= (long) (clone_info.x+clone_info.width)))
 
167
        {
 
168
          if ((indexes != (IndexPacket *) NULL) &&
 
169
              (chop_indexes != (IndexPacket *) NULL))
 
170
            *chop_indexes++=indexes[x];
 
171
          *q=(*p);
 
172
          q++;
 
173
        }
 
174
      p++;
 
175
    }
 
176
    if (!SyncImagePixels(chop_image))
 
177
      break;
 
178
    if (QuantumTick(y,image->rows))
 
179
      if (!MagickMonitor(ChopImageText,y,image->rows,exception))
 
180
        break;
 
181
  }
 
182
  /*
 
183
    Extract chop image.
 
184
  */
 
185
  i+=clone_info.height;
 
186
  for (y=0; y < (long) (image->rows-(clone_info.y+clone_info.height)); y++)
 
187
  {
 
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))
 
191
      break;
 
192
    indexes=GetIndexes(image);
 
193
    chop_indexes=GetIndexes(chop_image);
 
194
    for (x=0; x < (long) image->columns; x++)
 
195
    {
 
196
      if ((x < clone_info.x) || (x >= (long) (clone_info.x+clone_info.width)))
 
197
        {
 
198
          if ((indexes != (IndexPacket *) NULL) &&
 
199
              (chop_indexes != (IndexPacket *) NULL))
 
200
            *chop_indexes++=indexes[x];
 
201
          *q=(*p);
 
202
          q++;
 
203
        }
 
204
      p++;
 
205
    }
 
206
    if (!SyncImagePixels(chop_image))
 
207
      break;
 
208
    if (QuantumTick(i,image->rows))
 
209
      if (!MagickMonitor(ChopImageText,i,image->rows,exception))
 
210
        break;
 
211
  }
 
212
  chop_image->is_grayscale=image->is_grayscale;
 
213
  return(chop_image);
 
214
}
 
215
 
 
216
/*
 
217
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
218
%                                                                             %
 
219
%                                                                             %
 
220
%     C o a l e s c e I m a g e s                                             %
 
221
%                                                                             %
 
222
%                                                                             %
 
223
%                                                                             %
 
224
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
225
%
 
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.
 
232
%
 
233
%  The format of the CoalesceImages method is:
 
234
%
 
235
%      Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
 
236
%
 
237
%  A description of each parameter follows:
 
238
%
 
239
%    o image: The image sequence.
 
240
%
 
241
%    o exception: Return any errors or warnings in this structure.
 
242
%
 
243
*/
 
244
MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
 
245
{
 
246
  Image
 
247
    *coalesce_image,
 
248
    *previous_image;
 
249
 
 
250
  register const Image
 
251
    *next;
 
252
 
 
253
  /*
 
254
    Coalesce the image sequence.
 
255
  */
 
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);
 
263
  /*
 
264
    Clone first image in sequence.
 
265
  */
 
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;
 
271
  /*
 
272
    Coalesce image.
 
273
  */
 
274
  for (next=image->next; next != (Image *) NULL; next=next->next)
 
275
  {
 
276
    switch (next->dispose)
 
277
    {
 
278
      case UndefinedDispose:
 
279
      case NoneDispose:
 
280
      {
 
281
        coalesce_image->next=CloneImage(coalesce_image,0,0,True,exception);
 
282
        if (coalesce_image->next != (Image *) NULL)
 
283
          previous_image=coalesce_image;
 
284
        break;
 
285
      }
 
286
      case BackgroundDispose:
 
287
      {
 
288
        coalesce_image->next=CloneImage(coalesce_image,0,0,True,exception);
 
289
        if (coalesce_image->next != (Image *) NULL)
 
290
          SetImage(coalesce_image->next,OpaqueOpacity);
 
291
        break;
 
292
      }
 
293
      case PreviousDispose:
 
294
      default:
 
295
      {
 
296
        coalesce_image->next=CloneImage(previous_image,0,0,True,exception);
 
297
        break;
 
298
      }
 
299
    }
 
300
    if (coalesce_image->next == (Image *) NULL)
 
301
      {
 
302
        DestroyImageList(coalesce_image);
 
303
        return((Image *) NULL);
 
304
      }
 
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);
 
311
  }
 
312
  while (coalesce_image->previous != (Image *) NULL)
 
313
    coalesce_image=coalesce_image->previous;
 
314
  return(coalesce_image);
 
315
}
 
316
 
 
317
/*
 
318
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
319
%                                                                             %
 
320
%                                                                             %
 
321
%                                                                             %
 
322
%   C r o p I m a g e                                                         %
 
323
%                                                                             %
 
324
%                                                                             %
 
325
%                                                                             %
 
326
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
327
%
 
328
%  Use CropImage() to extract a region of the image starting at the offset
 
329
%  defined by geometry.
 
330
%
 
331
%  The format of the CropImage method is:
 
332
%
 
333
%      Image *CropImage(const Image *image,const RectangleInfo *geometry,
 
334
%        ExceptionInfo *exception)
 
335
%
 
336
%  A description of each parameter follows:
 
337
%
 
338
%    o image: The image.
 
339
%
 
340
%    o geometry: Define the region of the image to crop with members
 
341
%      x, y, width, and height.
 
342
%
 
343
%    o exception: Return any errors or warnings in this structure.
 
344
%
 
345
%
 
346
*/
 
347
MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
 
348
  ExceptionInfo *exception)
 
349
{
 
350
#define CropImageText  "  Crop image...  "
 
351
 
 
352
  Image
 
353
    *crop_image;
 
354
 
 
355
  long
 
356
    y;
 
357
 
 
358
  RectangleInfo
 
359
    page;
 
360
 
 
361
  register const PixelPacket
 
362
    *p;
 
363
 
 
364
  register IndexPacket
 
365
    *crop_indexes,
 
366
    *indexes;
 
367
 
 
368
  register PixelPacket
 
369
    *q;
 
370
 
 
371
  /*
 
372
    Check crop geometry.
 
373
  */
 
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))
 
380
    {
 
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));
 
387
    }
 
388
  page=(*geometry);
 
389
  if ((page.width != 0) || (page.height != 0))
 
390
    {
 
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;
 
395
      if (page.x < 0)
 
396
        {
 
397
          page.width+=page.x;
 
398
          page.x=0;
 
399
        }
 
400
      if (page.y < 0)
 
401
        {
 
402
          page.height+=page.y;
 
403
          page.y=0;
 
404
        }
 
405
    }
 
406
  else
 
407
    {
 
408
      /*
 
409
        Set bounding box to the image dimensions.
 
410
      */
 
411
      page=GetImageBoundingBox(image,exception);
 
412
      page.width+=geometry->x*2;
 
413
      page.height+=geometry->y*2;
 
414
      page.x-=geometry->x;
 
415
      if (page.x < 0)
 
416
        page.x=0;
 
417
      page.y-=geometry->y;
 
418
      if (page.y < 0)
 
419
        page.y=0;
 
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));
 
424
    }
 
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));
 
431
  /*
 
432
    Initialize crop image attributes.
 
433
  */
 
434
  crop_image=CloneImage(image,page.width,page.height,True,exception);
 
435
  if (crop_image == (Image *) NULL)
 
436
    return((Image *) NULL);
 
437
  /*
 
438
    Extract crop image.
 
439
  */
 
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++)
 
444
  {
 
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))
 
448
      break;
 
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))
 
457
      break;
 
458
    if (QuantumTick(y,crop_image->rows))
 
459
      if (!MagickMonitor(CropImageText,y,crop_image->rows-1,exception))
 
460
        break;
 
461
  }
 
462
  if (y < (long) crop_image->rows)
 
463
    {
 
464
      DestroyImage(crop_image);
 
465
      return((Image *) NULL);
 
466
    }
 
467
  crop_image->is_grayscale=image->is_grayscale;
 
468
  return(crop_image);
 
469
}
 
470
 
 
471
/*
 
472
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
473
%                                                                             %
 
474
%                                                                             %
 
475
%     D e c o n s t r u c t I m a g e s                                       %
 
476
%                                                                             %
 
477
%                                                                             %
 
478
%                                                                             %
 
479
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
480
%
 
481
%  DeconstructImages() compares each image with the next in a sequence and
 
482
%  returns the maximum bounding region of any pixel differences it discovers.
 
483
%
 
484
%  The format of the DeconstructImages method is:
 
485
%
 
486
%      Image *DeconstructImages(const Image *image,ExceptionInfo *exception)
 
487
%
 
488
%  A description of each parameter follows:
 
489
%
 
490
%    o image: The image.
 
491
%
 
492
%    o exception: Return any errors or warnings in this structure.
 
493
%
 
494
%
 
495
*/
 
496
MagickExport Image *DeconstructImages(const Image *image,
 
497
  ExceptionInfo *exception)
 
498
{
 
499
  Image
 
500
    *crop_image,
 
501
    *crop_next,
 
502
    *deconstruct_image;
 
503
 
 
504
  long
 
505
    y;
 
506
 
 
507
  RectangleInfo
 
508
    *bounds;
 
509
 
 
510
  register const Image
 
511
    *next;
 
512
 
 
513
  register const PixelPacket
 
514
    *p;
 
515
 
 
516
  register long
 
517
    i,
 
518
    x;
 
519
 
 
520
  register PixelPacket
 
521
    *q;
 
522
 
 
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);
 
530
  /*
 
531
    Ensure the image are the same size.
 
532
  */
 
533
  for (next=image; next != (Image *) NULL; next=next->next)
 
534
  {
 
535
    if ((next->columns != image->columns) || (next->rows != image->rows))
 
536
      ThrowImageException(OptionError,ImagesAreNotTheSameSize,
 
537
        MagickMsg(ImageError,UnableToDeconstructImageSequence));
 
538
  }
 
539
  /*
 
540
    Allocate memory.
 
541
  */
 
542
  bounds=MagickAllocateMemory(RectangleInfo *,
 
543
    GetImageListLength(image)*sizeof(RectangleInfo));
 
544
  if (bounds == (RectangleInfo *) NULL)
 
545
    ThrowImageException(ResourceLimitError,MemoryAllocationFailed,
 
546
      MagickMsg(ImageError,UnableToDeconstructImageSequence));
 
547
  /*
 
548
    Compute the bounding box for each next in the sequence.
 
549
  */
 
550
  i=0;
 
551
  for (next=image->next; next != (const Image *) NULL; next=next->next)
 
552
  {
 
553
    /*
 
554
      Set bounding box to the next dimensions.
 
555
    */
 
556
    for (x=0; x < (long) next->columns; x++)
 
557
    {
 
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))
 
561
        break;
 
562
      for (y=0; y < (long) next->rows; y++)
 
563
      {
 
564
        if (!FuzzyColorMatch(p,q,next->fuzz))
 
565
          break;
 
566
        p++;
 
567
        q++;
 
568
      }
 
569
      if (y < (long) next->rows)
 
570
        break;
 
571
    }
 
572
    bounds[i].x=x;
 
573
    for (y=0; y < (long) next->rows; y++)
 
574
    {
 
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))
 
578
        break;
 
579
      for (x=0; x < (long) next->columns; x++)
 
580
      {
 
581
        if (!FuzzyColorMatch(p,q,next->fuzz))
 
582
          break;
 
583
        p++;
 
584
        q++;
 
585
      }
 
586
      if (x < (long) next->columns)
 
587
        break;
 
588
    }
 
589
    bounds[i].y=y;
 
590
    for (x=(long) next->columns-1; x >= 0; x--)
 
591
    {
 
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))
 
595
        break;
 
596
      for (y=0; y < (long) next->rows; y++)
 
597
      {
 
598
        if (!FuzzyColorMatch(p,q,next->fuzz))
 
599
          break;
 
600
        p++;
 
601
        q++;
 
602
      }
 
603
      if (y < (long) next->rows)
 
604
        break;
 
605
    }
 
606
    bounds[i].width=x-bounds[i].x+1;
 
607
    for (y=(long) next->rows-1; y >= 0; y--)
 
608
    {
 
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))
 
612
        break;
 
613
      for (x=0; x < (long) next->columns; x++)
 
614
      {
 
615
        if (!FuzzyColorMatch(p,q,next->fuzz))
 
616
          break;
 
617
        p++;
 
618
        q++;
 
619
      }
 
620
      if (x < (long) next->columns)
 
621
        break;
 
622
    }
 
623
    bounds[i].height=y-bounds[i].y+1;
 
624
    i++;
 
625
  }
 
626
  /*
 
627
    Clone first image in sequence.
 
628
  */
 
629
  deconstruct_image=CloneImage(image,0,0,True,exception);
 
630
  if (deconstruct_image == (Image *) NULL)
 
631
    {
 
632
      MagickFreeMemory(bounds);
 
633
      return((Image *) NULL);
 
634
    }
 
635
  /*
 
636
    Deconstruct the image sequence.
 
637
  */
 
638
  i=0;
 
639
  for (next=image->next; next != (Image *) NULL; next=next->next)
 
640
  {
 
641
    crop_image=CloneImage(next,0,0,True,exception);
 
642
    if (crop_image == (Image *) NULL)
 
643
      break;
 
644
    crop_next=CropImage(crop_image,&bounds[i++],exception);
 
645
    DestroyImage(crop_image);
 
646
    if (crop_next == (Image *) NULL)
 
647
      break;
 
648
    deconstruct_image->next=crop_next;
 
649
    crop_next->previous=deconstruct_image;
 
650
    deconstruct_image=deconstruct_image->next;
 
651
  }
 
652
  MagickFreeMemory(bounds);
 
653
  while (deconstruct_image->previous != (Image *) NULL)
 
654
    deconstruct_image=deconstruct_image->previous;
 
655
  if (next != (Image *) NULL)
 
656
    {
 
657
      DestroyImageList(deconstruct_image);
 
658
      return((Image *) NULL);
 
659
    }
 
660
  return(deconstruct_image);
 
661
}
 
662
 
 
663
/*
 
664
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
665
%                                                                             %
 
666
%                                                                             %
 
667
%     F l a t t e n I m a g e                                                 %
 
668
%                                                                             %
 
669
%                                                                             %
 
670
%                                                                             %
 
671
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
672
%
 
673
%  Method FlattenImage merges a sequence of images.  This is useful for
 
674
%  combining Photoshop layers into a single image.
 
675
%
 
676
%  The format of the FlattenImage method is:
 
677
%
 
678
%      Image *FlattenImage(const Image *image,ExceptionInfo *exception)
 
679
%
 
680
%  A description of each parameter follows:
 
681
%
 
682
%    o image: The image sequence.
 
683
%
 
684
%    o exception: Return any errors or warnings in this structure.
 
685
%
 
686
*/
 
687
MagickExport Image *FlattenImages(const Image *image,ExceptionInfo *exception)
 
688
{
 
689
  Image
 
690
    *flatten_image;
 
691
 
 
692
  register const Image
 
693
    *next;
 
694
 
 
695
  /*
 
696
    Flatten the image sequence.
 
697
  */
 
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);
 
705
  /*
 
706
    Clone first image in sequence.
 
707
  */
 
708
  flatten_image=CloneImage(image,0,0,True,exception);
 
709
  if (flatten_image == (Image *) NULL)
 
710
    return((Image *) NULL);
 
711
  /*
 
712
    Flatten image.
 
713
  */
 
714
  for (next=image->next; next != (Image *) NULL; next=next->next)
 
715
    (void) CompositeImage(flatten_image,next->compose,next,next->page.x,
 
716
      next->page.y);
 
717
  return(flatten_image);
 
718
}
 
719
 
 
720
/*
 
721
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
722
%                                                                             %
 
723
%                                                                             %
 
724
%                                                                             %
 
725
%   F l i p I m a g e                                                         %
 
726
%                                                                             %
 
727
%                                                                             %
 
728
%                                                                             %
 
729
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
730
%
 
731
%  FlipImage() creates a vertical mirror image by reflecting the pixels
 
732
%  around the central x-axis.
 
733
%
 
734
%  The format of the FlipImage method is:
 
735
%
 
736
%      Image *FlipImage(const Image *image,ExceptionInfo *exception)
 
737
%
 
738
%  A description of each parameter follows:
 
739
%
 
740
%    o image: The image.
 
741
%
 
742
%    o exception: Return any errors or warnings in this structure.
 
743
%
 
744
%
 
745
*/
 
746
MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
 
747
{
 
748
#define FlipImageText  "  Flip image...  "
 
749
 
 
750
  Image
 
751
    *flip_image;
 
752
 
 
753
  long
 
754
    y;
 
755
 
 
756
  register const PixelPacket
 
757
    *p;
 
758
 
 
759
  register IndexPacket
 
760
    *flip_indexes,
 
761
    *indexes;
 
762
 
 
763
  register PixelPacket
 
764
    *q;
 
765
 
 
766
  unsigned int
 
767
    status;
 
768
 
 
769
  /*
 
770
    Initialize flip image attributes.
 
771
  */
 
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);
 
779
  /*
 
780
    Flip each row.
 
781
  */
 
782
  for (y=0; y < (long) flip_image->rows; y++)
 
783
  {
 
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))
 
788
      break;
 
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);
 
796
    if (status == False)
 
797
      break;
 
798
    if (QuantumTick(y,flip_image->rows))
 
799
      if (!MagickMonitor(FlipImageText,y,flip_image->rows,exception))
 
800
        break;
 
801
  }
 
802
  flip_image->is_grayscale=image->is_grayscale;
 
803
  return(flip_image);
 
804
}
 
805
 
 
806
/*
 
807
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
808
%                                                                             %
 
809
%                                                                             %
 
810
%                                                                             %
 
811
%   F l o p I m a g e                                                         %
 
812
%                                                                             %
 
813
%                                                                             %
 
814
%                                                                             %
 
815
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
816
%
 
817
%  FlopImage() creates a horizontal mirror image by reflecting the pixels
 
818
%  around the central y-axis.
 
819
%
 
820
%  The format of the FlopImage method is:
 
821
%
 
822
%      Image *FlopImage(const Image *image,ExceptionInfo *exception)
 
823
%
 
824
%  A description of each parameter follows:
 
825
%
 
826
%    o image: The image.
 
827
%
 
828
%    o exception: Return any errors or warnings in this structure.
 
829
%
 
830
%
 
831
*/
 
832
MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
 
833
{
 
834
#define FlopImageText  "  Flop image...  "
 
835
 
 
836
  Image
 
837
    *flop_image;
 
838
 
 
839
  long
 
840
    y;
 
841
 
 
842
  register IndexPacket
 
843
    *flop_indexes,
 
844
    *indexes;
 
845
 
 
846
  register const PixelPacket
 
847
    *p;
 
848
 
 
849
  register long
 
850
    x;
 
851
 
 
852
  register PixelPacket
 
853
    *q;
 
854
 
 
855
  unsigned int
 
856
    status;
 
857
 
 
858
  /*
 
859
    Initialize flop image attributes.
 
860
  */
 
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);
 
868
  /*
 
869
    Flop each row.
 
870
  */
 
871
  for (y=0; y < (long) flop_image->rows; y++)
 
872
  {
 
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))
 
876
      break;
 
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++)
 
881
    {
 
882
      if ((indexes != (IndexPacket *) NULL) &&
 
883
          (flop_indexes != (IndexPacket *) NULL))
 
884
        flop_indexes[flop_image->columns-x-1]=indexes[x];
 
885
      q--;
 
886
      *q=(*p);
 
887
      p++;
 
888
    }
 
889
    status=SyncImagePixels(flop_image);
 
890
    if (status == False)
 
891
      break;
 
892
    if (QuantumTick(y,flop_image->rows))
 
893
      if (!MagickMonitor(FlopImageText,y,flop_image->rows,exception))
 
894
        break;
 
895
  }
 
896
  flop_image->is_grayscale=image->is_grayscale;
 
897
  return(flop_image);
 
898
}
 
899
 
 
900
/*
 
901
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
902
%                                                                             %
 
903
%                                                                             %
 
904
%                                                                             %
 
905
%     M o s a i c I m a g e s                                                 %
 
906
%                                                                             %
 
907
%                                                                             %
 
908
%                                                                             %
 
909
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
910
%
 
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.
 
914
%
 
915
%  The format of the MosaicImage method is:
 
916
%
 
917
%      Image *MosaicImages(const Image *image,ExceptionInfo *exception)
 
918
%
 
919
%  A description of each parameter follows:
 
920
%
 
921
%    o image: The image.
 
922
%
 
923
%    o exception: Return any errors or warnings in this structure.
 
924
%
 
925
%
 
926
*/
 
927
MagickExport Image *MosaicImages(const Image *image,ExceptionInfo *exception)
 
928
{
 
929
#define MosaicImageText  "  Create an image mosaic...  "
 
930
 
 
931
  Image
 
932
    *mosaic_image;
 
933
 
 
934
  RectangleInfo
 
935
    page;
 
936
 
 
937
  register const Image
 
938
    *next;
 
939
 
 
940
  unsigned int
 
941
    scene,
 
942
    status;
 
943
 
 
944
  /*
 
945
    Determine mosaic bounding box.
 
946
  */
 
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;
 
956
  page.x=0;
 
957
  page.y=0;
 
958
  for (next=image; next != (Image *) NULL; next=next->next)
 
959
  {
 
960
    page.x=next->page.x;
 
961
    page.y=next->page.y;
 
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;
 
970
  }
 
971
  /*
 
972
    Allocate mosaic image.
 
973
  */
 
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);
 
980
  /*
 
981
    Initialize colormap.
 
982
  */
 
983
  scene=0;
 
984
  for (next=image; next != (Image *) NULL; next=next->next)
 
985
  {
 
986
    (void) CompositeImage(mosaic_image,CopyCompositeOp,next,next->page.x,
 
987
      next->page.y);
 
988
    status=MagickMonitor(MosaicImageText,scene++,GetImageListLength(image),
 
989
      exception);
 
990
    if (status == False)
 
991
      break;
 
992
  }
 
993
  return(mosaic_image);
 
994
}
 
995
 
 
996
/*
 
997
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
998
%                                                                             %
 
999
%                                                                             %
 
1000
%                                                                             %
 
1001
%   R o l l I m a g e                                                         %
 
1002
%                                                                             %
 
1003
%                                                                             %
 
1004
%                                                                             %
 
1005
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1006
%
 
1007
%  RollImage() offsets an image as defined by x_offset and y_offset.
 
1008
%
 
1009
%  The format of the RollImage method is:
 
1010
%
 
1011
%      Image *RollImage(const Image *image,const long x_offset,
 
1012
%        const long y_offset,ExceptionInfo *exception)
 
1013
%
 
1014
%  A description of each parameter follows:
 
1015
%
 
1016
%    o image: The image.
 
1017
%
 
1018
%    o x_offset: The number of columns to roll in the horizontal direction.
 
1019
%
 
1020
%    o y_offset: The number of rows to roll in the vertical direction.
 
1021
%
 
1022
%    o exception: Return any errors or warnings in this structure.
 
1023
%
 
1024
%
 
1025
*/
 
1026
MagickExport Image *RollImage(const Image *image,const long x_offset,
 
1027
  const long y_offset,ExceptionInfo *exception)
 
1028
{
 
1029
#define RollImageText  "  Roll image...  "
 
1030
 
 
1031
  Image
 
1032
    *roll_image;
 
1033
 
 
1034
  long
 
1035
    y;
 
1036
 
 
1037
  register const PixelPacket
 
1038
    *p;
 
1039
 
 
1040
  register IndexPacket
 
1041
    *indexes,
 
1042
    *roll_indexes;
 
1043
 
 
1044
  register long
 
1045
    x;
 
1046
 
 
1047
  register PixelPacket
 
1048
    *q;
 
1049
 
 
1050
  RectangleInfo
 
1051
    offset;
 
1052
 
 
1053
  /*
 
1054
    Initialize roll image attributes.
 
1055
  */
 
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);
 
1063
  /*
 
1064
    Roll image.
 
1065
  */
 
1066
  offset.x=x_offset;
 
1067
  offset.y=y_offset;
 
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++)
 
1077
  {
 
1078
    /*
 
1079
      Transfer scanline.
 
1080
    */
 
1081
    p=AcquireImagePixels(image,0,y,image->columns,1,exception);
 
1082
    if (p == (const PixelPacket *) NULL)
 
1083
      break;
 
1084
    indexes=GetIndexes(image);
 
1085
    for (x=0; x < (long) image->columns; x++)
 
1086
    {
 
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)
 
1090
        break;
 
1091
      roll_indexes=GetIndexes(roll_image);
 
1092
      if ((indexes != (IndexPacket *) NULL) &&
 
1093
          (roll_indexes != (IndexPacket *) NULL))
 
1094
        *roll_indexes=indexes[x];
 
1095
      *q=(*p);
 
1096
      p++;
 
1097
      if (!SyncImagePixels(roll_image))
 
1098
        break;
 
1099
    }
 
1100
    if (QuantumTick(y,image->rows))
 
1101
      if (!MagickMonitor(RollImageText,y,image->rows,exception))
 
1102
        break;
 
1103
  }
 
1104
  roll_image->is_grayscale=image->is_grayscale;
 
1105
  return(roll_image);
 
1106
}
 
1107
 
 
1108
/*
 
1109
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1110
%                                                                             %
 
1111
%                                                                             %
 
1112
%                                                                             %
 
1113
%   S h a v e I m a g e                                                       %
 
1114
%                                                                             %
 
1115
%                                                                             %
 
1116
%                                                                             %
 
1117
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1118
%
 
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
 
1121
%  new image.
 
1122
%
 
1123
%  The format of the ShaveImage method is:
 
1124
%
 
1125
%      Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
 
1126
%        ExceptionInfo *exception)
 
1127
%
 
1128
%  A description of each parameter follows:
 
1129
%
 
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.
 
1133
%
 
1134
%    o image: The image.
 
1135
%
 
1136
%    o shave_info: Specifies a pointer to a RectangleInfo which defines the
 
1137
%      region of the image to crop.
 
1138
%
 
1139
%    o exception: Return any errors or warnings in this structure.
 
1140
%
 
1141
%
 
1142
*/
 
1143
MagickExport Image *ShaveImage(const Image *image,
 
1144
  const RectangleInfo *shave_info,ExceptionInfo *exception)
 
1145
{
 
1146
  RectangleInfo
 
1147
    geometry;
 
1148
 
 
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));
 
1159
}
 
1160
 
 
1161
/*
 
1162
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1163
%                                                                             %
 
1164
%                                                                             %
 
1165
%                                                                             %
 
1166
%   T r a n s f o r m I m a g e                                               %
 
1167
%                                                                             %
 
1168
%                                                                             %
 
1169
%                                                                             % 
 
1170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1171
%
 
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
 
1175
%  is returned.
 
1176
%
 
1177
%  The format of the TransformImage method is:
 
1178
%
 
1179
%      void TransformImage(Image **image,const char *crop_geometry,
 
1180
%        const char *image_geometry)
 
1181
%
 
1182
%  A description of each parameter follows:
 
1183
%
 
1184
%    o image: The image The transformed image is returned as this parameter.
 
1185
%
 
1186
%    o crop_geometry: A crop geometry string.  This geometry defines a
 
1187
%      subregion of the image to crop.
 
1188
%
 
1189
%    o image_geometry: An image geometry string.  This geometry defines the
 
1190
%      final size of the image.
 
1191
%
 
1192
%
 
1193
*/
 
1194
MagickExport void TransformImage(Image **image,const char *crop_geometry,
 
1195
  const char *image_geometry)
 
1196
{
 
1197
  Image
 
1198
    *resize_image,
 
1199
    *transform_image;
 
1200
 
 
1201
  int
 
1202
    flags;
 
1203
 
 
1204
  RectangleInfo
 
1205
    geometry;
 
1206
 
 
1207
  assert(image != (Image **) NULL);
 
1208
  assert((*image)->signature == MagickSignature);
 
1209
  transform_image=(*image);
 
1210
  if (crop_geometry != (const char *) NULL)
 
1211
    {
 
1212
      Image
 
1213
        *crop_image;
 
1214
 
 
1215
      RectangleInfo
 
1216
        geometry;
 
1217
 
 
1218
      /*
 
1219
        Crop image to a user specified size.
 
1220
      */
 
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);
 
1227
      else
 
1228
        if ((transform_image->columns > geometry.width) ||
 
1229
            (transform_image->rows > geometry.height))
 
1230
          {
 
1231
            Image
 
1232
              *next;
 
1233
 
 
1234
            long
 
1235
              x,
 
1236
              y;
 
1237
 
 
1238
            unsigned long
 
1239
              height,
 
1240
              width;
 
1241
 
 
1242
            /*
 
1243
              Crop repeatedly to create uniform subimages.
 
1244
            */
 
1245
            width=geometry.width;
 
1246
            height=geometry.height;
 
1247
            next=(Image *) NULL;
 
1248
            for (y=0; y < (long) transform_image->rows; y+=height)
 
1249
            {
 
1250
              for (x=0; x < (long) transform_image->columns; x+=width)
 
1251
              {
 
1252
                geometry.width=width;
 
1253
                geometry.height=height;
 
1254
                geometry.x=x;
 
1255
                geometry.y=y;
 
1256
                next=CropImage(transform_image,&geometry,&(*image)->exception);
 
1257
                if (next == (Image *) NULL)
 
1258
                  break;
 
1259
                if (crop_image == (Image *) NULL)
 
1260
                  crop_image=next;
 
1261
                else
 
1262
                  {
 
1263
                    next->previous=crop_image;
 
1264
                    crop_image->next=next;
 
1265
                    crop_image=crop_image->next;
 
1266
                  }
 
1267
              }
 
1268
              if (next == (Image *) NULL)
 
1269
                break;
 
1270
            }
 
1271
          }
 
1272
      if (crop_image != (Image *) NULL)
 
1273
        {
 
1274
          DestroyImage(transform_image);
 
1275
          while (crop_image->previous != (Image *) NULL)
 
1276
            crop_image=crop_image->previous;
 
1277
          transform_image=crop_image;
 
1278
        }
 
1279
      *image=transform_image;
 
1280
    }
 
1281
  if (image_geometry == (const char *) NULL)
 
1282
    return;
 
1283
  /*
 
1284
    Scale image to a user specified size.
 
1285
  */
 
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))
 
1291
    return;
 
1292
  /*
 
1293
    Resize image.
 
1294
  */
 
1295
  resize_image=ZoomImage(transform_image,geometry.width,geometry.height,
 
1296
    &(*image)->exception);
 
1297
  if (resize_image == (Image *) NULL)
 
1298
    return;
 
1299
  DestroyImage(transform_image);
 
1300
  transform_image=resize_image;
 
1301
  *image=transform_image;
 
1302
}