blob: 398d9558ded0672f2ddab8b839622ac4718138e0 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% IIIII M M AAA GGGG EEEEE %
7% I MM MM A A G E %
8% I M M M AAAAA G GG EEE %
9% I M M A A G G E %
10% IIIII M M A A GGGG EEEEE %
11% %
12% %
13% MagickCore Image Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/animate.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/attribute.h"
47#include "MagickCore/blob.h"
48#include "MagickCore/blob-private.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-private.h"
51#include "MagickCore/cache-view.h"
52#include "MagickCore/client.h"
53#include "MagickCore/color.h"
54#include "MagickCore/color-private.h"
55#include "MagickCore/colormap.h"
56#include "MagickCore/colorspace.h"
57#include "MagickCore/colorspace-private.h"
58#include "MagickCore/composite.h"
59#include "MagickCore/composite-private.h"
60#include "MagickCore/compress.h"
61#include "MagickCore/constitute.h"
62#include "MagickCore/display.h"
63#include "MagickCore/draw.h"
64#include "MagickCore/enhance.h"
65#include "MagickCore/exception.h"
66#include "MagickCore/exception-private.h"
67#include "MagickCore/gem.h"
68#include "MagickCore/geometry.h"
69#include "MagickCore/histogram.h"
70#include "MagickCore/image-private.h"
71#include "MagickCore/list.h"
72#include "MagickCore/magic.h"
73#include "MagickCore/magick.h"
74#include "MagickCore/memory_.h"
75#include "MagickCore/module.h"
76#include "MagickCore/monitor.h"
77#include "MagickCore/monitor-private.h"
78#include "MagickCore/option.h"
79#include "MagickCore/paint.h"
80#include "MagickCore/pixel-accessor.h"
81#include "MagickCore/profile.h"
82#include "MagickCore/property.h"
83#include "MagickCore/quantize.h"
84#include "MagickCore/random_.h"
85#include "MagickCore/segment.h"
86#include "MagickCore/semaphore.h"
87#include "MagickCore/signature-private.h"
88#include "MagickCore/statistic.h"
89#include "MagickCore/string_.h"
90#include "MagickCore/string-private.h"
91#include "MagickCore/thread-private.h"
92#include "MagickCore/threshold.h"
93#include "MagickCore/timer.h"
94#include "MagickCore/utility.h"
95#include "MagickCore/version.h"
96#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000097
98/*
99 Constant declaration.
100*/
101const char
cristy7138c592009-09-08 13:58:52 +0000102 BackgroundColor[] = "#ffffff", /* white */
103 BorderColor[] = "#dfdfdf", /* gray */
104 DefaultTileFrame[] = "15x15+3+3",
105 DefaultTileGeometry[] = "120x120+4+3>",
106 DefaultTileLabel[] = "%f\n%G\n%b",
107 ForegroundColor[] = "#000", /* black */
108 LoadImageTag[] = "Load/Image",
109 LoadImagesTag[] = "Load/Images",
110 MatteColor[] = "#bdbdbd", /* gray */
111 PSDensityGeometry[] = "72.0x72.0",
112 PSPageGeometry[] = "612x792",
113 SaveImageTag[] = "Save/Image",
114 SaveImagesTag[] = "Save/Images",
115 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000116
117const double
118 DefaultResolution = 72.0;
119
120/*
121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122% %
123% %
124% %
125% A c q u i r e I m a g e %
126% %
127% %
128% %
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%
131% AcquireImage() returns a pointer to an image structure initialized to
132% default values.
133%
134% The format of the AcquireImage method is:
135%
136% Image *AcquireImage(const ImageInfo *image_info)
137%
138% A description of each parameter follows:
139%
140% o image_info: Many of the image default values are set from this
141% structure. For example, filename, compression, depth, background color,
142% and others.
143%
144*/
145MagickExport Image *AcquireImage(const ImageInfo *image_info)
146{
cristye412c892010-07-26 12:31:36 +0000147 const char
cristyf3a660a2010-07-26 14:17:52 +0000148 *option;
cristye412c892010-07-26 12:31:36 +0000149
cristy3ed852e2009-09-05 21:47:34 +0000150 Image
151 *image;
152
153 MagickStatusType
154 flags;
155
156 /*
157 Allocate image structure.
158 */
159 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy73bd4a52010-10-05 11:24:23 +0000160 image=(Image *) AcquireMagickMemory(sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000161 if (image == (Image *) NULL)
162 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
163 (void) ResetMagickMemory(image,0,sizeof(*image));
164 /*
165 Initialize Image structure.
166 */
167 (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
168 image->storage_class=DirectClass;
169 image->depth=MAGICKCORE_QUANTUM_DEPTH;
170 image->colorspace=RGBColorspace;
171 image->interlace=NoInterlace;
172 image->ticks_per_second=UndefinedTicksPerSecond;
173 image->compose=OverCompositeOp;
174 image->blur=1.0;
175 GetExceptionInfo(&image->exception);
176 (void) QueryColorDatabase(BackgroundColor,&image->background_color,
177 &image->exception);
178 (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
179 (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
180 (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
181 &image->exception);
182 image->x_resolution=DefaultResolution;
183 image->y_resolution=DefaultResolution;
184 image->units=PixelsPerInchResolution;
185 GetTimerInfo(&image->timer);
cristy73724512010-04-12 14:43:14 +0000186 image->ping=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000187 image->cache=AcquirePixelCache(0);
cristy4c08aed2011-07-01 19:47:50 +0000188 image->component_map=AcquirePixelComponentMap();
cristy3ed852e2009-09-05 21:47:34 +0000189 image->blob=CloneBlobInfo((BlobInfo *) NULL);
190 image->debug=IsEventLogging();
191 image->reference_count=1;
192 image->semaphore=AllocateSemaphoreInfo();
193 image->signature=MagickSignature;
194 if (image_info == (ImageInfo *) NULL)
195 return(image);
196 /*
197 Transfer image info.
198 */
199 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
200 MagickFalse);
201 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
202 (void) CopyMagickString(image->magick_filename,image_info->filename,
203 MaxTextExtent);
204 (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
205 if (image_info->size != (char *) NULL)
206 {
207 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
208 image->columns=image->extract_info.width;
209 image->rows=image->extract_info.height;
210 image->offset=image->extract_info.x;
211 image->extract_info.x=0;
212 image->extract_info.y=0;
213 }
214 if (image_info->extract != (char *) NULL)
215 {
216 RectangleInfo
217 geometry;
218
219 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
220 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
221 {
222 image->extract_info=geometry;
223 Swap(image->columns,image->extract_info.width);
224 Swap(image->rows,image->extract_info.height);
225 }
226 }
227 image->compression=image_info->compression;
228 image->quality=image_info->quality;
229 image->endian=image_info->endian;
230 image->interlace=image_info->interlace;
231 image->units=image_info->units;
232 if (image_info->density != (char *) NULL)
233 {
234 GeometryInfo
235 geometry_info;
236
237 flags=ParseGeometry(image_info->density,&geometry_info);
238 image->x_resolution=geometry_info.rho;
239 image->y_resolution=geometry_info.sigma;
240 if ((flags & SigmaValue) == 0)
241 image->y_resolution=image->x_resolution;
242 }
243 if (image_info->page != (char *) NULL)
244 {
245 char
246 *geometry;
247
248 image->page=image->extract_info;
249 geometry=GetPageGeometry(image_info->page);
250 (void) ParseAbsoluteGeometry(geometry,&image->page);
251 geometry=DestroyString(geometry);
252 }
253 if (image_info->depth != 0)
254 image->depth=image_info->depth;
255 image->dither=image_info->dither;
256 image->background_color=image_info->background_color;
257 image->border_color=image_info->border_color;
258 image->matte_color=image_info->matte_color;
259 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000260 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000261 image->progress_monitor=image_info->progress_monitor;
262 image->client_data=image_info->client_data;
263 if (image_info->cache != (void *) NULL)
264 ClonePixelCacheMethods(image->cache,image_info->cache);
265 (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
cristy6b9aca12010-02-21 01:50:11 +0000266 (void) SyncImageSettings(image_info,image);
cristye412c892010-07-26 12:31:36 +0000267 option=GetImageOption(image_info,"delay");
268 if (option != (const char *) NULL)
269 {
270 GeometryInfo
271 geometry_info;
272
273 flags=ParseGeometry(option,&geometry_info);
274 if ((flags & GreaterValue) != 0)
275 {
276 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
277 image->delay=(size_t) floor(geometry_info.rho+0.5);
278 }
279 else
280 if ((flags & LessValue) != 0)
281 {
282 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
283 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
284 }
285 else
286 image->delay=(size_t) floor(geometry_info.rho+0.5);
287 if ((flags & SigmaValue) != 0)
288 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
289 }
290 option=GetImageOption(image_info,"dispose");
291 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000292 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
cristye412c892010-07-26 12:31:36 +0000293 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000294 return(image);
295}
296
297/*
298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299% %
300% %
301% %
cristy3ed852e2009-09-05 21:47:34 +0000302% A c q u i r e I m a g e I n f o %
303% %
304% %
305% %
306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307%
308% AcquireImageInfo() allocates the ImageInfo structure.
309%
310% The format of the AcquireImageInfo method is:
311%
312% ImageInfo *AcquireImageInfo(void)
313%
314*/
315MagickExport ImageInfo *AcquireImageInfo(void)
316{
317 ImageInfo
318 *image_info;
319
cristy73bd4a52010-10-05 11:24:23 +0000320 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000321 if (image_info == (ImageInfo *) NULL)
322 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
323 GetImageInfo(image_info);
324 return(image_info);
325}
326
327/*
328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329% %
330% %
331% %
332% A c q u i r e N e x t I m a g e %
333% %
334% %
335% %
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337%
338% AcquireNextImage() initializes the next image in a sequence to
339% default values. The next member of image points to the newly allocated
340% image. If there is a memory shortage, next is assigned NULL.
341%
342% The format of the AcquireNextImage method is:
343%
344% void AcquireNextImage(const ImageInfo *image_info,Image *image)
345%
346% A description of each parameter follows:
347%
348% o image_info: Many of the image default values are set from this
349% structure. For example, filename, compression, depth, background color,
350% and others.
351%
352% o image: the image.
353%
354*/
355MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
356{
357 /*
358 Allocate image structure.
359 */
360 assert(image != (Image *) NULL);
361 assert(image->signature == MagickSignature);
362 if (image->debug != MagickFalse)
363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
364 image->next=AcquireImage(image_info);
365 if (GetNextImageInList(image) == (Image *) NULL)
366 return;
367 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
368 MaxTextExtent);
369 if (image_info != (ImageInfo *) NULL)
370 (void) CopyMagickString(GetNextImageInList(image)->filename,
371 image_info->filename,MaxTextExtent);
372 DestroyBlob(GetNextImageInList(image));
373 image->next->blob=ReferenceBlob(image->blob);
374 image->next->endian=image->endian;
375 image->next->scene=image->scene+1;
376 image->next->previous=image;
377}
378
379/*
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381% %
382% %
383% %
384% A p p e n d I m a g e s %
385% %
386% %
387% %
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389%
390% AppendImages() takes all images from the current image pointer to the end
391% of the image list and appends them to each other top-to-bottom if the
392% stack parameter is true, otherwise left-to-right.
393%
394% The current gravity setting now effects how the image is justified in the
395% final image.
396%
397% The format of the AppendImages method is:
398%
cristy4ca38e22011-02-10 02:57:49 +0000399% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000400% ExceptionInfo *exception)
401%
402% A description of each parameter follows:
403%
cristy4ca38e22011-02-10 02:57:49 +0000404% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000405%
406% o stack: A value other than 0 stacks the images top-to-bottom.
407%
408% o exception: return any errors or warnings in this structure.
409%
410*/
cristy4ca38e22011-02-10 02:57:49 +0000411MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000412 const MagickBooleanType stack,ExceptionInfo *exception)
413{
414#define AppendImageTag "Append/Image"
415
416 CacheView
417 *append_view,
418 *image_view;
419
cristy4ca38e22011-02-10 02:57:49 +0000420 const Image
421 *image;
422
cristy3ed852e2009-09-05 21:47:34 +0000423 Image
424 *append_image;
425
cristy3ed852e2009-09-05 21:47:34 +0000426 MagickBooleanType
427 matte,
428 proceed,
429 status;
430
cristybb503372010-05-27 20:51:26 +0000431 MagickOffsetType
432 n;
433
cristy3ed852e2009-09-05 21:47:34 +0000434 RectangleInfo
435 geometry;
436
437 register const Image
438 *next;
439
cristybb503372010-05-27 20:51:26 +0000440 size_t
cristy3ed852e2009-09-05 21:47:34 +0000441 height,
442 number_images,
443 width;
444
cristybb503372010-05-27 20:51:26 +0000445 ssize_t
446 x_offset,
447 y,
448 y_offset;
449
cristy3ed852e2009-09-05 21:47:34 +0000450 /*
cristy7c6dc152011-02-11 14:10:55 +0000451 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000452 */
cristy4ca38e22011-02-10 02:57:49 +0000453 assert(images != (Image *) NULL);
454 assert(images->signature == MagickSignature);
455 if (images->debug != MagickFalse)
456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000457 assert(exception != (ExceptionInfo *) NULL);
458 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +0000459 image=images;
cristy3ed852e2009-09-05 21:47:34 +0000460 matte=image->matte;
461 number_images=1;
462 width=image->columns;
463 height=image->rows;
464 next=GetNextImageInList(image);
465 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
466 {
467 if (next->matte != MagickFalse)
468 matte=MagickTrue;
469 number_images++;
470 if (stack != MagickFalse)
471 {
472 if (next->columns > width)
473 width=next->columns;
474 height+=next->rows;
475 continue;
476 }
477 width+=next->columns;
478 if (next->rows > height)
479 height=next->rows;
480 }
481 /*
cristy7c6dc152011-02-11 14:10:55 +0000482 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000483 */
484 append_image=CloneImage(image,width,height,MagickTrue,exception);
485 if (append_image == (Image *) NULL)
486 return((Image *) NULL);
487 if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
488 {
489 InheritException(exception,&append_image->exception);
490 append_image=DestroyImage(append_image);
491 return((Image *) NULL);
492 }
493 append_image->matte=matte;
494 (void) SetImageBackgroundColor(append_image);
495 status=MagickTrue;
496 x_offset=0;
497 y_offset=0;
498 append_view=AcquireCacheView(append_image);
cristybb503372010-05-27 20:51:26 +0000499 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000500 {
501 SetGeometry(append_image,&geometry);
502 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
503 if (stack != MagickFalse)
504 x_offset-=geometry.x;
505 else
506 y_offset-=geometry.y;
507 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +0000508#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1a2bd532010-11-19 02:53:15 +0000509 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
cristy3ed852e2009-09-05 21:47:34 +0000510#endif
cristybb503372010-05-27 20:51:26 +0000511 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000512 {
513 MagickBooleanType
514 sync;
515
cristy4c08aed2011-07-01 19:47:50 +0000516 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000517 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000518
cristy4c08aed2011-07-01 19:47:50 +0000519 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000520 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000521
cristycb6d09b2010-06-19 01:59:36 +0000522 register ssize_t
523 x;
524
cristy3ed852e2009-09-05 21:47:34 +0000525 if (status == MagickFalse)
526 continue;
527 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
528 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
529 image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000530 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000531 {
532 status=MagickFalse;
533 continue;
534 }
cristybb503372010-05-27 20:51:26 +0000535 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristy4c08aed2011-07-01 19:47:50 +0000537 SetPixelRed(append_image,GetPixelRed(image,p),q);
538 SetPixelGreen(append_image,GetPixelGreen(image,p),q);
539 SetPixelBlue(append_image,GetPixelBlue(image,p),q);
cristyff775322011-02-24 15:05:25 +0000540 if ((image->colorspace == CMYKColorspace) &&
541 (append_image->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +0000542 SetPixelBlack(append_image,GetPixelBlack(image,p),q);
543 SetPixelAlpha(append_image,OpaqueAlpha,q);
544 if (image->matte != MagickFalse)
545 SetPixelAlpha(append_image,GetPixelAlpha(image,p),q);
546 p+=GetPixelChannels(image);
547 q+=GetPixelChannels(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000548 }
549 sync=SyncCacheViewAuthenticPixels(append_view,exception);
550 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000551 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000552 }
553 image_view=DestroyCacheView(image_view);
554 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
555 if (proceed == MagickFalse)
556 break;
557 if (stack == MagickFalse)
558 {
cristyeaedf062010-05-29 22:36:02 +0000559 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000560 y_offset=0;
561 }
562 else
563 {
564 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000565 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000566 }
567 image=GetNextImageInList(image);
568 }
569 append_view=DestroyCacheView(append_view);
570 if (status == MagickFalse)
571 append_image=DestroyImage(append_image);
572 return(append_image);
573}
574
575/*
576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577% %
578% %
579% %
cristy3ed852e2009-09-05 21:47:34 +0000580% C a t c h I m a g e E x c e p t i o n %
581% %
582% %
583% %
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585%
586% CatchImageException() returns if no exceptions are found in the image
587% sequence, otherwise it determines the most severe exception and reports
588% it as a warning or error depending on the severity.
589%
590% The format of the CatchImageException method is:
591%
592% ExceptionType CatchImageException(Image *image)
593%
594% A description of each parameter follows:
595%
596% o image: An image sequence.
597%
598*/
599MagickExport ExceptionType CatchImageException(Image *image)
600{
601 ExceptionInfo
602 *exception;
603
604 ExceptionType
605 severity;
606
607 assert(image != (const Image *) NULL);
608 assert(image->signature == MagickSignature);
609 if (image->debug != MagickFalse)
610 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
611 exception=AcquireExceptionInfo();
612 GetImageException(image,exception);
613 CatchException(exception);
614 severity=exception->severity;
615 exception=DestroyExceptionInfo(exception);
616 return(severity);
617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
624% C l i p I m a g e P a t h %
625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629%
630% ClipImagePath() sets the image clip mask based any clipping path information
631% if it exists.
632%
633% The format of the ClipImagePath method is:
634%
635% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
636% const MagickBooleanType inside)
637%
638% A description of each parameter follows:
639%
640% o image: the image.
641%
642% o pathname: name of clipping path resource. If name is preceded by #, use
643% clipping path numbered by name.
644%
645% o inside: if non-zero, later operations take effect inside clipping path.
646% Otherwise later operations take effect outside clipping path.
647%
648*/
649
650MagickExport MagickBooleanType ClipImage(Image *image)
651{
652 return(ClipImagePath(image,"#1",MagickTrue));
653}
654
655MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
656 const MagickBooleanType inside)
657{
658#define ClipImagePathTag "ClipPath/Image"
659
660 char
661 *property;
662
663 const char
664 *value;
665
666 Image
667 *clip_mask;
668
669 ImageInfo
670 *image_info;
671
672 assert(image != (const Image *) NULL);
673 assert(image->signature == MagickSignature);
674 if (image->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
676 assert(pathname != NULL);
677 property=AcquireString(pathname);
cristyb51dff52011-05-19 16:55:47 +0000678 (void) FormatLocaleString(property,MaxTextExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000679 pathname);
680 value=GetImageProperty(image,property);
681 property=DestroyString(property);
682 if (value == (const char *) NULL)
683 {
684 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
685 image->filename);
686 return(MagickFalse);
687 }
688 image_info=AcquireImageInfo();
689 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
690 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
691 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
692 image_info=DestroyImageInfo(image_info);
693 if (clip_mask == (Image *) NULL)
694 return(MagickFalse);
695 if (clip_mask->storage_class == PseudoClass)
696 {
697 (void) SyncImage(clip_mask);
698 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
699 return(MagickFalse);
700 }
701 if (inside == MagickFalse)
702 (void) NegateImage(clip_mask,MagickFalse);
cristyb51dff52011-05-19 16:55:47 +0000703 (void) FormatLocaleString(clip_mask->magick_filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000704 "8BIM:1999,2998:%s\nPS",pathname);
705 (void) SetImageClipMask(image,clip_mask);
706 clip_mask=DestroyImage(clip_mask);
707 return(MagickTrue);
708}
709
710/*
711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712% %
713% %
714% %
715% C l o n e I m a g e %
716% %
717% %
718% %
719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720%
721% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000722%
cristy3ed852e2009-09-05 21:47:34 +0000723% If the specified columns and rows is 0, an exact copy of the image is
724% returned, otherwise the pixel data is undefined and must be initialized
725% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
726% failure, a NULL image is returned and exception describes the reason for the
727% failure.
728%
729% The format of the CloneImage method is:
730%
cristybb503372010-05-27 20:51:26 +0000731% Image *CloneImage(const Image *image,const size_t columns,
732% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000733% ExceptionInfo *exception)
734%
735% A description of each parameter follows:
736%
737% o image: the image.
738%
739% o columns: the number of columns in the cloned image.
740%
741% o rows: the number of rows in the cloned image.
742%
743% o detach: With a value other than 0, the cloned image is detached from
744% its parent I/O stream.
745%
746% o exception: return any errors or warnings in this structure.
747%
748*/
cristybb503372010-05-27 20:51:26 +0000749MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000750 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000751{
752 Image
753 *clone_image;
754
755 MagickRealType
756 scale;
757
758 size_t
759 length;
760
761 /*
762 Clone the image.
763 */
764 assert(image != (const Image *) NULL);
765 assert(image->signature == MagickSignature);
766 if (image->debug != MagickFalse)
767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
768 assert(exception != (ExceptionInfo *) NULL);
769 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000770 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000771 if (clone_image == (Image *) NULL)
772 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
773 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
774 clone_image->signature=MagickSignature;
775 clone_image->storage_class=image->storage_class;
cristy4c08aed2011-07-01 19:47:50 +0000776 clone_image->pixel_channels=image->pixel_channels;
777 clone_image->metacontent_extent=image->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +0000778 clone_image->colorspace=image->colorspace;
779 clone_image->matte=image->matte;
780 clone_image->columns=image->columns;
781 clone_image->rows=image->rows;
782 clone_image->dither=image->dither;
783 if (image->colormap != (PixelPacket *) NULL)
784 {
785 /*
786 Allocate and copy the image colormap.
787 */
788 clone_image->colors=image->colors;
789 length=(size_t) image->colors;
790 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
791 sizeof(*clone_image->colormap));
792 if (clone_image->colormap == (PixelPacket *) NULL)
793 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
794 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
795 sizeof(*clone_image->colormap));
796 }
797 (void) CloneImageProfiles(clone_image,image);
798 (void) CloneImageProperties(clone_image,image);
799 (void) CloneImageArtifacts(clone_image,image);
800 GetTimerInfo(&clone_image->timer);
801 GetExceptionInfo(&clone_image->exception);
802 InheritException(&clone_image->exception,&image->exception);
803 if (image->ascii85 != (void *) NULL)
804 Ascii85Initialize(clone_image);
805 clone_image->magick_columns=image->magick_columns;
806 clone_image->magick_rows=image->magick_rows;
807 clone_image->type=image->type;
cristy4c08aed2011-07-01 19:47:50 +0000808 clone_image->component_map=ClonePixelComponentMap(image->component_map);
cristy3ed852e2009-09-05 21:47:34 +0000809 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
810 MaxTextExtent);
811 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
812 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
813 clone_image->progress_monitor=image->progress_monitor;
814 clone_image->client_data=image->client_data;
815 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000816 clone_image->next=image->next;
817 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000818 clone_image->list=NewImageList();
819 clone_image->clip_mask=NewImageList();
820 clone_image->mask=NewImageList();
821 if (detach == MagickFalse)
822 clone_image->blob=ReferenceBlob(image->blob);
823 else
cristybee00932011-01-15 20:28:27 +0000824 {
825 clone_image->next=NewImageList();
826 clone_image->previous=NewImageList();
827 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
828 }
cristy73724512010-04-12 14:43:14 +0000829 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000830 clone_image->debug=IsEventLogging();
831 clone_image->semaphore=AllocateSemaphoreInfo();
832 if ((columns == 0) && (rows == 0))
833 {
834 if (image->montage != (char *) NULL)
835 (void) CloneString(&clone_image->montage,image->montage);
836 if (image->directory != (char *) NULL)
837 (void) CloneString(&clone_image->directory,image->directory);
838 if (image->clip_mask != (Image *) NULL)
839 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
840 exception);
841 if (image->mask != (Image *) NULL)
842 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
843 clone_image->cache=ReferencePixelCache(image->cache);
844 return(clone_image);
845 }
cristy1ab35fb2011-04-15 01:25:56 +0000846 if ((columns == image->columns) && (rows == image->rows))
847 {
848 if (image->clip_mask != (Image *) NULL)
849 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
850 exception);
851 if (image->mask != (Image *) NULL)
852 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
853 }
cristy3ed852e2009-09-05 21:47:34 +0000854 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000855 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
856 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
857 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000858 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000859 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
860 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
861 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000862 clone_image->columns=columns;
863 clone_image->rows=rows;
864 clone_image->cache=ClonePixelCache(image->cache);
865 return(clone_image);
866}
867
868/*
869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870% %
871% %
872% %
873% C l o n e I m a g e I n f o %
874% %
875% %
876% %
877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
878%
879% CloneImageInfo() makes a copy of the given image info structure. If
880% NULL is specified, a new image info structure is created initialized to
881% default values.
882%
883% The format of the CloneImageInfo method is:
884%
885% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
886%
887% A description of each parameter follows:
888%
889% o image_info: the image info.
890%
891*/
892MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
893{
894 ImageInfo
895 *clone_info;
896
897 clone_info=AcquireImageInfo();
898 if (image_info == (ImageInfo *) NULL)
899 return(clone_info);
900 clone_info->compression=image_info->compression;
901 clone_info->temporary=image_info->temporary;
902 clone_info->adjoin=image_info->adjoin;
903 clone_info->antialias=image_info->antialias;
904 clone_info->scene=image_info->scene;
905 clone_info->number_scenes=image_info->number_scenes;
906 clone_info->depth=image_info->depth;
907 if (image_info->size != (char *) NULL)
908 (void) CloneString(&clone_info->size,image_info->size);
909 if (image_info->extract != (char *) NULL)
910 (void) CloneString(&clone_info->extract,image_info->extract);
911 if (image_info->scenes != (char *) NULL)
912 (void) CloneString(&clone_info->scenes,image_info->scenes);
913 if (image_info->page != (char *) NULL)
914 (void) CloneString(&clone_info->page,image_info->page);
915 clone_info->interlace=image_info->interlace;
916 clone_info->endian=image_info->endian;
917 clone_info->units=image_info->units;
918 clone_info->quality=image_info->quality;
919 if (image_info->sampling_factor != (char *) NULL)
920 (void) CloneString(&clone_info->sampling_factor,
921 image_info->sampling_factor);
922 if (image_info->server_name != (char *) NULL)
923 (void) CloneString(&clone_info->server_name,image_info->server_name);
924 if (image_info->font != (char *) NULL)
925 (void) CloneString(&clone_info->font,image_info->font);
926 if (image_info->texture != (char *) NULL)
927 (void) CloneString(&clone_info->texture,image_info->texture);
928 if (image_info->density != (char *) NULL)
929 (void) CloneString(&clone_info->density,image_info->density);
930 clone_info->pointsize=image_info->pointsize;
931 clone_info->fuzz=image_info->fuzz;
cristy3ed852e2009-09-05 21:47:34 +0000932 clone_info->background_color=image_info->background_color;
933 clone_info->border_color=image_info->border_color;
934 clone_info->matte_color=image_info->matte_color;
935 clone_info->transparent_color=image_info->transparent_color;
936 clone_info->dither=image_info->dither;
937 clone_info->monochrome=image_info->monochrome;
938 clone_info->colors=image_info->colors;
939 clone_info->colorspace=image_info->colorspace;
940 clone_info->type=image_info->type;
941 clone_info->orientation=image_info->orientation;
942 clone_info->preview_type=image_info->preview_type;
943 clone_info->group=image_info->group;
944 clone_info->ping=image_info->ping;
945 clone_info->verbose=image_info->verbose;
946 if (image_info->view != (char *) NULL)
947 (void) CloneString(&clone_info->view,image_info->view);
948 if (image_info->authenticate != (char *) NULL)
949 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
950 (void) CloneImageOptions(clone_info,image_info);
951 clone_info->progress_monitor=image_info->progress_monitor;
952 clone_info->client_data=image_info->client_data;
953 clone_info->cache=image_info->cache;
954 if (image_info->cache != (void *) NULL)
955 clone_info->cache=ReferencePixelCache(image_info->cache);
956 if (image_info->profile != (void *) NULL)
957 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
958 image_info->profile);
959 SetImageInfoFile(clone_info,image_info->file);
960 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
961 clone_info->stream=image_info->stream;
962 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
963 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
964 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
965 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
966 (void) CopyMagickString(clone_info->filename,image_info->filename,
967 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000968 clone_info->channel=image_info->channel;
969 clone_info->debug=IsEventLogging();
970 clone_info->signature=image_info->signature;
971 return(clone_info);
972}
973
974/*
975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976% %
977% %
978% %
979% C o m b i n e I m a g e s %
980% %
981% %
982% %
983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984%
985% CombineImages() combines one or more images into a single image. The
986% grayscale value of the pixels of each image in the sequence is assigned in
987% order to the specified channels of the combined image. The typical
988% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
989%
990% The format of the CombineImages method is:
991%
992% Image *CombineImages(const Image *image,const ChannelType channel,
993% ExceptionInfo *exception)
994%
995% A description of each parameter follows:
996%
997% o image: the image.
998%
999% o exception: return any errors or warnings in this structure.
1000%
1001*/
1002MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1003 ExceptionInfo *exception)
1004{
1005#define CombineImageTag "Combine/Image"
1006
1007 CacheView
1008 *combine_view;
1009
1010 const Image
1011 *next;
1012
1013 Image
1014 *combine_image;
1015
cristy3ed852e2009-09-05 21:47:34 +00001016 MagickBooleanType
1017 status;
1018
cristybb503372010-05-27 20:51:26 +00001019 MagickOffsetType
1020 progress;
1021
1022 ssize_t
1023 y;
1024
cristy3ed852e2009-09-05 21:47:34 +00001025 /*
1026 Ensure the image are the same size.
1027 */
1028 assert(image != (const Image *) NULL);
1029 assert(image->signature == MagickSignature);
1030 if (image->debug != MagickFalse)
1031 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1032 assert(exception != (ExceptionInfo *) NULL);
1033 assert(exception->signature == MagickSignature);
1034 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1035 {
1036 if ((next->columns != image->columns) || (next->rows != image->rows))
1037 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1038 }
1039 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1040 if (combine_image == (Image *) NULL)
1041 return((Image *) NULL);
1042 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1043 {
1044 InheritException(exception,&combine_image->exception);
1045 combine_image=DestroyImage(combine_image);
1046 return((Image *) NULL);
1047 }
cristy2b9582a2011-07-04 17:38:56 +00001048 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001049 combine_image->matte=MagickTrue;
1050 (void) SetImageBackgroundColor(combine_image);
1051 /*
1052 Combine images.
1053 */
1054 status=MagickTrue;
1055 progress=0;
1056 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001057 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001058 {
1059 CacheView
1060 *image_view;
1061
1062 const Image
1063 *next;
1064
cristy4c08aed2011-07-01 19:47:50 +00001065 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001066 *pixels;
1067
cristy4c08aed2011-07-01 19:47:50 +00001068 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001069 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001070
cristy4c08aed2011-07-01 19:47:50 +00001071 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001072 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001073
cristycb6d09b2010-06-19 01:59:36 +00001074 register ssize_t
1075 x;
1076
cristy3ed852e2009-09-05 21:47:34 +00001077 if (status == MagickFalse)
1078 continue;
1079 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1080 1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001081 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001082 {
1083 status=MagickFalse;
1084 continue;
1085 }
1086 next=image;
cristy2b9582a2011-07-04 17:38:56 +00001087 if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
1088 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001089 {
1090 image_view=AcquireCacheView(next);
1091 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001092 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001093 continue;
1094 q=pixels;
cristybb503372010-05-27 20:51:26 +00001095 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001096 {
cristy4c08aed2011-07-01 19:47:50 +00001097 SetPixelRed(image,GetPixelIntensity(image,p),q);
1098 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001099 q++;
1100 }
1101 image_view=DestroyCacheView(image_view);
1102 next=GetNextImageInList(next);
1103 }
cristy2b9582a2011-07-04 17:38:56 +00001104 if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
1105 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001106 {
1107 image_view=AcquireCacheView(next);
1108 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001109 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001110 continue;
1111 q=pixels;
cristybb503372010-05-27 20:51:26 +00001112 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
cristy4c08aed2011-07-01 19:47:50 +00001114 SetPixelGreen(image,GetPixelIntensity(image,p),q);
1115 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001116 q++;
1117 }
1118 image_view=DestroyCacheView(image_view);
1119 next=GetNextImageInList(next);
1120 }
cristy2b9582a2011-07-04 17:38:56 +00001121 if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
1122 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001123 {
1124 image_view=AcquireCacheView(next);
1125 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001126 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001127 continue;
1128 q=pixels;
cristybb503372010-05-27 20:51:26 +00001129 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001130 {
cristy4c08aed2011-07-01 19:47:50 +00001131 SetPixelBlue(image,GetPixelIntensity(image,p),q);
1132 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001133 q++;
1134 }
1135 image_view=DestroyCacheView(image_view);
1136 next=GetNextImageInList(next);
1137 }
cristy2b9582a2011-07-04 17:38:56 +00001138 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +00001139 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1140 {
cristy3ed852e2009-09-05 21:47:34 +00001141 image_view=AcquireCacheView(next);
1142 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001143 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001144 continue;
cristy4c08aed2011-07-01 19:47:50 +00001145 q=pixels;
cristybb503372010-05-27 20:51:26 +00001146 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001147 {
cristy4c08aed2011-07-01 19:47:50 +00001148 SetPixelBlack(image,GetPixelIntensity(image,p),q);
1149 p+=GetPixelChannels(image);
1150 q++;
1151 }
1152 image_view=DestroyCacheView(image_view);
1153 next=GetNextImageInList(next);
1154 }
cristy2b9582a2011-07-04 17:38:56 +00001155 if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
1156 (next != (Image *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00001157 {
1158 image_view=AcquireCacheView(next);
1159 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1160 if (p == (const Quantum *) NULL)
1161 continue;
1162 q=pixels;
1163 for (x=0; x < (ssize_t) combine_image->columns; x++)
1164 {
1165 SetPixelAlpha(image,GetPixelIntensity(image,p),q);
1166 p+=GetPixelChannels(image);
1167 q++;
cristy3ed852e2009-09-05 21:47:34 +00001168 }
1169 image_view=DestroyCacheView(image_view);
1170 next=GetNextImageInList(next);
1171 }
1172 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1173 status=MagickFalse;
1174 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1175 {
1176 MagickBooleanType
1177 proceed;
1178
cristy3ed852e2009-09-05 21:47:34 +00001179 proceed=SetImageProgress(image,CombineImageTag,progress++,
1180 combine_image->rows);
1181 if (proceed == MagickFalse)
1182 status=MagickFalse;
1183 }
1184 }
1185 combine_view=DestroyCacheView(combine_view);
1186 if (status == MagickFalse)
1187 combine_image=DestroyImage(combine_image);
1188 return(combine_image);
1189}
1190
1191/*
1192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193% %
1194% %
1195% %
cristy3ed852e2009-09-05 21:47:34 +00001196% D e s t r o y I m a g e %
1197% %
1198% %
1199% %
1200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201%
1202% DestroyImage() dereferences an image, deallocating memory associated with
1203% the image if the reference count becomes zero.
1204%
1205% The format of the DestroyImage method is:
1206%
1207% Image *DestroyImage(Image *image)
1208%
1209% A description of each parameter follows:
1210%
1211% o image: the image.
1212%
1213*/
1214MagickExport Image *DestroyImage(Image *image)
1215{
1216 MagickBooleanType
1217 destroy;
1218
1219 /*
1220 Dereference image.
1221 */
1222 assert(image != (Image *) NULL);
1223 assert(image->signature == MagickSignature);
1224 if (image->debug != MagickFalse)
1225 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1226 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001227 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001228 image->reference_count--;
1229 if (image->reference_count == 0)
1230 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001231 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001232 if (destroy == MagickFalse)
1233 return((Image *) NULL);
1234 /*
1235 Destroy image.
1236 */
1237 DestroyImagePixels(image);
cristy4c08aed2011-07-01 19:47:50 +00001238 image->component_map=DestroyPixelComponentMap(image->component_map);
cristy3ed852e2009-09-05 21:47:34 +00001239 if (image->clip_mask != (Image *) NULL)
1240 image->clip_mask=DestroyImage(image->clip_mask);
1241 if (image->mask != (Image *) NULL)
1242 image->mask=DestroyImage(image->mask);
1243 if (image->montage != (char *) NULL)
1244 image->montage=DestroyString(image->montage);
1245 if (image->directory != (char *) NULL)
1246 image->directory=DestroyString(image->directory);
1247 if (image->colormap != (PixelPacket *) NULL)
1248 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1249 if (image->geometry != (char *) NULL)
1250 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001251 DestroyImageProfiles(image);
1252 DestroyImageProperties(image);
1253 DestroyImageArtifacts(image);
1254 if (image->ascii85 != (Ascii85Info*) NULL)
1255 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1256 DestroyBlob(image);
1257 (void) DestroyExceptionInfo(&image->exception);
1258 if (image->semaphore != (SemaphoreInfo *) NULL)
1259 DestroySemaphoreInfo(&image->semaphore);
1260 image->signature=(~MagickSignature);
1261 image=(Image *) RelinquishMagickMemory(image);
1262 return(image);
1263}
1264
1265/*
1266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267% %
1268% %
1269% %
1270% D e s t r o y I m a g e I n f o %
1271% %
1272% %
1273% %
1274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275%
1276% DestroyImageInfo() deallocates memory associated with an ImageInfo
1277% structure.
1278%
1279% The format of the DestroyImageInfo method is:
1280%
1281% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1282%
1283% A description of each parameter follows:
1284%
1285% o image_info: the image info.
1286%
1287*/
1288MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1289{
1290 assert(image_info != (ImageInfo *) NULL);
1291 assert(image_info->signature == MagickSignature);
1292 if (image_info->debug != MagickFalse)
1293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1294 image_info->filename);
1295 if (image_info->size != (char *) NULL)
1296 image_info->size=DestroyString(image_info->size);
1297 if (image_info->extract != (char *) NULL)
1298 image_info->extract=DestroyString(image_info->extract);
1299 if (image_info->scenes != (char *) NULL)
1300 image_info->scenes=DestroyString(image_info->scenes);
1301 if (image_info->page != (char *) NULL)
1302 image_info->page=DestroyString(image_info->page);
1303 if (image_info->sampling_factor != (char *) NULL)
1304 image_info->sampling_factor=DestroyString(
1305 image_info->sampling_factor);
1306 if (image_info->server_name != (char *) NULL)
1307 image_info->server_name=DestroyString(
1308 image_info->server_name);
1309 if (image_info->font != (char *) NULL)
1310 image_info->font=DestroyString(image_info->font);
1311 if (image_info->texture != (char *) NULL)
1312 image_info->texture=DestroyString(image_info->texture);
1313 if (image_info->density != (char *) NULL)
1314 image_info->density=DestroyString(image_info->density);
1315 if (image_info->view != (char *) NULL)
1316 image_info->view=DestroyString(image_info->view);
1317 if (image_info->authenticate != (char *) NULL)
1318 image_info->authenticate=DestroyString(
1319 image_info->authenticate);
1320 DestroyImageOptions(image_info);
1321 if (image_info->cache != (void *) NULL)
1322 image_info->cache=DestroyPixelCache(image_info->cache);
1323 if (image_info->profile != (StringInfo *) NULL)
1324 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1325 image_info->profile);
1326 image_info->signature=(~MagickSignature);
1327 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1328 return(image_info);
1329}
1330
1331/*
1332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333% %
1334% %
1335% %
1336+ D i s a s s o c i a t e I m a g e S t r e a m %
1337% %
1338% %
1339% %
1340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341%
1342% DisassociateImageStream() disassociates the image stream.
1343%
1344% The format of the DisassociateImageStream method is:
1345%
1346% MagickBooleanType DisassociateImageStream(const Image *image)
1347%
1348% A description of each parameter follows:
1349%
1350% o image: the image.
1351%
1352*/
1353MagickExport void DisassociateImageStream(Image *image)
1354{
1355 assert(image != (const Image *) NULL);
1356 assert(image->signature == MagickSignature);
1357 if (image->debug != MagickFalse)
1358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1359 (void) DetachBlob(image->blob);
1360}
1361
1362/*
1363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364% %
1365% %
1366% %
1367% G e t I m a g e A l p h a C h a n n e l %
1368% %
1369% %
1370% %
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372%
1373% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1374% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1375% than CMYKA.
1376%
1377% The format of the GetImageAlphaChannel method is:
1378%
1379% MagickBooleanType GetImageAlphaChannel(const Image *image)
1380%
1381% A description of each parameter follows:
1382%
1383% o image: the image.
1384%
1385*/
1386MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1387{
1388 assert(image != (const Image *) NULL);
1389 if (image->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1391 assert(image->signature == MagickSignature);
1392 return(image->matte);
1393}
1394
1395/*
1396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397% %
1398% %
1399% %
1400% G e t I m a g e C l i p M a s k %
1401% %
1402% %
1403% %
1404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1405%
1406% GetImageClipMask() returns the clip path associated with the image.
1407%
1408% The format of the GetImageClipMask method is:
1409%
1410% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1411%
1412% A description of each parameter follows:
1413%
1414% o image: the image.
1415%
1416*/
1417MagickExport Image *GetImageClipMask(const Image *image,
1418 ExceptionInfo *exception)
1419{
1420 assert(image != (const Image *) NULL);
1421 if (image->debug != MagickFalse)
1422 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1423 assert(image->signature == MagickSignature);
1424 if (image->clip_mask == (Image *) NULL)
1425 return((Image *) NULL);
1426 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1427}
1428
1429/*
1430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1431% %
1432% %
1433% %
1434% G e t I m a g e E x c e p t i o n %
1435% %
1436% %
1437% %
1438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439%
1440% GetImageException() traverses an image sequence and returns any
1441% error more severe than noted by the exception parameter.
1442%
1443% The format of the GetImageException method is:
1444%
1445% void GetImageException(Image *image,ExceptionInfo *exception)
1446%
1447% A description of each parameter follows:
1448%
1449% o image: Specifies a pointer to a list of one or more images.
1450%
1451% o exception: return the highest severity exception.
1452%
1453*/
1454MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1455{
1456 register Image
1457 *next;
1458
1459 assert(image != (Image *) NULL);
1460 assert(image->signature == MagickSignature);
1461 if (image->debug != MagickFalse)
1462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1463 assert(exception != (ExceptionInfo *) NULL);
1464 assert(exception->signature == MagickSignature);
1465 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1466 {
1467 if (next->exception.severity == UndefinedException)
1468 continue;
1469 if (next->exception.severity > exception->severity)
1470 InheritException(exception,&next->exception);
1471 next->exception.severity=UndefinedException;
1472 }
1473}
1474
1475/*
1476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477% %
1478% %
1479% %
1480% G e t I m a g e I n f o %
1481% %
1482% %
1483% %
1484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485%
1486% GetImageInfo() initializes image_info to default values.
1487%
1488% The format of the GetImageInfo method is:
1489%
1490% void GetImageInfo(ImageInfo *image_info)
1491%
1492% A description of each parameter follows:
1493%
1494% o image_info: the image info.
1495%
1496*/
1497MagickExport void GetImageInfo(ImageInfo *image_info)
1498{
cristyd9a29192010-10-16 16:49:53 +00001499 const char
1500 *synchronize;
1501
cristy3ed852e2009-09-05 21:47:34 +00001502 ExceptionInfo
1503 *exception;
1504
1505 /*
1506 File and image dimension members.
1507 */
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1509 assert(image_info != (ImageInfo *) NULL);
1510 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1511 image_info->adjoin=MagickTrue;
1512 image_info->interlace=NoInterlace;
1513 image_info->channel=DefaultChannels;
1514 image_info->quality=UndefinedCompressionQuality;
1515 image_info->antialias=MagickTrue;
1516 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001517 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1518 if (synchronize != (const char *) NULL)
1519 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001520 exception=AcquireExceptionInfo();
1521 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1522 exception);
1523 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1524 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1525 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1526 exception);
1527 exception=DestroyExceptionInfo(exception);
1528 image_info->debug=IsEventLogging();
1529 image_info->signature=MagickSignature;
1530}
1531
1532/*
1533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534% %
1535% %
1536% %
cristy15781e52009-12-05 23:05:27 +00001537% G e t I m a g e I n f o F i l e %
1538% %
1539% %
1540% %
1541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542%
1543% GetImageInfoFile() returns the image info file member.
1544%
1545% The format of the GetImageInfoFile method is:
1546%
1547% FILE *GetImageInfoFile(const ImageInfo *image_info)
1548%
1549% A description of each parameter follows:
1550%
1551% o image_info: the image info.
1552%
1553*/
1554MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1555{
1556 return(image_info->file);
1557}
1558
1559/*
1560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561% %
1562% %
1563% %
cristy3ed852e2009-09-05 21:47:34 +00001564% G e t I m a g e M a s k %
1565% %
1566% %
1567% %
1568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1569%
1570% GetImageMask() returns the mask associated with the image.
1571%
1572% The format of the GetImageMask method is:
1573%
1574% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1575%
1576% A description of each parameter follows:
1577%
1578% o image: the image.
1579%
1580*/
1581MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1582{
1583 assert(image != (const Image *) NULL);
1584 if (image->debug != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1586 assert(image->signature == MagickSignature);
1587 if (image->mask == (Image *) NULL)
1588 return((Image *) NULL);
1589 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1590}
1591
1592/*
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594% %
1595% %
1596% %
1597+ G e t I m a g e R e f e r e n c e C o u n t %
1598% %
1599% %
1600% %
1601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602%
1603% GetImageReferenceCount() returns the image reference count.
1604%
1605% The format of the GetReferenceCount method is:
1606%
cristybb503372010-05-27 20:51:26 +00001607% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001608%
1609% A description of each parameter follows:
1610%
1611% o image: the image.
1612%
1613*/
cristybb503372010-05-27 20:51:26 +00001614MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001615{
cristybb503372010-05-27 20:51:26 +00001616 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001617 reference_count;
1618
1619 assert(image != (Image *) NULL);
1620 assert(image->signature == MagickSignature);
1621 if (image->debug != MagickFalse)
1622 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001623 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001624 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001625 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001626 return(reference_count);
1627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
cristy3ed852e2009-09-05 21:47:34 +00001634% G e t I m a g e V i r t u a l P i x e l M e t h o d %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1641% image. A virtual pixel is any pixel access that is outside the boundaries
1642% of the image cache.
1643%
1644% The format of the GetImageVirtualPixelMethod() method is:
1645%
1646% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1654{
1655 assert(image != (Image *) NULL);
1656 assert(image->signature == MagickSignature);
1657 if (image->debug != MagickFalse)
1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1659 return(GetPixelCacheVirtualMethod(image));
1660}
1661
1662/*
1663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1664% %
1665% %
1666% %
1667% I n t e r p r e t I m a g e F i l e n a m e %
1668% %
1669% %
1670% %
1671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672%
1673% InterpretImageFilename() interprets embedded characters in an image filename.
1674% The filename length is returned.
1675%
1676% The format of the InterpretImageFilename method is:
1677%
1678% size_t InterpretImageFilename(const ImageInfo *image_info,
1679% Image *image,const char *format,int value,char *filename)
1680%
1681% A description of each parameter follows.
1682%
1683% o image_info: the image info..
1684%
1685% o image: the image.
1686%
1687% o format: A filename describing the format to use to write the numeric
1688% argument. Only the first numeric format identifier is replaced.
1689%
1690% o value: Numeric value to substitute into format filename.
1691%
1692% o filename: return the formatted filename in this character buffer.
1693%
1694*/
1695MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1696 Image *image,const char *format,int value,char *filename)
1697{
1698 char
1699 *q;
1700
1701 int
1702 c;
1703
1704 MagickBooleanType
1705 canonical;
1706
1707 register const char
1708 *p;
1709
1710 canonical=MagickFalse;
1711 (void) CopyMagickString(filename,format,MaxTextExtent);
1712 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1713 {
1714 q=(char *) p+1;
1715 if (*q == '%')
1716 {
1717 p=q+1;
1718 continue;
1719 }
1720 if (*q == '0')
1721 {
cristybb503372010-05-27 20:51:26 +00001722 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001723 value;
1724
cristybb503372010-05-27 20:51:26 +00001725 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001726 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001727 }
1728 switch (*q)
1729 {
1730 case 'd':
1731 case 'o':
1732 case 'x':
1733 {
1734 q++;
1735 c=(*q);
1736 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001737 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001738 (p-format)),p,value);
1739 *q=c;
1740 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1741 canonical=MagickTrue;
1742 if (*(q-1) != '%')
1743 break;
1744 p++;
1745 break;
1746 }
1747 case '[':
1748 {
1749 char
1750 pattern[MaxTextExtent];
1751
1752 const char
1753 *value;
1754
cristy3ed852e2009-09-05 21:47:34 +00001755 register char
1756 *r;
1757
cristybb503372010-05-27 20:51:26 +00001758 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001759 i;
1760
cristycb6d09b2010-06-19 01:59:36 +00001761 ssize_t
1762 depth;
1763
cristy3ed852e2009-09-05 21:47:34 +00001764 /*
1765 Image option.
1766 */
1767 if (strchr(p,']') == (char *) NULL)
1768 break;
1769 depth=1;
1770 r=q+1;
1771 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1772 {
1773 if (*r == '[')
1774 depth++;
1775 if (*r == ']')
1776 depth--;
1777 if (depth <= 0)
1778 break;
1779 pattern[i]=(*r++);
1780 }
1781 pattern[i]='\0';
1782 if (LocaleNCompare(pattern,"filename:",9) != 0)
1783 break;
1784 value=(const char *) NULL;
1785 if ((image_info != (const ImageInfo *) NULL) &&
1786 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001787 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001788 else
1789 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001790 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001791 else
1792 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001793 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001794 if (value == (const char *) NULL)
1795 break;
1796 q--;
1797 c=(*q);
1798 *q='\0';
1799 (void) CopyMagickString(filename+(p-format),value,(size_t)
1800 (MaxTextExtent-(p-format)));
1801 *q=c;
1802 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1803 canonical=MagickTrue;
1804 if (*(q-1) != '%')
1805 break;
1806 p++;
1807 break;
1808 }
1809 default:
1810 break;
1811 }
1812 }
1813 for (q=filename; *q != '\0'; q++)
1814 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001815 {
1816 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1817 canonical=MagickTrue;
1818 }
cristy3ed852e2009-09-05 21:47:34 +00001819 if (canonical == MagickFalse)
1820 (void) CopyMagickString(filename,format,MaxTextExtent);
1821 return(strlen(filename));
1822}
1823
1824/*
1825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1826% %
1827% %
1828% %
1829% I s H i g h D y n a m i c R a n g e I m a g e %
1830% %
1831% %
1832% %
1833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1834%
1835% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1836% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1837% 0..65535.
1838%
1839% The format of the IsHighDynamicRangeImage method is:
1840%
1841% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1842% ExceptionInfo *exception)
1843%
1844% A description of each parameter follows:
1845%
1846% o image: the image.
1847%
1848% o exception: return any errors or warnings in this structure.
1849%
1850*/
1851MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1852 ExceptionInfo *exception)
1853{
1854#if !defined(MAGICKCORE_HDRI_SUPPORT)
1855 (void) image;
1856 (void) exception;
1857 return(MagickFalse);
1858#else
1859 CacheView
1860 *image_view;
1861
cristy3ed852e2009-09-05 21:47:34 +00001862 MagickBooleanType
1863 status;
1864
cristy4c08aed2011-07-01 19:47:50 +00001865 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001866 zero;
1867
cristycb6d09b2010-06-19 01:59:36 +00001868 ssize_t
1869 y;
1870
cristy3ed852e2009-09-05 21:47:34 +00001871 assert(image != (Image *) NULL);
1872 assert(image->signature == MagickSignature);
1873 if (image->debug != MagickFalse)
1874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1875 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00001876 GetPixelInfo(image,&zero);
cristy3ed852e2009-09-05 21:47:34 +00001877 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001878#if defined(MAGICKCORE_OPENMP_SUPPORT)
1879 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001880#endif
cristybb503372010-05-27 20:51:26 +00001881 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001882 {
cristy4c08aed2011-07-01 19:47:50 +00001883 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001884 pixel;
1885
cristy4c08aed2011-07-01 19:47:50 +00001886 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001887 *p;
1888
cristybb503372010-05-27 20:51:26 +00001889 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001890 x;
1891
1892 if (status == MagickFalse)
1893 continue;
1894 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001895 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001896 {
1897 status=MagickFalse;
1898 continue;
1899 }
cristy3ed852e2009-09-05 21:47:34 +00001900 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001901 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001902 {
cristy4c08aed2011-07-01 19:47:50 +00001903 SetPixelInfo(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001904 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1905 (pixel.red != (QuantumAny) pixel.red))
1906 break;
1907 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1908 (pixel.green != (QuantumAny) pixel.green))
1909 break;
1910 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1911 (pixel.blue != (QuantumAny) pixel.blue))
1912 break;
cristy3ed852e2009-09-05 21:47:34 +00001913 if (pixel.colorspace == CMYKColorspace)
1914 {
cristy4c08aed2011-07-01 19:47:50 +00001915 if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
1916 (pixel.black != (QuantumAny) pixel.black))
cristy3ed852e2009-09-05 21:47:34 +00001917 break;
1918 }
cristy4c08aed2011-07-01 19:47:50 +00001919 if (pixel.matte != MagickFalse)
1920 {
1921 if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
1922 (pixel.alpha != (QuantumAny) pixel.alpha))
1923 break;
1924 }
1925 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001926 }
cristybb503372010-05-27 20:51:26 +00001927 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001928 status=MagickFalse;
1929 }
1930 image_view=DestroyCacheView(image_view);
1931 return(status != MagickFalse ? MagickFalse : MagickTrue);
1932#endif
1933}
1934
1935/*
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937% %
1938% %
1939% %
1940% I s I m a g e O b j e c t %
1941% %
1942% %
1943% %
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945%
1946% IsImageObject() returns MagickTrue if the image sequence contains a valid
1947% set of image objects.
1948%
1949% The format of the IsImageObject method is:
1950%
1951% MagickBooleanType IsImageObject(const Image *image)
1952%
1953% A description of each parameter follows:
1954%
1955% o image: the image.
1956%
1957*/
1958MagickExport MagickBooleanType IsImageObject(const Image *image)
1959{
1960 register const Image
1961 *p;
1962
1963 assert(image != (Image *) NULL);
1964 if (image->debug != MagickFalse)
1965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1966 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1967 if (p->signature != MagickSignature)
1968 return(MagickFalse);
1969 return(MagickTrue);
1970}
1971
1972/*
1973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974% %
1975% %
1976% %
1977% I s T a i n t I m a g e %
1978% %
1979% %
1980% %
1981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982%
1983% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1984% since it was first constituted.
1985%
1986% The format of the IsTaintImage method is:
1987%
1988% MagickBooleanType IsTaintImage(const Image *image)
1989%
1990% A description of each parameter follows:
1991%
1992% o image: the image.
1993%
1994*/
1995MagickExport MagickBooleanType IsTaintImage(const Image *image)
1996{
1997 char
1998 magick[MaxTextExtent],
1999 filename[MaxTextExtent];
2000
2001 register const Image
2002 *p;
2003
2004 assert(image != (Image *) NULL);
2005 if (image->debug != MagickFalse)
2006 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2007 assert(image->signature == MagickSignature);
2008 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2009 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2010 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2011 {
2012 if (p->taint != MagickFalse)
2013 return(MagickTrue);
2014 if (LocaleCompare(p->magick,magick) != 0)
2015 return(MagickTrue);
2016 if (LocaleCompare(p->filename,filename) != 0)
2017 return(MagickTrue);
2018 }
2019 return(MagickFalse);
2020}
2021
2022/*
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024% %
2025% %
2026% %
2027% M o d i f y I m a g e %
2028% %
2029% %
2030% %
2031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2032%
2033% ModifyImage() ensures that there is only a single reference to the image
2034% to be modified, updating the provided image pointer to point to a clone of
2035% the original image if necessary.
2036%
2037% The format of the ModifyImage method is:
2038%
2039% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2040%
2041% A description of each parameter follows:
2042%
2043% o image: the image.
2044%
2045% o exception: return any errors or warnings in this structure.
2046%
2047*/
2048MagickExport MagickBooleanType ModifyImage(Image **image,
2049 ExceptionInfo *exception)
2050{
2051 Image
2052 *clone_image;
2053
2054 assert(image != (Image **) NULL);
2055 assert(*image != (Image *) NULL);
2056 assert((*image)->signature == MagickSignature);
2057 if ((*image)->debug != MagickFalse)
2058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2059 if (GetImageReferenceCount(*image) <= 1)
2060 return(MagickTrue);
2061 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002062 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002063 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002064 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002065 *image=clone_image;
2066 return(MagickTrue);
2067}
2068
2069/*
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071% %
2072% %
2073% %
2074% N e w M a g i c k I m a g e %
2075% %
2076% %
2077% %
2078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079%
2080% NewMagickImage() creates a blank image canvas of the specified size and
2081% background color.
2082%
2083% The format of the NewMagickImage method is:
2084%
2085% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002086% const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002087% const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002088%
2089% A description of each parameter follows:
2090%
2091% o image: the image.
2092%
2093% o width: the image width.
2094%
2095% o height: the image height.
2096%
2097% o background: the image color.
2098%
2099*/
2100MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002101 const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002102 const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002103{
2104 CacheView
2105 *image_view;
2106
2107 ExceptionInfo
2108 *exception;
2109
2110 Image
2111 *image;
2112
cristybb503372010-05-27 20:51:26 +00002113 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002114 y;
2115
2116 MagickBooleanType
2117 status;
2118
2119 assert(image_info != (const ImageInfo *) NULL);
2120 if (image_info->debug != MagickFalse)
2121 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2122 assert(image_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002123 assert(background != (const PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002124 image=AcquireImage(image_info);
2125 image->columns=width;
2126 image->rows=height;
2127 image->colorspace=background->colorspace;
2128 image->matte=background->matte;
2129 image->fuzz=background->fuzz;
2130 image->depth=background->depth;
2131 status=MagickTrue;
2132 exception=(&image->exception);
2133 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002134#if defined(MAGICKCORE_OPENMP_SUPPORT)
2135 #pragma omp parallel for schedule(dynamic,4) shared(status)
2136#endif
cristybb503372010-05-27 20:51:26 +00002137 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002138 {
cristy4c08aed2011-07-01 19:47:50 +00002139 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002140 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002141
cristycb6d09b2010-06-19 01:59:36 +00002142 register ssize_t
2143 x;
2144
cristy48974b92009-12-19 02:36:06 +00002145 if (status == MagickFalse)
2146 continue;
cristy3ed852e2009-09-05 21:47:34 +00002147 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002148 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002149 {
2150 status=MagickFalse;
2151 continue;
2152 }
cristybb503372010-05-27 20:51:26 +00002153 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002154 {
cristy4c08aed2011-07-01 19:47:50 +00002155 SetPixelPixelInfo(image,background,q);
2156 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002157 }
2158 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2159 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002160 }
2161 image_view=DestroyCacheView(image_view);
2162 if (status == MagickFalse)
2163 image=DestroyImage(image);
2164 return(image);
2165}
2166
2167/*
2168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169% %
2170% %
2171% %
2172% R e f e r e n c e I m a g e %
2173% %
2174% %
2175% %
2176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2177%
2178% ReferenceImage() increments the reference count associated with an image
2179% returning a pointer to the image.
2180%
2181% The format of the ReferenceImage method is:
2182%
2183% Image *ReferenceImage(Image *image)
2184%
2185% A description of each parameter follows:
2186%
2187% o image: the image.
2188%
2189*/
2190MagickExport Image *ReferenceImage(Image *image)
2191{
2192 assert(image != (Image *) NULL);
2193 if (image->debug != MagickFalse)
2194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2195 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002196 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002197 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002198 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002199 return(image);
2200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207% R e s e t I m a g e P a g e %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% ResetImagePage() resets the image page canvas and position.
2214%
2215% The format of the ResetImagePage method is:
2216%
2217% MagickBooleanType ResetImagePage(Image *image,const char *page)
2218%
2219% A description of each parameter follows:
2220%
2221% o image: the image.
2222%
2223% o page: the relative page specification.
2224%
2225*/
2226MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2227{
2228 MagickStatusType
2229 flags;
2230
2231 RectangleInfo
2232 geometry;
2233
2234 assert(image != (Image *) NULL);
2235 assert(image->signature == MagickSignature);
2236 if (image->debug != MagickFalse)
2237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2238 flags=ParseAbsoluteGeometry(page,&geometry);
2239 if ((flags & WidthValue) != 0)
2240 {
2241 if ((flags & HeightValue) == 0)
2242 geometry.height=geometry.width;
2243 image->page.width=geometry.width;
2244 image->page.height=geometry.height;
2245 }
2246 if ((flags & AspectValue) != 0)
2247 {
2248 if ((flags & XValue) != 0)
2249 image->page.x+=geometry.x;
2250 if ((flags & YValue) != 0)
2251 image->page.y+=geometry.y;
2252 }
2253 else
2254 {
2255 if ((flags & XValue) != 0)
2256 {
2257 image->page.x=geometry.x;
2258 if ((image->page.width == 0) && (geometry.x > 0))
2259 image->page.width=image->columns+geometry.x;
2260 }
2261 if ((flags & YValue) != 0)
2262 {
2263 image->page.y=geometry.y;
2264 if ((image->page.height == 0) && (geometry.y > 0))
2265 image->page.height=image->rows+geometry.y;
2266 }
2267 }
2268 return(MagickTrue);
2269}
2270
2271/*
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273% %
2274% %
2275% %
2276% S e p a r a t e I m a g e C h a n n e l %
2277% %
2278% %
2279% %
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281%
2282% SeparateImageChannel() separates a channel from the image and returns it as
2283% a grayscale image. A channel is a particular color component of each pixel
2284% in the image.
2285%
2286% The format of the SeparateImageChannel method is:
2287%
2288% MagickBooleanType SeparateImageChannel(Image *image,
2289% const ChannelType channel)
2290%
2291% A description of each parameter follows:
2292%
2293% o image: the image.
2294%
2295% o channel: Identify which channel to extract: RedChannel, GreenChannel,
cristy4c08aed2011-07-01 19:47:50 +00002296% BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
cristy3ed852e2009-09-05 21:47:34 +00002297% YellowChannel, or BlackChannel.
2298%
2299*/
2300MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2301 const ChannelType channel)
2302{
2303#define SeparateImageTag "Separate/Image"
2304
2305 CacheView
2306 *image_view;
2307
2308 ExceptionInfo
2309 *exception;
2310
cristy3ed852e2009-09-05 21:47:34 +00002311 MagickBooleanType
2312 status;
2313
cristybb503372010-05-27 20:51:26 +00002314 MagickOffsetType
2315 progress;
2316
2317 ssize_t
2318 y;
2319
cristy3ed852e2009-09-05 21:47:34 +00002320 assert(image != (Image *) NULL);
2321 assert(image->signature == MagickSignature);
2322 if (image->debug != MagickFalse)
2323 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2324 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2325 return(MagickFalse);
2326 /*
2327 Separate image channels.
2328 */
2329 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002330 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002331 image->matte=MagickTrue;
2332 progress=0;
2333 exception=(&image->exception);
2334 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002335#if defined(MAGICKCORE_OPENMP_SUPPORT)
2336 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002337#endif
cristybb503372010-05-27 20:51:26 +00002338 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002339 {
cristy4c08aed2011-07-01 19:47:50 +00002340 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002341 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002342
cristycb6d09b2010-06-19 01:59:36 +00002343 register ssize_t
2344 x;
2345
cristy3ed852e2009-09-05 21:47:34 +00002346 if (status == MagickFalse)
2347 continue;
2348 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002349 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002350 {
2351 status=MagickFalse;
2352 continue;
2353 }
cristy3ed852e2009-09-05 21:47:34 +00002354 switch (channel)
2355 {
2356 case RedChannel:
2357 {
cristybb503372010-05-27 20:51:26 +00002358 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002359 {
cristy4c08aed2011-07-01 19:47:50 +00002360 SetPixelGreen(image,GetPixelRed(image,q),q);
2361 SetPixelBlue(image,GetPixelRed(image,q),q);
2362 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002363 }
2364 break;
2365 }
2366 case GreenChannel:
2367 {
cristybb503372010-05-27 20:51:26 +00002368 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002369 {
cristy4c08aed2011-07-01 19:47:50 +00002370 SetPixelRed(image,GetPixelGreen(image,q),q);
2371 SetPixelBlue(image,GetPixelGreen(image,q),q);
2372 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002373 }
2374 break;
2375 }
2376 case BlueChannel:
2377 {
cristybb503372010-05-27 20:51:26 +00002378 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002379 {
cristy4c08aed2011-07-01 19:47:50 +00002380 SetPixelRed(image,GetPixelBlue(image,q),q);
2381 SetPixelGreen(image,GetPixelBlue(image,q),q);
2382 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002383 }
2384 break;
2385 }
cristy4c08aed2011-07-01 19:47:50 +00002386 case AlphaChannel:
cristy3ed852e2009-09-05 21:47:34 +00002387 {
cristybb503372010-05-27 20:51:26 +00002388 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002389 {
cristy4c08aed2011-07-01 19:47:50 +00002390 SetPixelRed(image,GetPixelAlpha(image,q),q);
2391 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2392 SetPixelBlue(image,GetPixelAlpha(image,q),q);
2393 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002394 }
2395 break;
2396 }
2397 case BlackChannel:
2398 {
2399 if ((image->storage_class != PseudoClass) &&
2400 (image->colorspace != CMYKColorspace))
2401 break;
cristybb503372010-05-27 20:51:26 +00002402 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002403 {
cristy4c08aed2011-07-01 19:47:50 +00002404 SetPixelRed(image,GetPixelBlack(image,q),q);
2405 SetPixelGreen(image,GetPixelBlack(image,q),q);
2406 SetPixelBlue(image,GetPixelBlack(image,q),q);
2407 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002408 }
2409 break;
2410 }
2411 case TrueAlphaChannel:
2412 {
cristybb503372010-05-27 20:51:26 +00002413 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002414 {
cristy4c08aed2011-07-01 19:47:50 +00002415 SetPixelRed(image,GetPixelAlpha(image,q),q);
2416 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2417 SetPixelBlue(image,GetPixelAlpha(image,q),q);
2418 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002419 }
2420 break;
2421 }
2422 case GrayChannels:
2423 {
cristybb503372010-05-27 20:51:26 +00002424 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002425 {
cristy4c08aed2011-07-01 19:47:50 +00002426 SetPixelAlpha(image,GetPixelIntensity(image,q),q);
2427 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002428 }
2429 break;
2430 }
2431 default:
2432 break;
2433 }
2434 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2435 status=MagickFalse;
2436 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2437 {
2438 MagickBooleanType
2439 proceed;
2440
cristyb5d5f722009-11-04 03:03:49 +00002441#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002442 #pragma omp critical (MagickCore_SeparateImageChannel)
2443#endif
2444 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2445 if (proceed == MagickFalse)
2446 status=MagickFalse;
2447 }
2448 }
2449 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002450 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002451 image->matte=MagickFalse;
2452 (void) SetImageColorspace(image,RGBColorspace);
2453 return(status);
2454}
2455
2456/*
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458% %
2459% %
2460% %
2461% S e p a r a t e I m a g e s %
2462% %
2463% %
2464% %
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466%
2467% SeparateImages() returns a separate grayscale image for each channel
2468% specified.
2469%
2470% The format of the SeparateImages method is:
2471%
2472% MagickBooleanType SeparateImages(const Image *image,
2473% const ChannelType channel,ExceptionInfo *exception)
2474%
2475% A description of each parameter follows:
2476%
2477% o image: the image.
2478%
2479% o channel: Identify which channels to extract: RedChannel, GreenChannel,
cristy4c08aed2011-07-01 19:47:50 +00002480% BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
cristy3ed852e2009-09-05 21:47:34 +00002481% YellowChannel, or BlackChannel.
2482%
2483% o exception: return any errors or warnings in this structure.
2484%
2485*/
2486MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2487 ExceptionInfo *exception)
2488{
2489 Image
2490 *images,
2491 *separate_image;
2492
2493 assert(image != (Image *) NULL);
2494 assert(image->signature == MagickSignature);
2495 if (image->debug != MagickFalse)
2496 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2497 images=NewImageList();
cristy2b9582a2011-07-04 17:38:56 +00002498 if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002499 {
2500 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2501 (void) SeparateImageChannel(separate_image,RedChannel);
2502 AppendImageToList(&images,separate_image);
2503 }
cristy2b9582a2011-07-04 17:38:56 +00002504 if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002505 {
2506 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2507 (void) SeparateImageChannel(separate_image,GreenChannel);
2508 AppendImageToList(&images,separate_image);
2509 }
cristy2b9582a2011-07-04 17:38:56 +00002510 if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002511 {
2512 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2513 (void) SeparateImageChannel(separate_image,BlueChannel);
2514 AppendImageToList(&images,separate_image);
2515 }
cristy2b9582a2011-07-04 17:38:56 +00002516 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) && (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002517 {
2518 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2519 (void) SeparateImageChannel(separate_image,BlackChannel);
2520 AppendImageToList(&images,separate_image);
2521 }
cristy2b9582a2011-07-04 17:38:56 +00002522 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002523 {
2524 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy4c08aed2011-07-01 19:47:50 +00002525 (void) SeparateImageChannel(separate_image,AlphaChannel);
cristy3ed852e2009-09-05 21:47:34 +00002526 AppendImageToList(&images,separate_image);
2527 }
2528 return(images);
2529}
2530
2531/*
2532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533% %
2534% %
2535% %
2536% S e t I m a g e A l p h a C h a n n e l %
2537% %
2538% %
2539% %
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541%
2542% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2543% channel.
2544%
2545% The format of the SetImageAlphaChannel method is:
2546%
2547% MagickBooleanType SetImageAlphaChannel(Image *image,
2548% const AlphaChannelType alpha_type)
2549%
2550% A description of each parameter follows:
2551%
2552% o image: the image.
2553%
2554% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2555% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
cristy4c08aed2011-07-01 19:47:50 +00002556% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
2557% TransparentAlphaChannel.
cristy3ed852e2009-09-05 21:47:34 +00002558%
2559*/
2560MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2561 const AlphaChannelType alpha_type)
2562{
2563 MagickBooleanType
2564 status;
2565
2566 assert(image != (Image *) NULL);
2567 if (image->debug != MagickFalse)
2568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2569 assert(image->signature == MagickSignature);
2570 status=MagickFalse;
2571 switch (alpha_type)
2572 {
2573 case ActivateAlphaChannel:
2574 {
2575 image->matte=MagickTrue;
2576 break;
2577 }
2578 case BackgroundAlphaChannel:
2579 {
2580 CacheView
2581 *image_view;
2582
2583 ExceptionInfo
2584 *exception;
2585
cristy3ed852e2009-09-05 21:47:34 +00002586 MagickBooleanType
2587 status;
2588
cristy4c08aed2011-07-01 19:47:50 +00002589 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002590 background;
2591
2592 PixelPacket
2593 pixel;
2594
cristycb6d09b2010-06-19 01:59:36 +00002595 ssize_t
2596 y;
2597
cristy3ed852e2009-09-05 21:47:34 +00002598 /*
2599 Set transparent pixels to background color.
2600 */
2601 if (image->matte == MagickFalse)
2602 break;
2603 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2604 break;
cristy4c08aed2011-07-01 19:47:50 +00002605 GetPixelInfo(image,&background);
2606 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002607 if (image->colorspace == CMYKColorspace)
2608 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002609 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002610 status=MagickTrue;
2611 exception=(&image->exception);
2612 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002613 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2614 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002615 #endif
cristybb503372010-05-27 20:51:26 +00002616 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002617 {
cristy4c08aed2011-07-01 19:47:50 +00002618 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002619 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002620
cristycb6d09b2010-06-19 01:59:36 +00002621 register ssize_t
2622 x;
2623
cristy3ed852e2009-09-05 21:47:34 +00002624 if (status == MagickFalse)
2625 continue;
2626 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2627 exception);
cristy4c08aed2011-07-01 19:47:50 +00002628 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002629 {
2630 status=MagickFalse;
2631 continue;
2632 }
cristybb503372010-05-27 20:51:26 +00002633 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002634 {
cristy4c08aed2011-07-01 19:47:50 +00002635 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002636 {
cristy4c08aed2011-07-01 19:47:50 +00002637 SetPixelRed(image,pixel.red,q);
2638 SetPixelGreen(image,pixel.green,q);
2639 SetPixelBlue(image,pixel.blue,q);
2640 if (image->colorspace == CMYKColorspace)
2641 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002642 }
cristy4c08aed2011-07-01 19:47:50 +00002643 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002644 }
cristy3ed852e2009-09-05 21:47:34 +00002645 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2646 status=MagickFalse;
2647 }
2648 image_view=DestroyCacheView(image_view);
2649 return(status);
2650 }
2651 case DeactivateAlphaChannel:
2652 {
2653 image->matte=MagickFalse;
2654 break;
2655 }
2656 case ShapeAlphaChannel:
2657 case CopyAlphaChannel:
2658 {
2659 /*
2660 Special usage case for SeparateImageChannel(): copy grayscale color to
2661 the alpha channel.
2662 */
2663 status=SeparateImageChannel(image,GrayChannels);
2664 image->matte=MagickTrue; /* make sure transparency is now on! */
2665 if (alpha_type == ShapeAlphaChannel)
2666 {
cristy4c08aed2011-07-01 19:47:50 +00002667 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002668 background;
2669
2670 /*
2671 Reset all color channels to background color.
2672 */
cristy4c08aed2011-07-01 19:47:50 +00002673 GetPixelInfo(image,&background);
2674 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002675 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002676 }
2677 break;
2678 }
2679 case ExtractAlphaChannel:
2680 {
2681 status=SeparateImageChannel(image,TrueAlphaChannel);
2682 image->matte=MagickFalse;
2683 break;
2684 }
cristy3ed852e2009-09-05 21:47:34 +00002685 case OpaqueAlphaChannel:
2686 {
cristy4c08aed2011-07-01 19:47:50 +00002687 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002688 image->matte=MagickTrue;
2689 break;
2690 }
2691 case TransparentAlphaChannel:
2692 {
cristy4c08aed2011-07-01 19:47:50 +00002693 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002694 image->matte=MagickTrue;
2695 break;
2696 }
2697 case SetAlphaChannel:
2698 {
2699 if (image->matte == MagickFalse)
2700 {
cristy4c08aed2011-07-01 19:47:50 +00002701 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002702 image->matte=MagickTrue;
2703 }
2704 break;
2705 }
2706 case UndefinedAlphaChannel:
2707 break;
2708 }
2709 return(status);
2710}
2711
2712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
2717% S e t I m a g e B a c k g r o u n d C o l o r %
2718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
2723% SetImageBackgroundColor() initializes the image pixels to the image
2724% background color. The background color is defined by the background_color
2725% member of the image structure.
2726%
2727% The format of the SetImage method is:
2728%
2729% MagickBooleanType SetImageBackgroundColor(Image *image)
2730%
2731% A description of each parameter follows:
2732%
2733% o image: the image.
2734%
2735*/
2736MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2737{
2738 CacheView
2739 *image_view;
2740
2741 ExceptionInfo
2742 *exception;
2743
cristy3ed852e2009-09-05 21:47:34 +00002744 MagickBooleanType
2745 status;
2746
cristy4c08aed2011-07-01 19:47:50 +00002747 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002748 background;
2749
2750 PixelPacket
2751 pixel;
2752
cristycb6d09b2010-06-19 01:59:36 +00002753 ssize_t
2754 y;
2755
cristy3ed852e2009-09-05 21:47:34 +00002756 assert(image != (Image *) NULL);
2757 if (image->debug != MagickFalse)
2758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2759 assert(image->signature == MagickSignature);
2760 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2761 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002762 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002763 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002764 GetPixelInfo(image,&background);
2765 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002766 if (image->colorspace == CMYKColorspace)
2767 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002768 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002769 /*
2770 Set image background color.
2771 */
2772 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002773 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002774 exception=(&image->exception);
2775 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002776 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002777 {
cristy4c08aed2011-07-01 19:47:50 +00002778 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002779 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002780
cristycb6d09b2010-06-19 01:59:36 +00002781 register ssize_t
2782 x;
2783
cristy3ed852e2009-09-05 21:47:34 +00002784 if (status == MagickFalse)
2785 continue;
2786 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002787 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002788 {
2789 status=MagickFalse;
2790 continue;
2791 }
cristybb503372010-05-27 20:51:26 +00002792 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002793 {
2794 SetPixelPacket(image,&pixel,q);
2795 if (image->colorspace == CMYKColorspace)
2796 SetPixelBlack(image,pixel.black,q);
2797 q+=GetPixelChannels(image);
2798 }
cristy3ed852e2009-09-05 21:47:34 +00002799 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2800 status=MagickFalse;
2801 }
2802 image_view=DestroyCacheView(image_view);
2803 return(status);
2804}
2805
2806/*
2807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2808% %
2809% %
2810% %
cristya5b77cb2010-05-07 19:34:48 +00002811% S e t I m a g e C o l o r %
2812% %
2813% %
2814% %
2815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2816%
2817% SetImageColor() set the entire image canvas to the specified color.
2818%
2819% The format of the SetImageColor method is:
2820%
2821% MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002822% const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002823%
2824% A description of each parameter follows:
2825%
2826% o image: the image.
2827%
2828% o background: the image color.
2829%
2830*/
2831MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002832 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002833{
2834 CacheView
2835 *image_view;
2836
2837 ExceptionInfo
2838 *exception;
2839
cristya5b77cb2010-05-07 19:34:48 +00002840 MagickBooleanType
2841 status;
2842
cristycb6d09b2010-06-19 01:59:36 +00002843 ssize_t
2844 y;
2845
cristya5b77cb2010-05-07 19:34:48 +00002846 assert(image != (Image *) NULL);
2847 if (image->debug != MagickFalse)
2848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2849 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002850 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002851 image->colorspace=color->colorspace;
2852 image->matte=color->matte;
2853 image->fuzz=color->fuzz;
2854 image->depth=color->depth;
2855 status=MagickTrue;
2856 exception=(&image->exception);
2857 image_view=AcquireCacheView(image);
2858#if defined(MAGICKCORE_OPENMP_SUPPORT)
2859 #pragma omp parallel for schedule(dynamic,4) shared(status)
2860#endif
cristybb503372010-05-27 20:51:26 +00002861 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002862 {
cristy4c08aed2011-07-01 19:47:50 +00002863 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002864 *restrict q;
2865
cristycb6d09b2010-06-19 01:59:36 +00002866 register ssize_t
2867 x;
2868
cristya5b77cb2010-05-07 19:34:48 +00002869 if (status == MagickFalse)
2870 continue;
2871 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002872 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002873 {
2874 status=MagickFalse;
2875 continue;
2876 }
cristybb503372010-05-27 20:51:26 +00002877 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002878 {
cristy4c08aed2011-07-01 19:47:50 +00002879 SetPixelPixelInfo(image,color,q);
2880 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002881 }
2882 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2883 status=MagickFalse;
2884 }
2885 image_view=DestroyCacheView(image_view);
2886 return(status);
2887}
2888
2889/*
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891% %
2892% %
2893% %
cristy3ed852e2009-09-05 21:47:34 +00002894% S e t I m a g e S t o r a g e C l a s s %
2895% %
2896% %
2897% %
2898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899%
2900% SetImageStorageClass() sets the image class: DirectClass for true color
2901% images or PseudoClass for colormapped images.
2902%
2903% The format of the SetImageStorageClass method is:
2904%
2905% MagickBooleanType SetImageStorageClass(Image *image,
2906% const ClassType storage_class)
2907%
2908% A description of each parameter follows:
2909%
2910% o image: the image.
2911%
2912% o storage_class: The image class.
2913%
2914*/
2915MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2916 const ClassType storage_class)
2917{
cristy3ed852e2009-09-05 21:47:34 +00002918 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00002919 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002920}
2921
2922/*
2923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924% %
2925% %
2926% %
2927% S e t I m a g e C l i p M a s k %
2928% %
2929% %
2930% %
2931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932%
2933% SetImageClipMask() associates a clip path with the image. The clip path
2934% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002935% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002936% pixel component from being updated when SyncAuthenticPixels() is applied.
2937%
2938% The format of the SetImageClipMask method is:
2939%
2940% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946% o clip_mask: the image clip path.
2947%
2948*/
2949MagickExport MagickBooleanType SetImageClipMask(Image *image,
2950 const Image *clip_mask)
2951{
2952 assert(image != (Image *) NULL);
2953 if (image->debug != MagickFalse)
2954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2955 assert(image->signature == MagickSignature);
2956 if (clip_mask != (const Image *) NULL)
2957 if ((clip_mask->columns != image->columns) ||
2958 (clip_mask->rows != image->rows))
2959 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2960 if (image->clip_mask != (Image *) NULL)
2961 image->clip_mask=DestroyImage(image->clip_mask);
2962 image->clip_mask=NewImageList();
2963 if (clip_mask == (Image *) NULL)
2964 return(MagickTrue);
2965 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2966 return(MagickFalse);
2967 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2968 if (image->clip_mask == (Image *) NULL)
2969 return(MagickFalse);
2970 return(MagickTrue);
2971}
2972
2973/*
2974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2975% %
2976% %
2977% %
2978% S e t I m a g e E x t e n t %
2979% %
2980% %
2981% %
2982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2983%
2984% SetImageExtent() sets the image size (i.e. columns & rows).
2985%
2986% The format of the SetImageExtent method is:
2987%
2988% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00002989% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002990%
2991% A description of each parameter follows:
2992%
2993% o image: the image.
2994%
2995% o columns: The image width in pixels.
2996%
2997% o rows: The image height in pixels.
2998%
2999*/
3000MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003001 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003002{
cristy537e2722010-09-21 15:30:59 +00003003 if ((columns == 0) || (rows == 0))
3004 return(MagickFalse);
3005 image->columns=columns;
3006 image->rows=rows;
3007 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003008}
3009
3010/*
3011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012% %
3013% %
3014% %
3015+ S e t I m a g e I n f o %
3016% %
3017% %
3018% %
3019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3020%
3021% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3022% It is set to a type of image format based on the prefix or suffix of the
3023% filename. For example, `ps:image' returns PS indicating a Postscript image.
3024% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3025% precendence over the suffix. Use an optional index enclosed in brackets
3026% after a file name to specify a desired scene of a multi-resolution image
3027% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3028% indicates success.
3029%
3030% The format of the SetImageInfo method is:
3031%
3032% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003033% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003034%
3035% A description of each parameter follows:
3036%
cristyd965a422010-03-03 17:47:35 +00003037% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003038%
cristyd965a422010-03-03 17:47:35 +00003039% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003040%
3041% o exception: return any errors or warnings in this structure.
3042%
3043*/
3044MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003045 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003046{
3047 char
3048 extension[MaxTextExtent],
3049 filename[MaxTextExtent],
3050 magic[MaxTextExtent],
3051 *q,
3052 subimage[MaxTextExtent];
3053
3054 const MagicInfo
3055 *magic_info;
3056
3057 const MagickInfo
3058 *magick_info;
3059
3060 ExceptionInfo
3061 *sans_exception;
3062
3063 Image
3064 *image;
3065
3066 MagickBooleanType
3067 status;
3068
3069 register const char
3070 *p;
3071
3072 ssize_t
3073 count;
3074
3075 unsigned char
3076 magick[2*MaxTextExtent];
3077
3078 /*
3079 Look for 'image.format' in filename.
3080 */
3081 assert(image_info != (ImageInfo *) NULL);
3082 assert(image_info->signature == MagickSignature);
3083 if (image_info->debug != MagickFalse)
3084 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3085 image_info->filename);
3086 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003087 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003088 {
cristyd965a422010-03-03 17:47:35 +00003089 GetPathComponent(image_info->filename,SubimagePath,subimage);
3090 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003091 {
cristyd965a422010-03-03 17:47:35 +00003092 /*
3093 Look for scene specification (e.g. img0001.pcd[4]).
3094 */
3095 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3096 {
3097 if (IsGeometry(subimage) != MagickFalse)
3098 (void) CloneString(&image_info->extract,subimage);
3099 }
3100 else
3101 {
cristybb503372010-05-27 20:51:26 +00003102 size_t
cristyd965a422010-03-03 17:47:35 +00003103 first,
3104 last;
cristy3ed852e2009-09-05 21:47:34 +00003105
cristyd965a422010-03-03 17:47:35 +00003106 (void) CloneString(&image_info->scenes,subimage);
3107 image_info->scene=StringToUnsignedLong(image_info->scenes);
3108 image_info->number_scenes=image_info->scene;
3109 p=image_info->scenes;
3110 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3111 {
3112 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3113 (*p == ','))
3114 p++;
cristybb503372010-05-27 20:51:26 +00003115 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003116 last=first;
3117 while (isspace((int) ((unsigned char) *q)) != 0)
3118 q++;
3119 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003120 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003121 if (first > last)
3122 Swap(first,last);
3123 if (first < image_info->scene)
3124 image_info->scene=first;
3125 if (last > image_info->number_scenes)
3126 image_info->number_scenes=last;
3127 p=q;
3128 }
3129 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003130 }
cristy3ed852e2009-09-05 21:47:34 +00003131 }
3132 }
3133 *extension='\0';
3134 GetPathComponent(image_info->filename,ExtensionPath,extension);
3135#if defined(MAGICKCORE_ZLIB_DELEGATE)
3136 if (*extension != '\0')
3137 if ((LocaleCompare(extension,"gz") == 0) ||
3138 (LocaleCompare(extension,"Z") == 0) ||
3139 (LocaleCompare(extension,"wmz") == 0))
3140 {
3141 char
3142 path[MaxTextExtent];
3143
3144 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3145 path[strlen(path)-strlen(extension)-1]='\0';
3146 GetPathComponent(path,ExtensionPath,extension);
3147 }
3148#endif
3149#if defined(MAGICKCORE_BZLIB_DELEGATE)
3150 if (*extension != '\0')
3151 if (LocaleCompare(extension,"bz2") == 0)
3152 {
3153 char
3154 path[MaxTextExtent];
3155
3156 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3157 path[strlen(path)-strlen(extension)-1]='\0';
3158 GetPathComponent(path,ExtensionPath,extension);
3159 }
3160#endif
3161 image_info->affirm=MagickFalse;
3162 sans_exception=AcquireExceptionInfo();
3163 if (*extension != '\0')
3164 {
3165 MagickFormatType
3166 format_type;
3167
cristybb503372010-05-27 20:51:26 +00003168 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003169 i;
3170
3171 static const char
3172 *format_type_formats[] =
3173 {
3174 "AUTOTRACE",
3175 "BROWSE",
3176 "DCRAW",
3177 "EDIT",
3178 "EPHEMERAL",
3179 "LAUNCH",
3180 "MPEG:DECODE",
3181 "MPEG:ENCODE",
3182 "PRINT",
3183 "PS:ALPHA",
3184 "PS:CMYK",
3185 "PS:COLOR",
3186 "PS:GRAY",
3187 "PS:MONO",
3188 "SCAN",
3189 "SHOW",
3190 "WIN",
3191 (char *) NULL
3192 };
3193
3194 /*
3195 User specified image format.
3196 */
3197 (void) CopyMagickString(magic,extension,MaxTextExtent);
3198 LocaleUpper(magic);
3199 /*
3200 Look for explicit image formats.
3201 */
3202 format_type=UndefinedFormatType;
3203 i=0;
cristydd9a2532010-02-20 19:26:46 +00003204 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003205 (format_type_formats[i] != (char *) NULL))
3206 {
3207 if ((*magic == *format_type_formats[i]) &&
3208 (LocaleCompare(magic,format_type_formats[i]) == 0))
3209 format_type=ExplicitFormatType;
3210 i++;
3211 }
3212 magick_info=GetMagickInfo(magic,sans_exception);
3213 if ((magick_info != (const MagickInfo *) NULL) &&
3214 (magick_info->format_type != UndefinedFormatType))
3215 format_type=magick_info->format_type;
3216 if (format_type == UndefinedFormatType)
3217 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3218 else
3219 if (format_type == ExplicitFormatType)
3220 {
3221 image_info->affirm=MagickTrue;
3222 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3223 }
3224 if (LocaleCompare(magic,"RGB") == 0)
3225 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3226 }
3227 /*
3228 Look for explicit 'format:image' in filename.
3229 */
3230 *magic='\0';
3231 GetPathComponent(image_info->filename,MagickPath,magic);
3232 if (*magic == '\0')
3233 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3234 else
3235 {
3236 /*
3237 User specified image format.
3238 */
3239 LocaleUpper(magic);
3240 if (IsMagickConflict(magic) == MagickFalse)
3241 {
3242 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3243 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3244 image_info->affirm=MagickTrue;
3245 else
3246 image_info->temporary=MagickTrue;
3247 }
3248 }
3249 magick_info=GetMagickInfo(magic,sans_exception);
3250 sans_exception=DestroyExceptionInfo(sans_exception);
3251 if ((magick_info == (const MagickInfo *) NULL) ||
3252 (GetMagickEndianSupport(magick_info) == MagickFalse))
3253 image_info->endian=UndefinedEndian;
3254 GetPathComponent(image_info->filename,CanonicalPath,filename);
3255 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003256 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003257 {
3258 /*
cristyd965a422010-03-03 17:47:35 +00003259 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003260 */
cristyd965a422010-03-03 17:47:35 +00003261 (void) InterpretImageFilename(image_info,(Image *) NULL,
3262 image_info->filename,(int) image_info->scene,filename);
3263 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3264 (strchr(filename,'%') == (char *) NULL))
3265 image_info->adjoin=MagickFalse;
3266 }
3267 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3268 {
3269 /*
3270 Some image formats do not support multiple frames per file.
3271 */
cristy3ed852e2009-09-05 21:47:34 +00003272 magick_info=GetMagickInfo(magic,exception);
3273 if (magick_info != (const MagickInfo *) NULL)
3274 if (GetMagickAdjoin(magick_info) == MagickFalse)
3275 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003276 }
3277 if (image_info->affirm != MagickFalse)
3278 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003279 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003280 {
3281 /*
cristyd965a422010-03-03 17:47:35 +00003282 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003283 */
cristyd965a422010-03-03 17:47:35 +00003284 image=AcquireImage(image_info);
3285 (void) CopyMagickString(image->filename,image_info->filename,
3286 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003287 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3288 if (status == MagickFalse)
3289 {
3290 image=DestroyImage(image);
3291 return(MagickFalse);
3292 }
cristyd965a422010-03-03 17:47:35 +00003293 if ((IsBlobSeekable(image) == MagickFalse) ||
3294 (IsBlobExempt(image) != MagickFalse))
3295 {
3296 /*
3297 Copy standard input or pipe to temporary file.
3298 */
3299 *filename='\0';
3300 status=ImageToFile(image,filename,exception);
3301 (void) CloseBlob(image);
3302 if (status == MagickFalse)
3303 {
3304 image=DestroyImage(image);
3305 return(MagickFalse);
3306 }
3307 SetImageInfoFile(image_info,(FILE *) NULL);
3308 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3309 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3310 if (status == MagickFalse)
3311 {
3312 image=DestroyImage(image);
3313 return(MagickFalse);
3314 }
3315 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3316 image_info->temporary=MagickTrue;
3317 }
3318 (void) ResetMagickMemory(magick,0,sizeof(magick));
3319 count=ReadBlob(image,2*MaxTextExtent,magick);
3320 (void) CloseBlob(image);
3321 image=DestroyImage(image);
3322 /*
3323 Check magic.xml configuration file.
3324 */
3325 sans_exception=AcquireExceptionInfo();
3326 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3327 if ((magic_info != (const MagicInfo *) NULL) &&
3328 (GetMagicName(magic_info) != (char *) NULL))
3329 {
3330 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3331 MaxTextExtent);
3332 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3333 if ((magick_info == (const MagickInfo *) NULL) ||
3334 (GetMagickEndianSupport(magick_info) == MagickFalse))
3335 image_info->endian=UndefinedEndian;
3336 sans_exception=DestroyExceptionInfo(sans_exception);
3337 return(MagickTrue);
3338 }
cristy3ed852e2009-09-05 21:47:34 +00003339 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3340 if ((magick_info == (const MagickInfo *) NULL) ||
3341 (GetMagickEndianSupport(magick_info) == MagickFalse))
3342 image_info->endian=UndefinedEndian;
3343 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003344 }
cristy3ed852e2009-09-05 21:47:34 +00003345 return(MagickTrue);
3346}
3347
3348/*
3349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3350% %
3351% %
3352% %
3353% S e t I m a g e I n f o B l o b %
3354% %
3355% %
3356% %
3357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3358%
3359% SetImageInfoBlob() sets the image info blob member.
3360%
3361% The format of the SetImageInfoBlob method is:
3362%
3363% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3364% const size_t length)
3365%
3366% A description of each parameter follows:
3367%
3368% o image_info: the image info.
3369%
3370% o blob: the blob.
3371%
3372% o length: the blob length.
3373%
3374*/
3375MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3376 const size_t length)
3377{
3378 assert(image_info != (ImageInfo *) NULL);
3379 assert(image_info->signature == MagickSignature);
3380 if (image_info->debug != MagickFalse)
3381 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3382 image_info->filename);
3383 image_info->blob=(void *) blob;
3384 image_info->length=length;
3385}
3386
3387/*
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389% %
3390% %
3391% %
3392% S e t I m a g e I n f o F i l e %
3393% %
3394% %
3395% %
3396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397%
3398% SetImageInfoFile() sets the image info file member.
3399%
3400% The format of the SetImageInfoFile method is:
3401%
3402% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3403%
3404% A description of each parameter follows:
3405%
3406% o image_info: the image info.
3407%
3408% o file: the file.
3409%
3410*/
3411MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3412{
3413 assert(image_info != (ImageInfo *) NULL);
3414 assert(image_info->signature == MagickSignature);
3415 if (image_info->debug != MagickFalse)
3416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3417 image_info->filename);
3418 image_info->file=file;
3419}
3420
3421/*
3422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3423% %
3424% %
3425% %
3426% S e t I m a g e M a s k %
3427% %
3428% %
3429% %
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431%
3432% SetImageMask() associates a mask with the image. The mask must be the same
3433% dimensions as the image.
3434%
3435% The format of the SetImageMask method is:
3436%
3437% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3438%
3439% A description of each parameter follows:
3440%
3441% o image: the image.
3442%
3443% o mask: the image mask.
3444%
3445*/
3446MagickExport MagickBooleanType SetImageMask(Image *image,
3447 const Image *mask)
3448{
3449 assert(image != (Image *) NULL);
3450 if (image->debug != MagickFalse)
3451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3452 assert(image->signature == MagickSignature);
3453 if (mask != (const Image *) NULL)
3454 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3455 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3456 if (image->mask != (Image *) NULL)
3457 image->mask=DestroyImage(image->mask);
3458 image->mask=NewImageList();
3459 if (mask == (Image *) NULL)
3460 return(MagickTrue);
3461 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3462 return(MagickFalse);
3463 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3464 if (image->mask == (Image *) NULL)
3465 return(MagickFalse);
3466 return(MagickTrue);
3467}
3468
3469/*
3470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3471% %
3472% %
3473% %
3474% S e t I m a g e O p a c i t y %
3475% %
3476% %
3477% %
3478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3479%
3480% SetImageOpacity() sets the opacity levels of the image.
3481%
3482% The format of the SetImageOpacity method is:
3483%
3484% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3485%
3486% A description of each parameter follows:
3487%
3488% o image: the image.
3489%
3490% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3491% fully transparent.
3492%
3493*/
3494MagickExport MagickBooleanType SetImageOpacity(Image *image,
3495 const Quantum opacity)
3496{
3497 CacheView
3498 *image_view;
3499
3500 ExceptionInfo
3501 *exception;
3502
cristy3ed852e2009-09-05 21:47:34 +00003503 MagickBooleanType
3504 status;
3505
cristycb6d09b2010-06-19 01:59:36 +00003506 ssize_t
3507 y;
3508
cristy3ed852e2009-09-05 21:47:34 +00003509 assert(image != (Image *) NULL);
3510 if (image->debug != MagickFalse)
3511 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3512 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003513 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003514 status=MagickTrue;
3515 exception=(&image->exception);
3516 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003517#if defined(MAGICKCORE_OPENMP_SUPPORT)
3518 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003519#endif
cristybb503372010-05-27 20:51:26 +00003520 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003521 {
cristy4c08aed2011-07-01 19:47:50 +00003522 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003523 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003524
cristycb6d09b2010-06-19 01:59:36 +00003525 register ssize_t
3526 x;
3527
cristy3ed852e2009-09-05 21:47:34 +00003528 if (status == MagickFalse)
3529 continue;
3530 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003531 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003532 {
3533 status=MagickFalse;
3534 continue;
3535 }
cristybb503372010-05-27 20:51:26 +00003536 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003537 {
cristy4c08aed2011-07-01 19:47:50 +00003538 SetPixelAlpha(image,opacity,q);
3539 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003540 }
3541 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3542 status=MagickFalse;
3543 }
3544 image_view=DestroyCacheView(image_view);
3545 return(status);
3546}
3547
3548/*
3549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3550% %
3551% %
3552% %
3553% S e t I m a g e T y p e %
3554% %
3555% %
3556% %
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558%
3559% SetImageType() sets the type of image. Choose from these types:
3560%
3561% Bilevel Grayscale GrayscaleMatte
3562% Palette PaletteMatte TrueColor
3563% TrueColorMatte ColorSeparation ColorSeparationMatte
3564% OptimizeType
3565%
3566% The format of the SetImageType method is:
3567%
3568% MagickBooleanType SetImageType(Image *image,const ImageType type)
3569%
3570% A description of each parameter follows:
3571%
3572% o image: the image.
3573%
3574% o type: Image type.
3575%
3576*/
3577MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3578{
3579 const char
3580 *artifact;
3581
3582 ImageInfo
3583 *image_info;
3584
3585 MagickBooleanType
3586 status;
3587
3588 QuantizeInfo
3589 *quantize_info;
3590
3591 assert(image != (Image *) NULL);
3592 if (image->debug != MagickFalse)
3593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3594 assert(image->signature == MagickSignature);
3595 status=MagickTrue;
3596 image_info=AcquireImageInfo();
3597 image_info->dither=image->dither;
3598 artifact=GetImageArtifact(image,"dither");
3599 if (artifact != (const char *) NULL)
3600 (void) SetImageOption(image_info,"dither",artifact);
3601 switch (type)
3602 {
3603 case BilevelType:
3604 {
cristy4c08aed2011-07-01 19:47:50 +00003605 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003606 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003607 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003608 {
3609 quantize_info=AcquireQuantizeInfo(image_info);
3610 quantize_info->number_colors=2;
3611 quantize_info->colorspace=GRAYColorspace;
3612 status=QuantizeImage(quantize_info,image);
3613 quantize_info=DestroyQuantizeInfo(quantize_info);
3614 }
3615 image->matte=MagickFalse;
3616 break;
3617 }
3618 case GrayscaleType:
3619 {
cristy4c08aed2011-07-01 19:47:50 +00003620 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003621 status=TransformImageColorspace(image,GRAYColorspace);
3622 image->matte=MagickFalse;
3623 break;
3624 }
3625 case GrayscaleMatteType:
3626 {
cristy4c08aed2011-07-01 19:47:50 +00003627 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003628 status=TransformImageColorspace(image,GRAYColorspace);
3629 if (image->matte == MagickFalse)
3630 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3631 break;
3632 }
3633 case PaletteType:
3634 {
cristy510d06a2011-07-06 23:43:54 +00003635 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003636 status=TransformImageColorspace(image,RGBColorspace);
3637 if ((image->storage_class == DirectClass) || (image->colors > 256))
3638 {
3639 quantize_info=AcquireQuantizeInfo(image_info);
3640 quantize_info->number_colors=256;
3641 status=QuantizeImage(quantize_info,image);
3642 quantize_info=DestroyQuantizeInfo(quantize_info);
3643 }
3644 image->matte=MagickFalse;
3645 break;
3646 }
3647 case PaletteBilevelMatteType:
3648 {
cristy510d06a2011-07-06 23:43:54 +00003649 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003650 status=TransformImageColorspace(image,RGBColorspace);
3651 if (image->matte == MagickFalse)
3652 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3653 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3654 quantize_info=AcquireQuantizeInfo(image_info);
3655 status=QuantizeImage(quantize_info,image);
3656 quantize_info=DestroyQuantizeInfo(quantize_info);
3657 break;
3658 }
3659 case PaletteMatteType:
3660 {
cristy510d06a2011-07-06 23:43:54 +00003661 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003662 status=TransformImageColorspace(image,RGBColorspace);
3663 if (image->matte == MagickFalse)
3664 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3665 quantize_info=AcquireQuantizeInfo(image_info);
3666 quantize_info->colorspace=TransparentColorspace;
3667 status=QuantizeImage(quantize_info,image);
3668 quantize_info=DestroyQuantizeInfo(quantize_info);
3669 break;
3670 }
3671 case TrueColorType:
3672 {
cristy510d06a2011-07-06 23:43:54 +00003673 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003674 status=TransformImageColorspace(image,RGBColorspace);
3675 if (image->storage_class != DirectClass)
3676 status=SetImageStorageClass(image,DirectClass);
3677 image->matte=MagickFalse;
3678 break;
3679 }
3680 case TrueColorMatteType:
3681 {
cristy510d06a2011-07-06 23:43:54 +00003682 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003683 status=TransformImageColorspace(image,RGBColorspace);
3684 if (image->storage_class != DirectClass)
3685 status=SetImageStorageClass(image,DirectClass);
3686 if (image->matte == MagickFalse)
3687 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3688 break;
3689 }
3690 case ColorSeparationType:
3691 {
3692 if (image->colorspace != CMYKColorspace)
3693 {
cristy510d06a2011-07-06 23:43:54 +00003694 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003695 status=TransformImageColorspace(image,RGBColorspace);
3696 status=TransformImageColorspace(image,CMYKColorspace);
3697 }
3698 if (image->storage_class != DirectClass)
3699 status=SetImageStorageClass(image,DirectClass);
3700 image->matte=MagickFalse;
3701 break;
3702 }
3703 case ColorSeparationMatteType:
3704 {
3705 if (image->colorspace != CMYKColorspace)
3706 {
cristy510d06a2011-07-06 23:43:54 +00003707 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003708 status=TransformImageColorspace(image,RGBColorspace);
3709 status=TransformImageColorspace(image,CMYKColorspace);
3710 }
3711 if (image->storage_class != DirectClass)
3712 status=SetImageStorageClass(image,DirectClass);
3713 if (image->matte == MagickFalse)
3714 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3715 break;
3716 }
3717 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003718 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003719 break;
3720 }
3721 image->type=type;
3722 image_info=DestroyImageInfo(image_info);
3723 return(status);
3724}
3725
3726/*
3727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3728% %
3729% %
3730% %
3731% S e t I m a g e V i r t u a l P i x e l M e t h o d %
3732% %
3733% %
3734% %
3735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736%
3737% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3738% image and returns the previous setting. A virtual pixel is any pixel access
3739% that is outside the boundaries of the image cache.
3740%
3741% The format of the SetImageVirtualPixelMethod() method is:
3742%
3743% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3744% const VirtualPixelMethod virtual_pixel_method)
3745%
3746% A description of each parameter follows:
3747%
3748% o image: the image.
3749%
3750% o virtual_pixel_method: choose the type of virtual pixel.
3751%
3752*/
3753MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3754 const VirtualPixelMethod virtual_pixel_method)
3755{
3756 assert(image != (const Image *) NULL);
3757 assert(image->signature == MagickSignature);
3758 if (image->debug != MagickFalse)
3759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3760 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3761}
3762
3763/*
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765% %
3766% %
3767% %
cristy4285d782011-02-09 20:12:28 +00003768% S m u s h I m a g e s %
3769% %
3770% %
3771% %
3772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773%
3774% SmushImages() takes all images from the current image pointer to the end
3775% of the image list and smushes them to each other top-to-bottom if the
3776% stack parameter is true, otherwise left-to-right.
3777%
3778% The current gravity setting now effects how the image is justified in the
3779% final image.
3780%
3781% The format of the SmushImages method is:
3782%
cristy4ca38e22011-02-10 02:57:49 +00003783% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003784% ExceptionInfo *exception)
3785%
3786% A description of each parameter follows:
3787%
cristy4ca38e22011-02-10 02:57:49 +00003788% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003789%
3790% o stack: A value other than 0 stacks the images top-to-bottom.
3791%
3792% o offset: minimum distance in pixels between images.
3793%
3794% o exception: return any errors or warnings in this structure.
3795%
3796*/
cristy4ca38e22011-02-10 02:57:49 +00003797
cristy7c6dc152011-02-11 14:10:55 +00003798static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003799 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003800{
cristy4d727152011-02-10 19:57:21 +00003801 CacheView
3802 *left_view,
3803 *right_view;
3804
3805 const Image
3806 *left_image,
3807 *right_image;
3808
cristy4d727152011-02-10 19:57:21 +00003809 RectangleInfo
3810 left_geometry,
3811 right_geometry;
3812
cristy4c08aed2011-07-01 19:47:50 +00003813 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003814 *p;
3815
cristy4d727152011-02-10 19:57:21 +00003816 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003817 i,
cristy4d727152011-02-10 19:57:21 +00003818 y;
3819
cristy7c6dc152011-02-11 14:10:55 +00003820 size_t
3821 gap;
3822
cristy4d727152011-02-10 19:57:21 +00003823 ssize_t
cristy4d727152011-02-10 19:57:21 +00003824 x;
3825
3826 if (images->previous == (Image *) NULL)
3827 return(0);
3828 right_image=images;
3829 SetGeometry(smush_image,&right_geometry);
3830 GravityAdjustGeometry(right_image->columns,right_image->rows,
3831 right_image->gravity,&right_geometry);
3832 left_image=images->previous;
3833 SetGeometry(smush_image,&left_geometry);
3834 GravityAdjustGeometry(left_image->columns,left_image->rows,
3835 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003836 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003837 left_view=AcquireCacheView(left_image);
3838 right_view=AcquireCacheView(right_image);
3839 for (y=0; y < (ssize_t) smush_image->rows; y++)
3840 {
3841 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3842 {
cristydab7e912011-02-11 18:19:24 +00003843 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003844 if ((p == (const Quantum *) NULL) ||
3845 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003846 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003847 break;
3848 }
cristy4ef6f062011-02-10 20:30:22 +00003849 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003850 for (x=0; x < (ssize_t) right_image->columns; x++)
3851 {
cristydab7e912011-02-11 18:19:24 +00003852 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003853 exception);
cristy4c08aed2011-07-01 19:47:50 +00003854 if ((p == (const Quantum *) NULL) ||
3855 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3856 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003857 break;
3858 }
cristy7c6dc152011-02-11 14:10:55 +00003859 if ((x+i) < (ssize_t) gap)
3860 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003861 }
3862 right_view=DestroyCacheView(right_view);
3863 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003864 if (y < (ssize_t) smush_image->rows)
3865 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003866 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003867}
3868
cristy7c6dc152011-02-11 14:10:55 +00003869static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003870 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003871{
cristy4d727152011-02-10 19:57:21 +00003872 CacheView
3873 *bottom_view,
3874 *top_view;
3875
3876 const Image
3877 *bottom_image,
3878 *top_image;
3879
cristy4d727152011-02-10 19:57:21 +00003880 RectangleInfo
3881 bottom_geometry,
3882 top_geometry;
3883
cristy4c08aed2011-07-01 19:47:50 +00003884 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003885 *p;
3886
cristy4d727152011-02-10 19:57:21 +00003887 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003888 i,
cristy4d727152011-02-10 19:57:21 +00003889 x;
3890
cristy7c6dc152011-02-11 14:10:55 +00003891 size_t
3892 gap;
3893
cristy4d727152011-02-10 19:57:21 +00003894 ssize_t
cristy4d727152011-02-10 19:57:21 +00003895 y;
3896
3897 if (images->previous == (Image *) NULL)
3898 return(0);
3899 bottom_image=images;
3900 SetGeometry(smush_image,&bottom_geometry);
3901 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3902 bottom_image->gravity,&bottom_geometry);
3903 top_image=images->previous;
3904 SetGeometry(smush_image,&top_geometry);
3905 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3906 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003907 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003908 top_view=AcquireCacheView(top_image);
3909 bottom_view=AcquireCacheView(bottom_image);
3910 for (x=0; x < (ssize_t) smush_image->columns; x++)
3911 {
3912 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3913 {
cristydab7e912011-02-11 18:19:24 +00003914 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003915 if ((p == (const Quantum *) NULL) ||
3916 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3917 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003918 break;
3919 }
cristy4ef6f062011-02-10 20:30:22 +00003920 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003921 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3922 {
cristydab7e912011-02-11 18:19:24 +00003923 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3924 exception);
cristy4c08aed2011-07-01 19:47:50 +00003925 if ((p == (const Quantum *) NULL) ||
3926 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3927 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003928 break;
3929 }
cristy7c6dc152011-02-11 14:10:55 +00003930 if ((y+i) < (ssize_t) gap)
3931 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003932 }
3933 bottom_view=DestroyCacheView(bottom_view);
3934 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003935 if (x < (ssize_t) smush_image->columns)
3936 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003937 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003938}
3939
3940MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003941 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3942{
3943#define SmushImageTag "Smush/Image"
3944
3945 CacheView
cristybb5dced2011-02-10 02:17:16 +00003946 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003947
cristy4ca38e22011-02-10 02:57:49 +00003948 const Image
3949 *image;
3950
cristy4285d782011-02-09 20:12:28 +00003951 Image
3952 *smush_image;
3953
3954 MagickBooleanType
3955 matte,
3956 proceed,
3957 status;
3958
3959 MagickOffsetType
3960 n;
3961
3962 RectangleInfo
3963 geometry;
3964
3965 register const Image
3966 *next;
3967
3968 size_t
3969 height,
3970 number_images,
3971 width;
3972
3973 ssize_t
3974 x_offset,
cristy4285d782011-02-09 20:12:28 +00003975 y_offset;
3976
3977 /*
cristy7c6dc152011-02-11 14:10:55 +00003978 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003979 */
cristy4ca38e22011-02-10 02:57:49 +00003980 assert(images != (Image *) NULL);
3981 assert(images->signature == MagickSignature);
3982 if (images->debug != MagickFalse)
3983 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003984 assert(exception != (ExceptionInfo *) NULL);
3985 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003986 image=images;
cristy4285d782011-02-09 20:12:28 +00003987 matte=image->matte;
3988 number_images=1;
3989 width=image->columns;
3990 height=image->rows;
3991 next=GetNextImageInList(image);
3992 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3993 {
3994 if (next->matte != MagickFalse)
3995 matte=MagickTrue;
3996 number_images++;
3997 if (stack != MagickFalse)
3998 {
3999 if (next->columns > width)
4000 width=next->columns;
4001 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004002 if (next->previous != (Image *) NULL)
4003 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004004 continue;
4005 }
4006 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004007 if (next->previous != (Image *) NULL)
4008 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004009 if (next->rows > height)
4010 height=next->rows;
4011 }
4012 /*
cristy7c6dc152011-02-11 14:10:55 +00004013 Smush images.
cristy4285d782011-02-09 20:12:28 +00004014 */
4015 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4016 if (smush_image == (Image *) NULL)
4017 return((Image *) NULL);
4018 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4019 {
4020 InheritException(exception,&smush_image->exception);
4021 smush_image=DestroyImage(smush_image);
4022 return((Image *) NULL);
4023 }
4024 smush_image->matte=matte;
4025 (void) SetImageBackgroundColor(smush_image);
4026 status=MagickTrue;
4027 x_offset=0;
4028 y_offset=0;
4029 smush_view=AcquireCacheView(smush_image);
4030 for (n=0; n < (MagickOffsetType) number_images; n++)
4031 {
4032 SetGeometry(smush_image,&geometry);
4033 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4034 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004035 {
4036 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004037 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004038 }
cristy4285d782011-02-09 20:12:28 +00004039 else
cristy4ca38e22011-02-10 02:57:49 +00004040 {
cristy7c6dc152011-02-11 14:10:55 +00004041 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004042 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004043 }
cristybb5dced2011-02-10 02:17:16 +00004044 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004045 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4046 if (proceed == MagickFalse)
4047 break;
4048 if (stack == MagickFalse)
4049 {
4050 x_offset+=(ssize_t) image->columns;
4051 y_offset=0;
4052 }
4053 else
4054 {
4055 x_offset=0;
4056 y_offset+=(ssize_t) image->rows;
4057 }
4058 image=GetNextImageInList(image);
4059 }
cristy4ef6f062011-02-10 20:30:22 +00004060 if (stack == MagickFalse)
4061 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004062 else
cristy4ef6f062011-02-10 20:30:22 +00004063 smush_image->rows=(size_t) y_offset;
4064 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004065 if (status == MagickFalse)
4066 smush_image=DestroyImage(smush_image);
4067 return(smush_image);
4068}
4069
4070/*
4071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4072% %
4073% %
4074% %
cristy3ed852e2009-09-05 21:47:34 +00004075% S t r i p I m a g e %
4076% %
4077% %
4078% %
4079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4080%
cristy376bda92009-12-22 21:15:23 +00004081% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004082%
4083% The format of the StripImage method is:
4084%
4085% MagickBooleanType StripImage(Image *image)
4086%
4087% A description of each parameter follows:
4088%
4089% o image: the image.
4090%
4091*/
4092MagickExport MagickBooleanType StripImage(Image *image)
4093{
4094 assert(image != (Image *) NULL);
4095 if (image->debug != MagickFalse)
4096 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4097 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004098 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004099 (void) DeleteImageProperty(image,"date:create");
4100 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004101 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004102 return(MagickTrue);
4103}
4104
4105/*
4106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4107% %
4108% %
4109% %
4110+ S y n c I m a g e %
4111% %
4112% %
4113% %
4114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4115%
4116% SyncImage() initializes the red, green, and blue intensities of each pixel
4117% as defined by the colormap index.
4118%
4119% The format of the SyncImage method is:
4120%
4121% MagickBooleanType SyncImage(Image *image)
4122%
4123% A description of each parameter follows:
4124%
4125% o image: the image.
4126%
4127*/
4128
cristy4c08aed2011-07-01 19:47:50 +00004129static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004130 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004131{
4132 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004133 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004134 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004135 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004136}
4137
4138MagickExport MagickBooleanType SyncImage(Image *image)
4139{
4140 CacheView
4141 *image_view;
4142
4143 ExceptionInfo
4144 *exception;
4145
cristy3ed852e2009-09-05 21:47:34 +00004146 MagickBooleanType
4147 range_exception,
4148 status;
4149
cristycb6d09b2010-06-19 01:59:36 +00004150 ssize_t
4151 y;
4152
cristy3ed852e2009-09-05 21:47:34 +00004153 assert(image != (Image *) NULL);
4154 if (image->debug != MagickFalse)
4155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4156 assert(image->signature == MagickSignature);
4157 if (image->storage_class == DirectClass)
4158 return(MagickFalse);
4159 range_exception=MagickFalse;
4160 status=MagickTrue;
4161 exception=(&image->exception);
4162 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004163#if defined(MAGICKCORE_OPENMP_SUPPORT)
4164 #pragma omp parallel for schedule(dynamic,4) shared(status)
4165#endif
cristybb503372010-05-27 20:51:26 +00004166 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004167 {
cristy4c08aed2011-07-01 19:47:50 +00004168 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004169 index;
4170
cristy4c08aed2011-07-01 19:47:50 +00004171 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004172 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004173
cristycb6d09b2010-06-19 01:59:36 +00004174 register ssize_t
4175 x;
4176
cristy48974b92009-12-19 02:36:06 +00004177 if (status == MagickFalse)
4178 continue;
cristy3ed852e2009-09-05 21:47:34 +00004179 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004180 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004181 {
4182 status=MagickFalse;
4183 continue;
4184 }
cristybb503372010-05-27 20:51:26 +00004185 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004186 {
cristy4c08aed2011-07-01 19:47:50 +00004187 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004188 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004189 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
4190 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004191 }
4192 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4193 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004194 }
4195 image_view=DestroyCacheView(image_view);
4196 if (range_exception != MagickFalse)
4197 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4198 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4199 return(status);
4200}
cristy1626d332009-11-10 16:58:17 +00004201
4202/*
4203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4204% %
4205% %
4206% %
4207% S y n c I m a g e S e t t i n g s %
4208% %
4209% %
4210% %
4211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4212%
4213% SyncImageSettings() sync the image info options to the image.
4214%
4215% The format of the SyncImageSettings method is:
4216%
4217% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4218% Image *image)
4219% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4220% Image *image)
4221%
4222% A description of each parameter follows:
4223%
4224% o image_info: the image info.
4225%
4226% o image: the image.
4227%
4228*/
4229
4230MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4231 Image *images)
4232{
4233 Image
4234 *image;
4235
4236 assert(image_info != (const ImageInfo *) NULL);
4237 assert(image_info->signature == MagickSignature);
4238 assert(images != (Image *) NULL);
4239 assert(images->signature == MagickSignature);
4240 if (images->debug != MagickFalse)
4241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4242 image=images;
4243 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4244 (void) SyncImageSettings(image_info,image);
4245 (void) DeleteImageOption(image_info,"page");
4246 return(MagickTrue);
4247}
4248
4249MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4250 Image *image)
4251{
4252 char
4253 property[MaxTextExtent];
4254
4255 const char
cristy9a703812010-07-26 14:50:29 +00004256 *option,
4257 *value;
cristy1626d332009-11-10 16:58:17 +00004258
4259 GeometryInfo
4260 geometry_info;
4261
4262 MagickStatusType
4263 flags;
4264
cristy19eb6412010-04-23 14:42:29 +00004265 ResolutionType
4266 units;
4267
cristy1626d332009-11-10 16:58:17 +00004268 /*
4269 Sync image options.
4270 */
4271 assert(image_info != (const ImageInfo *) NULL);
4272 assert(image_info->signature == MagickSignature);
4273 assert(image != (Image *) NULL);
4274 assert(image->signature == MagickSignature);
4275 if (image->debug != MagickFalse)
4276 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4277 option=GetImageOption(image_info,"background");
4278 if (option != (const char *) NULL)
4279 (void) QueryColorDatabase(option,&image->background_color,
4280 &image->exception);
4281 option=GetImageOption(image_info,"bias");
4282 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004283 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004284 option=GetImageOption(image_info,"black-point-compensation");
4285 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004286 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004287 MagickBooleanOptions,MagickFalse,option);
4288 option=GetImageOption(image_info,"blue-primary");
4289 if (option != (const char *) NULL)
4290 {
4291 flags=ParseGeometry(option,&geometry_info);
4292 image->chromaticity.blue_primary.x=geometry_info.rho;
4293 image->chromaticity.blue_primary.y=geometry_info.sigma;
4294 if ((flags & SigmaValue) == 0)
4295 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4296 }
4297 option=GetImageOption(image_info,"bordercolor");
4298 if (option != (const char *) NULL)
4299 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4300 option=GetImageOption(image_info,"colors");
4301 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004302 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004303 option=GetImageOption(image_info,"compose");
4304 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004305 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004306 MagickFalse,option);
4307 option=GetImageOption(image_info,"compress");
4308 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004309 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004310 MagickCompressOptions,MagickFalse,option);
4311 option=GetImageOption(image_info,"debug");
4312 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004313 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004314 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004315 option=GetImageOption(image_info,"density");
4316 if (option != (const char *) NULL)
4317 {
4318 GeometryInfo
4319 geometry_info;
4320
4321 /*
4322 Set image density.
4323 */
4324 flags=ParseGeometry(option,&geometry_info);
4325 image->x_resolution=geometry_info.rho;
4326 image->y_resolution=geometry_info.sigma;
4327 if ((flags & SigmaValue) == 0)
4328 image->y_resolution=image->x_resolution;
4329 }
cristy1626d332009-11-10 16:58:17 +00004330 option=GetImageOption(image_info,"depth");
4331 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004332 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004333 option=GetImageOption(image_info,"endian");
4334 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004335 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004336 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004337 option=GetImageOption(image_info,"filter");
4338 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004339 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004340 MagickFalse,option);
4341 option=GetImageOption(image_info,"fuzz");
4342 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004343 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004344 option=GetImageOption(image_info,"gravity");
4345 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004346 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004347 MagickFalse,option);
4348 option=GetImageOption(image_info,"green-primary");
4349 if (option != (const char *) NULL)
4350 {
4351 flags=ParseGeometry(option,&geometry_info);
4352 image->chromaticity.green_primary.x=geometry_info.rho;
4353 image->chromaticity.green_primary.y=geometry_info.sigma;
4354 if ((flags & SigmaValue) == 0)
4355 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4356 }
4357 option=GetImageOption(image_info,"intent");
4358 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004359 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004360 MagickIntentOptions,MagickFalse,option);
4361 option=GetImageOption(image_info,"interlace");
4362 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004363 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004364 MagickFalse,option);
4365 option=GetImageOption(image_info,"interpolate");
4366 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004367 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004368 MagickInterpolateOptions,MagickFalse,option);
4369 option=GetImageOption(image_info,"loop");
4370 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004371 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004372 option=GetImageOption(image_info,"mattecolor");
4373 if (option != (const char *) NULL)
4374 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4375 option=GetImageOption(image_info,"orient");
4376 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004377 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004378 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004379 option=GetImageOption(image_info,"page");
4380 if (option != (const char *) NULL)
4381 {
4382 char
4383 *geometry;
4384
4385 geometry=GetPageGeometry(option);
4386 flags=ParseAbsoluteGeometry(geometry,&image->page);
4387 geometry=DestroyString(geometry);
4388 }
cristy1626d332009-11-10 16:58:17 +00004389 option=GetImageOption(image_info,"quality");
4390 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004391 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004392 option=GetImageOption(image_info,"red-primary");
4393 if (option != (const char *) NULL)
4394 {
4395 flags=ParseGeometry(option,&geometry_info);
4396 image->chromaticity.red_primary.x=geometry_info.rho;
4397 image->chromaticity.red_primary.y=geometry_info.sigma;
4398 if ((flags & SigmaValue) == 0)
4399 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4400 }
4401 if (image_info->quality != UndefinedCompressionQuality)
4402 image->quality=image_info->quality;
4403 option=GetImageOption(image_info,"scene");
4404 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004405 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004406 option=GetImageOption(image_info,"taint");
4407 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004408 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004409 MagickFalse,option);
4410 option=GetImageOption(image_info,"tile-offset");
4411 if (option != (const char *) NULL)
4412 {
4413 char
4414 *geometry;
4415
4416 geometry=GetPageGeometry(option);
4417 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4418 geometry=DestroyString(geometry);
4419 }
4420 option=GetImageOption(image_info,"transparent-color");
4421 if (option != (const char *) NULL)
4422 (void) QueryColorDatabase(option,&image->transparent_color,
4423 &image->exception);
4424 option=GetImageOption(image_info,"type");
4425 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004426 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004427 option);
4428 option=GetImageOption(image_info,"units");
4429 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004430 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004431 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004432 else
4433 units = image_info->units;
4434 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004435 {
cristy19eb6412010-04-23 14:42:29 +00004436 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004437 switch (image->units)
4438 {
4439 case PixelsPerInchResolution:
4440 {
cristy19eb6412010-04-23 14:42:29 +00004441 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004442 {
4443 image->x_resolution/=2.54;
4444 image->y_resolution/=2.54;
4445 }
4446 break;
4447 }
4448 case PixelsPerCentimeterResolution:
4449 {
cristy19eb6412010-04-23 14:42:29 +00004450 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004451 {
cristybb503372010-05-27 20:51:26 +00004452 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004453 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004454 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004455 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004456 }
4457 break;
4458 }
4459 default:
4460 break;
4461 }
cristy19eb6412010-04-23 14:42:29 +00004462 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004463 }
4464 option=GetImageOption(image_info,"white-point");
4465 if (option != (const char *) NULL)
4466 {
4467 flags=ParseGeometry(option,&geometry_info);
4468 image->chromaticity.white_point.x=geometry_info.rho;
4469 image->chromaticity.white_point.y=geometry_info.sigma;
4470 if ((flags & SigmaValue) == 0)
4471 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4472 }
4473 ResetImageOptionIterator(image_info);
4474 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4475 {
4476 value=GetImageOption(image_info,option);
4477 if (value != (const char *) NULL)
4478 {
cristyb51dff52011-05-19 16:55:47 +00004479 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004480 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004481 }
4482 option=GetNextImageOption(image_info);
4483 }
4484 return(MagickTrue);
4485}