blob: 1f8610c2fcdfdc332ca6aedf04aa8ad284bf7ad5 [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);
cristyed231572011-07-14 02:18:59 +0000188 image->channel_map=AcquirePixelChannelMap();
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);
cristy574cc262011-08-05 01:23:58 +0000487 if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000488 {
cristy3ed852e2009-09-05 21:47:34 +0000489 append_image=DestroyImage(append_image);
490 return((Image *) NULL);
491 }
492 append_image->matte=matte;
493 (void) SetImageBackgroundColor(append_image);
494 status=MagickTrue;
495 x_offset=0;
496 y_offset=0;
497 append_view=AcquireCacheView(append_image);
cristybb503372010-05-27 20:51:26 +0000498 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000499 {
500 SetGeometry(append_image,&geometry);
501 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
502 if (stack != MagickFalse)
503 x_offset-=geometry.x;
504 else
505 y_offset-=geometry.y;
506 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +0000507#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1a2bd532010-11-19 02:53:15 +0000508 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
cristy3ed852e2009-09-05 21:47:34 +0000509#endif
cristybb503372010-05-27 20:51:26 +0000510 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000511 {
512 MagickBooleanType
513 sync;
514
cristy4c08aed2011-07-01 19:47:50 +0000515 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000516 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000517
cristy4c08aed2011-07-01 19:47:50 +0000518 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000519 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000520
cristycb6d09b2010-06-19 01:59:36 +0000521 register ssize_t
522 x;
523
cristy3ed852e2009-09-05 21:47:34 +0000524 if (status == MagickFalse)
525 continue;
526 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
527 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
528 image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000529 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000530 {
531 status=MagickFalse;
532 continue;
533 }
cristybb503372010-05-27 20:51:26 +0000534 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000535 {
cristy4c08aed2011-07-01 19:47:50 +0000536 SetPixelRed(append_image,GetPixelRed(image,p),q);
537 SetPixelGreen(append_image,GetPixelGreen(image,p),q);
538 SetPixelBlue(append_image,GetPixelBlue(image,p),q);
cristyff775322011-02-24 15:05:25 +0000539 if ((image->colorspace == CMYKColorspace) &&
540 (append_image->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +0000541 SetPixelBlack(append_image,GetPixelBlack(image,p),q);
542 SetPixelAlpha(append_image,OpaqueAlpha,q);
543 if (image->matte != MagickFalse)
544 SetPixelAlpha(append_image,GetPixelAlpha(image,p),q);
cristyed231572011-07-14 02:18:59 +0000545 p+=GetPixelChannels(image);
546 q+=GetPixelChannels(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000547 }
548 sync=SyncCacheViewAuthenticPixels(append_view,exception);
549 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000550 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000551 }
552 image_view=DestroyCacheView(image_view);
553 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
554 if (proceed == MagickFalse)
555 break;
556 if (stack == MagickFalse)
557 {
cristyeaedf062010-05-29 22:36:02 +0000558 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000559 y_offset=0;
560 }
561 else
562 {
563 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000564 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000565 }
566 image=GetNextImageInList(image);
567 }
568 append_view=DestroyCacheView(append_view);
569 if (status == MagickFalse)
570 append_image=DestroyImage(append_image);
571 return(append_image);
572}
573
574/*
575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576% %
577% %
578% %
cristy3ed852e2009-09-05 21:47:34 +0000579% C a t c h I m a g e E x c e p t i o n %
580% %
581% %
582% %
583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584%
585% CatchImageException() returns if no exceptions are found in the image
586% sequence, otherwise it determines the most severe exception and reports
587% it as a warning or error depending on the severity.
588%
589% The format of the CatchImageException method is:
590%
591% ExceptionType CatchImageException(Image *image)
592%
593% A description of each parameter follows:
594%
595% o image: An image sequence.
596%
597*/
598MagickExport ExceptionType CatchImageException(Image *image)
599{
600 ExceptionInfo
601 *exception;
602
603 ExceptionType
604 severity;
605
606 assert(image != (const Image *) NULL);
607 assert(image->signature == MagickSignature);
608 if (image->debug != MagickFalse)
609 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
610 exception=AcquireExceptionInfo();
611 GetImageException(image,exception);
612 CatchException(exception);
613 severity=exception->severity;
614 exception=DestroyExceptionInfo(exception);
615 return(severity);
616}
617
618/*
619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620% %
621% %
622% %
623% C l i p I m a g e P a t h %
624% %
625% %
626% %
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628%
629% ClipImagePath() sets the image clip mask based any clipping path information
630% if it exists.
631%
632% The format of the ClipImagePath method is:
633%
634% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
635% const MagickBooleanType inside)
636%
637% A description of each parameter follows:
638%
639% o image: the image.
640%
641% o pathname: name of clipping path resource. If name is preceded by #, use
642% clipping path numbered by name.
643%
644% o inside: if non-zero, later operations take effect inside clipping path.
645% Otherwise later operations take effect outside clipping path.
646%
647*/
648
649MagickExport MagickBooleanType ClipImage(Image *image)
650{
651 return(ClipImagePath(image,"#1",MagickTrue));
652}
653
654MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
655 const MagickBooleanType inside)
656{
657#define ClipImagePathTag "ClipPath/Image"
658
659 char
660 *property;
661
662 const char
663 *value;
664
665 Image
666 *clip_mask;
667
668 ImageInfo
669 *image_info;
670
671 assert(image != (const Image *) NULL);
672 assert(image->signature == MagickSignature);
673 if (image->debug != MagickFalse)
674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
675 assert(pathname != NULL);
676 property=AcquireString(pathname);
cristyb51dff52011-05-19 16:55:47 +0000677 (void) FormatLocaleString(property,MaxTextExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000678 pathname);
679 value=GetImageProperty(image,property);
680 property=DestroyString(property);
681 if (value == (const char *) NULL)
682 {
683 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
684 image->filename);
685 return(MagickFalse);
686 }
687 image_info=AcquireImageInfo();
688 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
689 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
690 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
691 image_info=DestroyImageInfo(image_info);
692 if (clip_mask == (Image *) NULL)
693 return(MagickFalse);
694 if (clip_mask->storage_class == PseudoClass)
695 {
696 (void) SyncImage(clip_mask);
cristy574cc262011-08-05 01:23:58 +0000697 if (SetImageStorageClass(clip_mask,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000698 return(MagickFalse);
699 }
700 if (inside == MagickFalse)
cristyb3e7c6c2011-07-24 01:43:55 +0000701 (void) NegateImage(clip_mask,MagickFalse,&image->exception);
cristyb51dff52011-05-19 16:55:47 +0000702 (void) FormatLocaleString(clip_mask->magick_filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000703 "8BIM:1999,2998:%s\nPS",pathname);
704 (void) SetImageClipMask(image,clip_mask);
705 clip_mask=DestroyImage(clip_mask);
706 return(MagickTrue);
707}
708
709/*
710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711% %
712% %
713% %
714% C l o n e I m a g e %
715% %
716% %
717% %
718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719%
720% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000721%
cristy3ed852e2009-09-05 21:47:34 +0000722% If the specified columns and rows is 0, an exact copy of the image is
723% returned, otherwise the pixel data is undefined and must be initialized
724% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
725% failure, a NULL image is returned and exception describes the reason for the
726% failure.
727%
728% The format of the CloneImage method is:
729%
cristybb503372010-05-27 20:51:26 +0000730% Image *CloneImage(const Image *image,const size_t columns,
731% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000732% ExceptionInfo *exception)
733%
734% A description of each parameter follows:
735%
736% o image: the image.
737%
738% o columns: the number of columns in the cloned image.
739%
740% o rows: the number of rows in the cloned image.
741%
742% o detach: With a value other than 0, the cloned image is detached from
743% its parent I/O stream.
744%
745% o exception: return any errors or warnings in this structure.
746%
747*/
cristybb503372010-05-27 20:51:26 +0000748MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000749 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000750{
751 Image
752 *clone_image;
753
754 MagickRealType
755 scale;
756
757 size_t
758 length;
759
760 /*
761 Clone the image.
762 */
763 assert(image != (const Image *) NULL);
764 assert(image->signature == MagickSignature);
765 if (image->debug != MagickFalse)
766 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
767 assert(exception != (ExceptionInfo *) NULL);
768 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000769 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000770 if (clone_image == (Image *) NULL)
771 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
772 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
773 clone_image->signature=MagickSignature;
774 clone_image->storage_class=image->storage_class;
cristyed231572011-07-14 02:18:59 +0000775 clone_image->number_channels=image->number_channels;
cristyb3a73b52011-07-26 01:34:43 +0000776 clone_image->number_meta_channels=image->number_meta_channels;
cristy4c08aed2011-07-01 19:47:50 +0000777 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;
cristye23ec9d2011-08-16 18:15:40 +0000808 clone_image->sync=image->sync;
cristy5e0890f2011-07-07 23:30:35 +0000809 clone_image->map=image->map;
cristyed231572011-07-14 02:18:59 +0000810 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +0000811 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
812 MaxTextExtent);
813 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
814 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
815 clone_image->progress_monitor=image->progress_monitor;
816 clone_image->client_data=image->client_data;
817 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000818 clone_image->next=image->next;
819 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000820 clone_image->list=NewImageList();
821 clone_image->clip_mask=NewImageList();
822 clone_image->mask=NewImageList();
823 if (detach == MagickFalse)
824 clone_image->blob=ReferenceBlob(image->blob);
825 else
cristybee00932011-01-15 20:28:27 +0000826 {
827 clone_image->next=NewImageList();
828 clone_image->previous=NewImageList();
829 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
830 }
cristy73724512010-04-12 14:43:14 +0000831 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000832 clone_image->debug=IsEventLogging();
833 clone_image->semaphore=AllocateSemaphoreInfo();
834 if ((columns == 0) && (rows == 0))
835 {
836 if (image->montage != (char *) NULL)
837 (void) CloneString(&clone_image->montage,image->montage);
838 if (image->directory != (char *) NULL)
839 (void) CloneString(&clone_image->directory,image->directory);
840 if (image->clip_mask != (Image *) NULL)
841 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
842 exception);
843 if (image->mask != (Image *) NULL)
844 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
845 clone_image->cache=ReferencePixelCache(image->cache);
846 return(clone_image);
847 }
cristy1ab35fb2011-04-15 01:25:56 +0000848 if ((columns == image->columns) && (rows == image->rows))
849 {
850 if (image->clip_mask != (Image *) NULL)
851 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
852 exception);
853 if (image->mask != (Image *) NULL)
854 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
855 }
cristy3ed852e2009-09-05 21:47:34 +0000856 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000857 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
858 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
859 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000860 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000861 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
862 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
863 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000864 clone_image->columns=columns;
865 clone_image->rows=rows;
866 clone_image->cache=ClonePixelCache(image->cache);
867 return(clone_image);
868}
869
870/*
871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872% %
873% %
874% %
875% C l o n e I m a g e I n f o %
876% %
877% %
878% %
879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880%
881% CloneImageInfo() makes a copy of the given image info structure. If
882% NULL is specified, a new image info structure is created initialized to
883% default values.
884%
885% The format of the CloneImageInfo method is:
886%
887% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
888%
889% A description of each parameter follows:
890%
891% o image_info: the image info.
892%
893*/
894MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
895{
896 ImageInfo
897 *clone_info;
898
899 clone_info=AcquireImageInfo();
900 if (image_info == (ImageInfo *) NULL)
901 return(clone_info);
902 clone_info->compression=image_info->compression;
903 clone_info->temporary=image_info->temporary;
904 clone_info->adjoin=image_info->adjoin;
905 clone_info->antialias=image_info->antialias;
906 clone_info->scene=image_info->scene;
907 clone_info->number_scenes=image_info->number_scenes;
908 clone_info->depth=image_info->depth;
909 if (image_info->size != (char *) NULL)
910 (void) CloneString(&clone_info->size,image_info->size);
911 if (image_info->extract != (char *) NULL)
912 (void) CloneString(&clone_info->extract,image_info->extract);
913 if (image_info->scenes != (char *) NULL)
914 (void) CloneString(&clone_info->scenes,image_info->scenes);
915 if (image_info->page != (char *) NULL)
916 (void) CloneString(&clone_info->page,image_info->page);
917 clone_info->interlace=image_info->interlace;
918 clone_info->endian=image_info->endian;
919 clone_info->units=image_info->units;
920 clone_info->quality=image_info->quality;
921 if (image_info->sampling_factor != (char *) NULL)
922 (void) CloneString(&clone_info->sampling_factor,
923 image_info->sampling_factor);
924 if (image_info->server_name != (char *) NULL)
925 (void) CloneString(&clone_info->server_name,image_info->server_name);
926 if (image_info->font != (char *) NULL)
927 (void) CloneString(&clone_info->font,image_info->font);
928 if (image_info->texture != (char *) NULL)
929 (void) CloneString(&clone_info->texture,image_info->texture);
930 if (image_info->density != (char *) NULL)
931 (void) CloneString(&clone_info->density,image_info->density);
932 clone_info->pointsize=image_info->pointsize;
933 clone_info->fuzz=image_info->fuzz;
cristy3ed852e2009-09-05 21:47:34 +0000934 clone_info->background_color=image_info->background_color;
935 clone_info->border_color=image_info->border_color;
936 clone_info->matte_color=image_info->matte_color;
937 clone_info->transparent_color=image_info->transparent_color;
938 clone_info->dither=image_info->dither;
939 clone_info->monochrome=image_info->monochrome;
940 clone_info->colors=image_info->colors;
941 clone_info->colorspace=image_info->colorspace;
942 clone_info->type=image_info->type;
943 clone_info->orientation=image_info->orientation;
944 clone_info->preview_type=image_info->preview_type;
945 clone_info->group=image_info->group;
946 clone_info->ping=image_info->ping;
947 clone_info->verbose=image_info->verbose;
948 if (image_info->view != (char *) NULL)
949 (void) CloneString(&clone_info->view,image_info->view);
950 if (image_info->authenticate != (char *) NULL)
951 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
952 (void) CloneImageOptions(clone_info,image_info);
953 clone_info->progress_monitor=image_info->progress_monitor;
954 clone_info->client_data=image_info->client_data;
955 clone_info->cache=image_info->cache;
956 if (image_info->cache != (void *) NULL)
957 clone_info->cache=ReferencePixelCache(image_info->cache);
958 if (image_info->profile != (void *) NULL)
959 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
960 image_info->profile);
961 SetImageInfoFile(clone_info,image_info->file);
962 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
963 clone_info->stream=image_info->stream;
964 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
965 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
966 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
967 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
968 (void) CopyMagickString(clone_info->filename,image_info->filename,
969 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000970 clone_info->channel=image_info->channel;
971 clone_info->debug=IsEventLogging();
972 clone_info->signature=image_info->signature;
973 return(clone_info);
974}
975
976/*
977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978% %
979% %
980% %
981% C o m b i n e I m a g e s %
982% %
983% %
984% %
985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986%
987% CombineImages() combines one or more images into a single image. The
988% grayscale value of the pixels of each image in the sequence is assigned in
989% order to the specified channels of the combined image. The typical
990% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
991%
992% The format of the CombineImages method is:
993%
cristy3139dc22011-07-08 00:11:42 +0000994% Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000995%
996% A description of each parameter follows:
997%
998% o image: the image.
999%
1000% o exception: return any errors or warnings in this structure.
1001%
1002*/
cristy3139dc22011-07-08 00:11:42 +00001003MagickExport Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001004{
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);
cristy574cc262011-08-05 01:23:58 +00001042 if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001043 {
cristy3ed852e2009-09-05 21:47:34 +00001044 combine_image=DestroyImage(combine_image);
1045 return((Image *) NULL);
1046 }
cristyed231572011-07-14 02:18:59 +00001047 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001048 combine_image->matte=MagickTrue;
1049 (void) SetImageBackgroundColor(combine_image);
1050 /*
1051 Combine images.
1052 */
1053 status=MagickTrue;
1054 progress=0;
1055 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001056 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001057 {
1058 CacheView
1059 *image_view;
1060
1061 const Image
1062 *next;
1063
cristy4c08aed2011-07-01 19:47:50 +00001064 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001065 *pixels;
1066
cristy4c08aed2011-07-01 19:47:50 +00001067 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001068 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001069
cristy4c08aed2011-07-01 19:47:50 +00001070 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001071 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001072
cristycb6d09b2010-06-19 01:59:36 +00001073 register ssize_t
1074 x;
1075
cristy3ed852e2009-09-05 21:47:34 +00001076 if (status == MagickFalse)
1077 continue;
1078 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1079 1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001080 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001081 {
1082 status=MagickFalse;
1083 continue;
1084 }
1085 next=image;
cristyed231572011-07-14 02:18:59 +00001086 if (((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001087 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001088 {
1089 image_view=AcquireCacheView(next);
1090 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001091 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001092 continue;
1093 q=pixels;
cristybb503372010-05-27 20:51:26 +00001094 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001095 {
cristy4c08aed2011-07-01 19:47:50 +00001096 SetPixelRed(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001097 p+=GetPixelChannels(image);
1098 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001099 }
1100 image_view=DestroyCacheView(image_view);
1101 next=GetNextImageInList(next);
1102 }
cristyed231572011-07-14 02:18:59 +00001103 if (((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001104 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001105 {
1106 image_view=AcquireCacheView(next);
1107 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001108 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001109 continue;
1110 q=pixels;
cristybb503372010-05-27 20:51:26 +00001111 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001112 {
cristy4c08aed2011-07-01 19:47:50 +00001113 SetPixelGreen(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001114 p+=GetPixelChannels(image);
1115 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001116 }
1117 image_view=DestroyCacheView(image_view);
1118 next=GetNextImageInList(next);
1119 }
cristyed231572011-07-14 02:18:59 +00001120 if (((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001121 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001122 {
1123 image_view=AcquireCacheView(next);
1124 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001125 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001126 continue;
1127 q=pixels;
cristybb503372010-05-27 20:51:26 +00001128 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001129 {
cristy4c08aed2011-07-01 19:47:50 +00001130 SetPixelBlue(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001131 p+=GetPixelChannels(image);
1132 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001133 }
1134 image_view=DestroyCacheView(image_view);
1135 next=GetNextImageInList(next);
1136 }
cristyed231572011-07-14 02:18:59 +00001137 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +00001138 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1139 {
cristy3ed852e2009-09-05 21:47:34 +00001140 image_view=AcquireCacheView(next);
1141 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001142 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001143 continue;
cristy4c08aed2011-07-01 19:47:50 +00001144 q=pixels;
cristybb503372010-05-27 20:51:26 +00001145 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001146 {
cristy4c08aed2011-07-01 19:47:50 +00001147 SetPixelBlack(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001148 p+=GetPixelChannels(image);
1149 q+=GetPixelChannels(combine_image);
cristy4c08aed2011-07-01 19:47:50 +00001150 }
1151 image_view=DestroyCacheView(image_view);
1152 next=GetNextImageInList(next);
1153 }
cristyed231572011-07-14 02:18:59 +00001154 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001155 (next != (Image *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00001156 {
1157 image_view=AcquireCacheView(next);
1158 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1159 if (p == (const Quantum *) NULL)
1160 continue;
1161 q=pixels;
1162 for (x=0; x < (ssize_t) combine_image->columns; x++)
1163 {
1164 SetPixelAlpha(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001165 p+=GetPixelChannels(image);
1166 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001167 }
1168 image_view=DestroyCacheView(image_view);
1169 next=GetNextImageInList(next);
1170 }
1171 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1172 status=MagickFalse;
1173 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1174 {
1175 MagickBooleanType
1176 proceed;
1177
cristy3ed852e2009-09-05 21:47:34 +00001178 proceed=SetImageProgress(image,CombineImageTag,progress++,
1179 combine_image->rows);
1180 if (proceed == MagickFalse)
1181 status=MagickFalse;
1182 }
1183 }
1184 combine_view=DestroyCacheView(combine_view);
1185 if (status == MagickFalse)
1186 combine_image=DestroyImage(combine_image);
1187 return(combine_image);
1188}
1189
1190/*
1191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192% %
1193% %
1194% %
cristy3ed852e2009-09-05 21:47:34 +00001195% D e s t r o y I m a g e %
1196% %
1197% %
1198% %
1199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200%
1201% DestroyImage() dereferences an image, deallocating memory associated with
1202% the image if the reference count becomes zero.
1203%
1204% The format of the DestroyImage method is:
1205%
1206% Image *DestroyImage(Image *image)
1207%
1208% A description of each parameter follows:
1209%
1210% o image: the image.
1211%
1212*/
1213MagickExport Image *DestroyImage(Image *image)
1214{
1215 MagickBooleanType
1216 destroy;
1217
1218 /*
1219 Dereference image.
1220 */
1221 assert(image != (Image *) NULL);
1222 assert(image->signature == MagickSignature);
1223 if (image->debug != MagickFalse)
1224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1225 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001226 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001227 image->reference_count--;
1228 if (image->reference_count == 0)
1229 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001230 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001231 if (destroy == MagickFalse)
1232 return((Image *) NULL);
1233 /*
1234 Destroy image.
1235 */
1236 DestroyImagePixels(image);
cristyed231572011-07-14 02:18:59 +00001237 image->channel_map=DestroyPixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +00001238 if (image->clip_mask != (Image *) NULL)
1239 image->clip_mask=DestroyImage(image->clip_mask);
1240 if (image->mask != (Image *) NULL)
1241 image->mask=DestroyImage(image->mask);
1242 if (image->montage != (char *) NULL)
1243 image->montage=DestroyString(image->montage);
1244 if (image->directory != (char *) NULL)
1245 image->directory=DestroyString(image->directory);
1246 if (image->colormap != (PixelPacket *) NULL)
1247 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1248 if (image->geometry != (char *) NULL)
1249 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001250 DestroyImageProfiles(image);
1251 DestroyImageProperties(image);
1252 DestroyImageArtifacts(image);
1253 if (image->ascii85 != (Ascii85Info*) NULL)
1254 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1255 DestroyBlob(image);
1256 (void) DestroyExceptionInfo(&image->exception);
1257 if (image->semaphore != (SemaphoreInfo *) NULL)
1258 DestroySemaphoreInfo(&image->semaphore);
1259 image->signature=(~MagickSignature);
1260 image=(Image *) RelinquishMagickMemory(image);
1261 return(image);
1262}
1263
1264/*
1265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266% %
1267% %
1268% %
1269% D e s t r o y I m a g e I n f o %
1270% %
1271% %
1272% %
1273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1274%
1275% DestroyImageInfo() deallocates memory associated with an ImageInfo
1276% structure.
1277%
1278% The format of the DestroyImageInfo method is:
1279%
1280% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1281%
1282% A description of each parameter follows:
1283%
1284% o image_info: the image info.
1285%
1286*/
1287MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1288{
1289 assert(image_info != (ImageInfo *) NULL);
1290 assert(image_info->signature == MagickSignature);
1291 if (image_info->debug != MagickFalse)
1292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1293 image_info->filename);
1294 if (image_info->size != (char *) NULL)
1295 image_info->size=DestroyString(image_info->size);
1296 if (image_info->extract != (char *) NULL)
1297 image_info->extract=DestroyString(image_info->extract);
1298 if (image_info->scenes != (char *) NULL)
1299 image_info->scenes=DestroyString(image_info->scenes);
1300 if (image_info->page != (char *) NULL)
1301 image_info->page=DestroyString(image_info->page);
1302 if (image_info->sampling_factor != (char *) NULL)
1303 image_info->sampling_factor=DestroyString(
1304 image_info->sampling_factor);
1305 if (image_info->server_name != (char *) NULL)
1306 image_info->server_name=DestroyString(
1307 image_info->server_name);
1308 if (image_info->font != (char *) NULL)
1309 image_info->font=DestroyString(image_info->font);
1310 if (image_info->texture != (char *) NULL)
1311 image_info->texture=DestroyString(image_info->texture);
1312 if (image_info->density != (char *) NULL)
1313 image_info->density=DestroyString(image_info->density);
1314 if (image_info->view != (char *) NULL)
1315 image_info->view=DestroyString(image_info->view);
1316 if (image_info->authenticate != (char *) NULL)
1317 image_info->authenticate=DestroyString(
1318 image_info->authenticate);
1319 DestroyImageOptions(image_info);
1320 if (image_info->cache != (void *) NULL)
1321 image_info->cache=DestroyPixelCache(image_info->cache);
1322 if (image_info->profile != (StringInfo *) NULL)
1323 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1324 image_info->profile);
1325 image_info->signature=(~MagickSignature);
1326 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1327 return(image_info);
1328}
1329
1330/*
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332% %
1333% %
1334% %
1335+ D i s a s s o c i a t e I m a g e S t r e a m %
1336% %
1337% %
1338% %
1339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340%
1341% DisassociateImageStream() disassociates the image stream.
1342%
1343% The format of the DisassociateImageStream method is:
1344%
1345% MagickBooleanType DisassociateImageStream(const Image *image)
1346%
1347% A description of each parameter follows:
1348%
1349% o image: the image.
1350%
1351*/
1352MagickExport void DisassociateImageStream(Image *image)
1353{
1354 assert(image != (const Image *) NULL);
1355 assert(image->signature == MagickSignature);
1356 if (image->debug != MagickFalse)
1357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1358 (void) DetachBlob(image->blob);
1359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
1366% G e t I m a g e A l p h a C h a n n e l %
1367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
1372% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1373% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1374% than CMYKA.
1375%
1376% The format of the GetImageAlphaChannel method is:
1377%
1378% MagickBooleanType GetImageAlphaChannel(const Image *image)
1379%
1380% A description of each parameter follows:
1381%
1382% o image: the image.
1383%
1384*/
1385MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1386{
1387 assert(image != (const Image *) NULL);
1388 if (image->debug != MagickFalse)
1389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1390 assert(image->signature == MagickSignature);
1391 return(image->matte);
1392}
1393
1394/*
1395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396% %
1397% %
1398% %
1399% G e t I m a g e C l i p M a s k %
1400% %
1401% %
1402% %
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404%
1405% GetImageClipMask() returns the clip path associated with the image.
1406%
1407% The format of the GetImageClipMask method is:
1408%
1409% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1410%
1411% A description of each parameter follows:
1412%
1413% o image: the image.
1414%
1415*/
1416MagickExport Image *GetImageClipMask(const Image *image,
1417 ExceptionInfo *exception)
1418{
1419 assert(image != (const Image *) NULL);
1420 if (image->debug != MagickFalse)
1421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1422 assert(image->signature == MagickSignature);
1423 if (image->clip_mask == (Image *) NULL)
1424 return((Image *) NULL);
1425 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1426}
1427
1428/*
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430% %
1431% %
1432% %
1433% G e t I m a g e E x c e p t i o n %
1434% %
1435% %
1436% %
1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438%
1439% GetImageException() traverses an image sequence and returns any
1440% error more severe than noted by the exception parameter.
1441%
1442% The format of the GetImageException method is:
1443%
1444% void GetImageException(Image *image,ExceptionInfo *exception)
1445%
1446% A description of each parameter follows:
1447%
1448% o image: Specifies a pointer to a list of one or more images.
1449%
1450% o exception: return the highest severity exception.
1451%
1452*/
1453MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1454{
1455 register Image
1456 *next;
1457
1458 assert(image != (Image *) NULL);
1459 assert(image->signature == MagickSignature);
1460 if (image->debug != MagickFalse)
1461 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1462 assert(exception != (ExceptionInfo *) NULL);
1463 assert(exception->signature == MagickSignature);
1464 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1465 {
1466 if (next->exception.severity == UndefinedException)
1467 continue;
1468 if (next->exception.severity > exception->severity)
1469 InheritException(exception,&next->exception);
1470 next->exception.severity=UndefinedException;
1471 }
1472}
1473
1474/*
1475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476% %
1477% %
1478% %
1479% G e t I m a g e I n f o %
1480% %
1481% %
1482% %
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484%
1485% GetImageInfo() initializes image_info to default values.
1486%
1487% The format of the GetImageInfo method is:
1488%
1489% void GetImageInfo(ImageInfo *image_info)
1490%
1491% A description of each parameter follows:
1492%
1493% o image_info: the image info.
1494%
1495*/
1496MagickExport void GetImageInfo(ImageInfo *image_info)
1497{
cristyd9a29192010-10-16 16:49:53 +00001498 const char
1499 *synchronize;
1500
cristy3ed852e2009-09-05 21:47:34 +00001501 ExceptionInfo
1502 *exception;
1503
1504 /*
1505 File and image dimension members.
1506 */
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1508 assert(image_info != (ImageInfo *) NULL);
1509 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1510 image_info->adjoin=MagickTrue;
1511 image_info->interlace=NoInterlace;
1512 image_info->channel=DefaultChannels;
1513 image_info->quality=UndefinedCompressionQuality;
1514 image_info->antialias=MagickTrue;
1515 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001516 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1517 if (synchronize != (const char *) NULL)
1518 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001519 exception=AcquireExceptionInfo();
1520 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1521 exception);
1522 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1523 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1524 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1525 exception);
1526 exception=DestroyExceptionInfo(exception);
1527 image_info->debug=IsEventLogging();
1528 image_info->signature=MagickSignature;
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
cristy15781e52009-12-05 23:05:27 +00001536% G e t I m a g e I n f o F i l e %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% GetImageInfoFile() returns the image info file member.
1543%
1544% The format of the GetImageInfoFile method is:
1545%
1546% FILE *GetImageInfoFile(const ImageInfo *image_info)
1547%
1548% A description of each parameter follows:
1549%
1550% o image_info: the image info.
1551%
1552*/
1553MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1554{
1555 return(image_info->file);
1556}
1557
1558/*
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560% %
1561% %
1562% %
cristy3ed852e2009-09-05 21:47:34 +00001563% G e t I m a g e M a s k %
1564% %
1565% %
1566% %
1567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568%
1569% GetImageMask() returns the mask associated with the image.
1570%
1571% The format of the GetImageMask method is:
1572%
1573% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1574%
1575% A description of each parameter follows:
1576%
1577% o image: the image.
1578%
1579*/
1580MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1581{
1582 assert(image != (const Image *) NULL);
1583 if (image->debug != MagickFalse)
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1585 assert(image->signature == MagickSignature);
1586 if (image->mask == (Image *) NULL)
1587 return((Image *) NULL);
1588 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ G e t I m a g e R e f e r e n c e C o u n t %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetImageReferenceCount() returns the image reference count.
1603%
1604% The format of the GetReferenceCount method is:
1605%
cristybb503372010-05-27 20:51:26 +00001606% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001607%
1608% A description of each parameter follows:
1609%
1610% o image: the image.
1611%
1612*/
cristybb503372010-05-27 20:51:26 +00001613MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001614{
cristybb503372010-05-27 20:51:26 +00001615 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001616 reference_count;
1617
1618 assert(image != (Image *) NULL);
1619 assert(image->signature == MagickSignature);
1620 if (image->debug != MagickFalse)
1621 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001622 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001623 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001624 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001625 return(reference_count);
1626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
cristy3ed852e2009-09-05 21:47:34 +00001633% 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 %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1640% image. A virtual pixel is any pixel access that is outside the boundaries
1641% of the image cache.
1642%
1643% The format of the GetImageVirtualPixelMethod() method is:
1644%
1645% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1646%
1647% A description of each parameter follows:
1648%
1649% o image: the image.
1650%
1651*/
1652MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1653{
1654 assert(image != (Image *) NULL);
1655 assert(image->signature == MagickSignature);
1656 if (image->debug != MagickFalse)
1657 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1658 return(GetPixelCacheVirtualMethod(image));
1659}
1660
1661/*
1662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1663% %
1664% %
1665% %
1666% I n t e r p r e t I m a g e F i l e n a m e %
1667% %
1668% %
1669% %
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671%
1672% InterpretImageFilename() interprets embedded characters in an image filename.
1673% The filename length is returned.
1674%
1675% The format of the InterpretImageFilename method is:
1676%
1677% size_t InterpretImageFilename(const ImageInfo *image_info,
1678% Image *image,const char *format,int value,char *filename)
1679%
1680% A description of each parameter follows.
1681%
1682% o image_info: the image info..
1683%
1684% o image: the image.
1685%
1686% o format: A filename describing the format to use to write the numeric
1687% argument. Only the first numeric format identifier is replaced.
1688%
1689% o value: Numeric value to substitute into format filename.
1690%
1691% o filename: return the formatted filename in this character buffer.
1692%
1693*/
1694MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1695 Image *image,const char *format,int value,char *filename)
1696{
1697 char
1698 *q;
1699
1700 int
1701 c;
1702
1703 MagickBooleanType
1704 canonical;
1705
1706 register const char
1707 *p;
1708
cristyad785752011-07-27 23:13:03 +00001709 size_t
1710 length;
1711
cristy3ed852e2009-09-05 21:47:34 +00001712 canonical=MagickFalse;
cristyc7b79fc2011-07-28 00:24:17 +00001713 length=0;
cristy3ed852e2009-09-05 21:47:34 +00001714 (void) CopyMagickString(filename,format,MaxTextExtent);
1715 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1716 {
1717 q=(char *) p+1;
1718 if (*q == '%')
1719 {
1720 p=q+1;
1721 continue;
1722 }
1723 if (*q == '0')
1724 {
cristybb503372010-05-27 20:51:26 +00001725 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001726 value;
1727
cristybb503372010-05-27 20:51:26 +00001728 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001729 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001730 }
1731 switch (*q)
1732 {
1733 case 'd':
1734 case 'o':
1735 case 'x':
1736 {
1737 q++;
1738 c=(*q);
1739 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001740 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001741 (p-format)),p,value);
1742 *q=c;
1743 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1744 canonical=MagickTrue;
1745 if (*(q-1) != '%')
1746 break;
1747 p++;
1748 break;
1749 }
1750 case '[':
1751 {
1752 char
1753 pattern[MaxTextExtent];
1754
1755 const char
1756 *value;
1757
cristy3ed852e2009-09-05 21:47:34 +00001758 register char
1759 *r;
1760
cristybb503372010-05-27 20:51:26 +00001761 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001762 i;
1763
cristycb6d09b2010-06-19 01:59:36 +00001764 ssize_t
1765 depth;
1766
cristy3ed852e2009-09-05 21:47:34 +00001767 /*
1768 Image option.
1769 */
1770 if (strchr(p,']') == (char *) NULL)
1771 break;
1772 depth=1;
1773 r=q+1;
1774 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1775 {
1776 if (*r == '[')
1777 depth++;
1778 if (*r == ']')
1779 depth--;
1780 if (depth <= 0)
1781 break;
1782 pattern[i]=(*r++);
1783 }
1784 pattern[i]='\0';
1785 if (LocaleNCompare(pattern,"filename:",9) != 0)
1786 break;
1787 value=(const char *) NULL;
1788 if ((image_info != (const ImageInfo *) NULL) &&
1789 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001790 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001791 else
1792 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001793 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001794 else
1795 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001796 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001797 if (value == (const char *) NULL)
1798 break;
1799 q--;
1800 c=(*q);
1801 *q='\0';
cristyad785752011-07-27 23:13:03 +00001802 (void) CopyMagickString(filename+(p-format-length),value,(size_t)
1803 (MaxTextExtent-(p-format-length)));
1804 length+=strlen(pattern)-1;
cristy3ed852e2009-09-05 21:47:34 +00001805 *q=c;
1806 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1807 canonical=MagickTrue;
1808 if (*(q-1) != '%')
1809 break;
1810 p++;
1811 break;
1812 }
1813 default:
1814 break;
1815 }
1816 }
1817 for (q=filename; *q != '\0'; q++)
1818 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001819 {
1820 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1821 canonical=MagickTrue;
1822 }
cristy3ed852e2009-09-05 21:47:34 +00001823 if (canonical == MagickFalse)
1824 (void) CopyMagickString(filename,format,MaxTextExtent);
1825 return(strlen(filename));
1826}
1827
1828/*
1829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830% %
1831% %
1832% %
1833% I s H i g h D y n a m i c R a n g e I m a g e %
1834% %
1835% %
1836% %
1837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838%
1839% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1840% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1841% 0..65535.
1842%
1843% The format of the IsHighDynamicRangeImage method is:
1844%
1845% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1846% ExceptionInfo *exception)
1847%
1848% A description of each parameter follows:
1849%
1850% o image: the image.
1851%
1852% o exception: return any errors or warnings in this structure.
1853%
1854*/
1855MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1856 ExceptionInfo *exception)
1857{
1858#if !defined(MAGICKCORE_HDRI_SUPPORT)
1859 (void) image;
1860 (void) exception;
1861 return(MagickFalse);
1862#else
1863 CacheView
1864 *image_view;
1865
cristy3ed852e2009-09-05 21:47:34 +00001866 MagickBooleanType
1867 status;
1868
cristy4c08aed2011-07-01 19:47:50 +00001869 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001870 zero;
1871
cristycb6d09b2010-06-19 01:59:36 +00001872 ssize_t
1873 y;
1874
cristy3ed852e2009-09-05 21:47:34 +00001875 assert(image != (Image *) NULL);
1876 assert(image->signature == MagickSignature);
1877 if (image->debug != MagickFalse)
1878 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1879 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00001880 GetPixelInfo(image,&zero);
cristy3ed852e2009-09-05 21:47:34 +00001881 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001882#if defined(MAGICKCORE_OPENMP_SUPPORT)
1883 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001884#endif
cristybb503372010-05-27 20:51:26 +00001885 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001886 {
cristy4c08aed2011-07-01 19:47:50 +00001887 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001888 pixel;
1889
cristy4c08aed2011-07-01 19:47:50 +00001890 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001891 *p;
1892
cristybb503372010-05-27 20:51:26 +00001893 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001894 x;
1895
1896 if (status == MagickFalse)
1897 continue;
1898 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001899 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001900 {
1901 status=MagickFalse;
1902 continue;
1903 }
cristy3ed852e2009-09-05 21:47:34 +00001904 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001905 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001906 {
cristy4c08aed2011-07-01 19:47:50 +00001907 SetPixelInfo(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001908 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1909 (pixel.red != (QuantumAny) pixel.red))
1910 break;
1911 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1912 (pixel.green != (QuantumAny) pixel.green))
1913 break;
1914 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1915 (pixel.blue != (QuantumAny) pixel.blue))
1916 break;
cristy3ed852e2009-09-05 21:47:34 +00001917 if (pixel.colorspace == CMYKColorspace)
1918 {
cristy4c08aed2011-07-01 19:47:50 +00001919 if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
1920 (pixel.black != (QuantumAny) pixel.black))
cristy3ed852e2009-09-05 21:47:34 +00001921 break;
1922 }
cristy4c08aed2011-07-01 19:47:50 +00001923 if (pixel.matte != MagickFalse)
1924 {
1925 if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
1926 (pixel.alpha != (QuantumAny) pixel.alpha))
1927 break;
1928 }
cristyed231572011-07-14 02:18:59 +00001929 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001930 }
cristybb503372010-05-27 20:51:26 +00001931 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001932 status=MagickFalse;
1933 }
1934 image_view=DestroyCacheView(image_view);
1935 return(status != MagickFalse ? MagickFalse : MagickTrue);
1936#endif
1937}
1938
1939/*
1940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941% %
1942% %
1943% %
1944% I s I m a g e O b j e c t %
1945% %
1946% %
1947% %
1948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1949%
1950% IsImageObject() returns MagickTrue if the image sequence contains a valid
1951% set of image objects.
1952%
1953% The format of the IsImageObject method is:
1954%
1955% MagickBooleanType IsImageObject(const Image *image)
1956%
1957% A description of each parameter follows:
1958%
1959% o image: the image.
1960%
1961*/
1962MagickExport MagickBooleanType IsImageObject(const Image *image)
1963{
1964 register const Image
1965 *p;
1966
1967 assert(image != (Image *) NULL);
1968 if (image->debug != MagickFalse)
1969 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1970 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1971 if (p->signature != MagickSignature)
1972 return(MagickFalse);
1973 return(MagickTrue);
1974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
1981% I s T a i n t I m a g e %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1988% since it was first constituted.
1989%
1990% The format of the IsTaintImage method is:
1991%
1992% MagickBooleanType IsTaintImage(const Image *image)
1993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998*/
1999MagickExport MagickBooleanType IsTaintImage(const Image *image)
2000{
2001 char
2002 magick[MaxTextExtent],
2003 filename[MaxTextExtent];
2004
2005 register const Image
2006 *p;
2007
2008 assert(image != (Image *) NULL);
2009 if (image->debug != MagickFalse)
2010 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2011 assert(image->signature == MagickSignature);
2012 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2013 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2014 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2015 {
2016 if (p->taint != MagickFalse)
2017 return(MagickTrue);
2018 if (LocaleCompare(p->magick,magick) != 0)
2019 return(MagickTrue);
2020 if (LocaleCompare(p->filename,filename) != 0)
2021 return(MagickTrue);
2022 }
2023 return(MagickFalse);
2024}
2025
2026/*
2027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028% %
2029% %
2030% %
2031% M o d i f y I m a g e %
2032% %
2033% %
2034% %
2035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036%
2037% ModifyImage() ensures that there is only a single reference to the image
2038% to be modified, updating the provided image pointer to point to a clone of
2039% the original image if necessary.
2040%
2041% The format of the ModifyImage method is:
2042%
2043% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2044%
2045% A description of each parameter follows:
2046%
2047% o image: the image.
2048%
2049% o exception: return any errors or warnings in this structure.
2050%
2051*/
2052MagickExport MagickBooleanType ModifyImage(Image **image,
2053 ExceptionInfo *exception)
2054{
2055 Image
2056 *clone_image;
2057
2058 assert(image != (Image **) NULL);
2059 assert(*image != (Image *) NULL);
2060 assert((*image)->signature == MagickSignature);
2061 if ((*image)->debug != MagickFalse)
2062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2063 if (GetImageReferenceCount(*image) <= 1)
2064 return(MagickTrue);
2065 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002066 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002067 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002068 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002069 *image=clone_image;
2070 return(MagickTrue);
2071}
2072
2073/*
2074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2075% %
2076% %
2077% %
2078% N e w M a g i c k I m a g e %
2079% %
2080% %
2081% %
2082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2083%
2084% NewMagickImage() creates a blank image canvas of the specified size and
2085% background color.
2086%
2087% The format of the NewMagickImage method is:
2088%
2089% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002090% const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002091% const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002092%
2093% A description of each parameter follows:
2094%
2095% o image: the image.
2096%
2097% o width: the image width.
2098%
2099% o height: the image height.
2100%
2101% o background: the image color.
2102%
2103*/
2104MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002105 const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002106 const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002107{
2108 CacheView
2109 *image_view;
2110
2111 ExceptionInfo
2112 *exception;
2113
2114 Image
2115 *image;
2116
cristybb503372010-05-27 20:51:26 +00002117 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002118 y;
2119
2120 MagickBooleanType
2121 status;
2122
2123 assert(image_info != (const ImageInfo *) NULL);
2124 if (image_info->debug != MagickFalse)
2125 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2126 assert(image_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002127 assert(background != (const PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002128 image=AcquireImage(image_info);
2129 image->columns=width;
2130 image->rows=height;
2131 image->colorspace=background->colorspace;
2132 image->matte=background->matte;
2133 image->fuzz=background->fuzz;
2134 image->depth=background->depth;
2135 status=MagickTrue;
2136 exception=(&image->exception);
2137 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002138#if defined(MAGICKCORE_OPENMP_SUPPORT)
2139 #pragma omp parallel for schedule(dynamic,4) shared(status)
2140#endif
cristybb503372010-05-27 20:51:26 +00002141 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002142 {
cristy4c08aed2011-07-01 19:47:50 +00002143 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002144 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002145
cristycb6d09b2010-06-19 01:59:36 +00002146 register ssize_t
2147 x;
2148
cristy48974b92009-12-19 02:36:06 +00002149 if (status == MagickFalse)
2150 continue;
cristy3ed852e2009-09-05 21:47:34 +00002151 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002152 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002153 {
2154 status=MagickFalse;
2155 continue;
2156 }
cristybb503372010-05-27 20:51:26 +00002157 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002158 {
cristy4c08aed2011-07-01 19:47:50 +00002159 SetPixelPixelInfo(image,background,q);
cristyed231572011-07-14 02:18:59 +00002160 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002161 }
2162 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2163 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002164 }
2165 image_view=DestroyCacheView(image_view);
2166 if (status == MagickFalse)
2167 image=DestroyImage(image);
2168 return(image);
2169}
2170
2171/*
2172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173% %
2174% %
2175% %
2176% R e f e r e n c e I m a g e %
2177% %
2178% %
2179% %
2180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2181%
2182% ReferenceImage() increments the reference count associated with an image
2183% returning a pointer to the image.
2184%
2185% The format of the ReferenceImage method is:
2186%
2187% Image *ReferenceImage(Image *image)
2188%
2189% A description of each parameter follows:
2190%
2191% o image: the image.
2192%
2193*/
2194MagickExport Image *ReferenceImage(Image *image)
2195{
2196 assert(image != (Image *) NULL);
2197 if (image->debug != MagickFalse)
2198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2199 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002200 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002201 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002202 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002203 return(image);
2204}
2205
2206/*
2207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208% %
2209% %
2210% %
2211% R e s e t I m a g e P a g e %
2212% %
2213% %
2214% %
2215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216%
2217% ResetImagePage() resets the image page canvas and position.
2218%
2219% The format of the ResetImagePage method is:
2220%
2221% MagickBooleanType ResetImagePage(Image *image,const char *page)
2222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o page: the relative page specification.
2228%
2229*/
2230MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2231{
2232 MagickStatusType
2233 flags;
2234
2235 RectangleInfo
2236 geometry;
2237
2238 assert(image != (Image *) NULL);
2239 assert(image->signature == MagickSignature);
2240 if (image->debug != MagickFalse)
2241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2242 flags=ParseAbsoluteGeometry(page,&geometry);
2243 if ((flags & WidthValue) != 0)
2244 {
2245 if ((flags & HeightValue) == 0)
2246 geometry.height=geometry.width;
2247 image->page.width=geometry.width;
2248 image->page.height=geometry.height;
2249 }
2250 if ((flags & AspectValue) != 0)
2251 {
2252 if ((flags & XValue) != 0)
2253 image->page.x+=geometry.x;
2254 if ((flags & YValue) != 0)
2255 image->page.y+=geometry.y;
2256 }
2257 else
2258 {
2259 if ((flags & XValue) != 0)
2260 {
2261 image->page.x=geometry.x;
2262 if ((image->page.width == 0) && (geometry.x > 0))
2263 image->page.width=image->columns+geometry.x;
2264 }
2265 if ((flags & YValue) != 0)
2266 {
2267 image->page.y=geometry.y;
2268 if ((image->page.height == 0) && (geometry.y > 0))
2269 image->page.height=image->rows+geometry.y;
2270 }
2271 }
2272 return(MagickTrue);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
2280% S e p a r a t e I m a g e C h a n n e l %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
cristy3139dc22011-07-08 00:11:42 +00002286% SeparateImage() separates a channel from the image and returns it as
cristy3ed852e2009-09-05 21:47:34 +00002287% a grayscale image. A channel is a particular color component of each pixel
2288% in the image.
2289%
cristy3139dc22011-07-08 00:11:42 +00002290% The format of the SeparateImage method is:
cristy3ed852e2009-09-05 21:47:34 +00002291%
cristy3139dc22011-07-08 00:11:42 +00002292% MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002293%
2294% A description of each parameter follows:
2295%
2296% o image: the image.
2297%
cristy3ed852e2009-09-05 21:47:34 +00002298*/
cristy3139dc22011-07-08 00:11:42 +00002299MagickExport MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002300{
2301#define SeparateImageTag "Separate/Image"
2302
2303 CacheView
2304 *image_view;
2305
2306 ExceptionInfo
2307 *exception;
2308
cristy3ed852e2009-09-05 21:47:34 +00002309 MagickBooleanType
2310 status;
2311
cristybb503372010-05-27 20:51:26 +00002312 MagickOffsetType
2313 progress;
2314
2315 ssize_t
2316 y;
2317
cristy3ed852e2009-09-05 21:47:34 +00002318 assert(image != (Image *) NULL);
2319 assert(image->signature == MagickSignature);
2320 if (image->debug != MagickFalse)
2321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy47fa6ee2011-08-05 17:35:33 +00002322 exception=(&image->exception);
cristy574cc262011-08-05 01:23:58 +00002323 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002324 return(MagickFalse);
2325 /*
2326 Separate image channels.
2327 */
2328 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002329 progress=0;
cristy3ed852e2009-09-05 21:47:34 +00002330 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002331#if defined(MAGICKCORE_OPENMP_SUPPORT)
2332 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002333#endif
cristybb503372010-05-27 20:51:26 +00002334 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002335 {
cristy4c08aed2011-07-01 19:47:50 +00002336 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002337 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002338
cristycb6d09b2010-06-19 01:59:36 +00002339 register ssize_t
2340 x;
2341
cristy3ed852e2009-09-05 21:47:34 +00002342 if (status == MagickFalse)
2343 continue;
2344 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002345 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002346 {
2347 status=MagickFalse;
2348 continue;
2349 }
cristy3139dc22011-07-08 00:11:42 +00002350 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002351 {
cristyed231572011-07-14 02:18:59 +00002352 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002353 {
cristy4c08aed2011-07-01 19:47:50 +00002354 SetPixelGreen(image,GetPixelRed(image,q),q);
2355 SetPixelBlue(image,GetPixelRed(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002356 }
cristyed231572011-07-14 02:18:59 +00002357 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002358 {
cristy4c08aed2011-07-01 19:47:50 +00002359 SetPixelRed(image,GetPixelGreen(image,q),q);
2360 SetPixelBlue(image,GetPixelGreen(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002361 }
cristyed231572011-07-14 02:18:59 +00002362 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002363 {
cristy4c08aed2011-07-01 19:47:50 +00002364 SetPixelRed(image,GetPixelBlue(image,q),q);
2365 SetPixelGreen(image,GetPixelBlue(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002366 }
cristyed231572011-07-14 02:18:59 +00002367 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002368 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002369 {
cristy4c08aed2011-07-01 19:47:50 +00002370 SetPixelRed(image,GetPixelBlack(image,q),q);
2371 SetPixelGreen(image,GetPixelBlack(image,q),q);
2372 SetPixelBlue(image,GetPixelBlack(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002373 }
cristyed231572011-07-14 02:18:59 +00002374 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002375 (image->matte != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002376 {
cristy4c08aed2011-07-01 19:47:50 +00002377 SetPixelRed(image,GetPixelAlpha(image,q),q);
2378 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2379 SetPixelBlue(image,GetPixelAlpha(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002380 }
cristyed231572011-07-14 02:18:59 +00002381 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002382 }
2383 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2384 status=MagickFalse;
2385 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2386 {
2387 MagickBooleanType
2388 proceed;
2389
cristyb5d5f722009-11-04 03:03:49 +00002390#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3139dc22011-07-08 00:11:42 +00002391 #pragma omp critical (MagickCore_SeparateImage)
cristy3ed852e2009-09-05 21:47:34 +00002392#endif
2393 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2394 if (proceed == MagickFalse)
2395 status=MagickFalse;
2396 }
2397 }
2398 image_view=DestroyCacheView(image_view);
cristy63240882011-08-05 19:05:27 +00002399 (void) SetImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00002400 return(status);
2401}
2402
2403/*
2404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2405% %
2406% %
2407% %
2408% S e p a r a t e I m a g e s %
2409% %
2410% %
2411% %
2412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413%
2414% SeparateImages() returns a separate grayscale image for each channel
2415% specified.
2416%
2417% The format of the SeparateImages method is:
2418%
2419% MagickBooleanType SeparateImages(const Image *image,
cristy3139dc22011-07-08 00:11:42 +00002420% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002421%
2422% A description of each parameter follows:
2423%
2424% o image: the image.
2425%
cristy3ed852e2009-09-05 21:47:34 +00002426% o exception: return any errors or warnings in this structure.
2427%
2428*/
cristy3139dc22011-07-08 00:11:42 +00002429MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002430{
2431 Image
2432 *images,
2433 *separate_image;
2434
2435 assert(image != (Image *) NULL);
2436 assert(image->signature == MagickSignature);
2437 if (image->debug != MagickFalse)
2438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2439 images=NewImageList();
cristyed231572011-07-14 02:18:59 +00002440 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002441 {
2442 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002443 PushPixelChannelMap(separate_image,RedChannel);
cristy3139dc22011-07-08 00:11:42 +00002444 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002445 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002446 AppendImageToList(&images,separate_image);
2447 }
cristyed231572011-07-14 02:18:59 +00002448 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002449 {
2450 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002451 PushPixelChannelMap(separate_image,GreenChannel);
cristy3139dc22011-07-08 00:11:42 +00002452 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002453 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002454 AppendImageToList(&images,separate_image);
2455 }
cristyed231572011-07-14 02:18:59 +00002456 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002457 {
2458 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002459 PushPixelChannelMap(separate_image,BlueChannel);
cristy3139dc22011-07-08 00:11:42 +00002460 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002461 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002462 AppendImageToList(&images,separate_image);
2463 }
cristyed231572011-07-14 02:18:59 +00002464 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002465 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002466 {
2467 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002468 PushPixelChannelMap(separate_image,BlackChannel);
cristy3139dc22011-07-08 00:11:42 +00002469 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002470 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002471 AppendImageToList(&images,separate_image);
2472 }
cristyed231572011-07-14 02:18:59 +00002473 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002474 {
2475 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002476 PushPixelChannelMap(separate_image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002477 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002478 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002479 AppendImageToList(&images,separate_image);
2480 }
2481 return(images);
2482}
2483
2484/*
2485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2486% %
2487% %
2488% %
2489% S e t I m a g e A l p h a C h a n n e l %
2490% %
2491% %
2492% %
2493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2494%
2495% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2496% channel.
2497%
2498% The format of the SetImageAlphaChannel method is:
2499%
2500% MagickBooleanType SetImageAlphaChannel(Image *image,
cristy63240882011-08-05 19:05:27 +00002501% const AlphaChannelType alpha_type,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002502%
2503% A description of each parameter follows:
2504%
2505% o image: the image.
2506%
2507% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2508% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
cristy4c08aed2011-07-01 19:47:50 +00002509% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
2510% TransparentAlphaChannel.
cristy3ed852e2009-09-05 21:47:34 +00002511%
cristy63240882011-08-05 19:05:27 +00002512% o exception: return any errors or warnings in this structure.
2513%
cristy3ed852e2009-09-05 21:47:34 +00002514*/
2515MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
cristy63240882011-08-05 19:05:27 +00002516 const AlphaChannelType alpha_type,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002517{
2518 MagickBooleanType
2519 status;
2520
2521 assert(image != (Image *) NULL);
2522 if (image->debug != MagickFalse)
2523 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2524 assert(image->signature == MagickSignature);
cristy327d5e92011-08-07 01:16:47 +00002525 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002526 switch (alpha_type)
2527 {
2528 case ActivateAlphaChannel:
2529 {
2530 image->matte=MagickTrue;
2531 break;
2532 }
2533 case BackgroundAlphaChannel:
2534 {
2535 CacheView
2536 *image_view;
2537
cristy4c08aed2011-07-01 19:47:50 +00002538 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002539 background;
2540
2541 PixelPacket
2542 pixel;
2543
cristycb6d09b2010-06-19 01:59:36 +00002544 ssize_t
2545 y;
2546
cristy3ed852e2009-09-05 21:47:34 +00002547 /*
2548 Set transparent pixels to background color.
2549 */
2550 if (image->matte == MagickFalse)
2551 break;
cristy574cc262011-08-05 01:23:58 +00002552 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002553 break;
cristy4c08aed2011-07-01 19:47:50 +00002554 GetPixelInfo(image,&background);
2555 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002556 if (image->colorspace == CMYKColorspace)
2557 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002558 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002559 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002560 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2561 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002562 #endif
cristybb503372010-05-27 20:51:26 +00002563 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002564 {
cristy4c08aed2011-07-01 19:47:50 +00002565 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002566 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002567
cristycb6d09b2010-06-19 01:59:36 +00002568 register ssize_t
2569 x;
2570
cristy3ed852e2009-09-05 21:47:34 +00002571 if (status == MagickFalse)
2572 continue;
2573 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2574 exception);
cristy4c08aed2011-07-01 19:47:50 +00002575 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002576 {
2577 status=MagickFalse;
2578 continue;
2579 }
cristybb503372010-05-27 20:51:26 +00002580 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002581 {
cristy4c08aed2011-07-01 19:47:50 +00002582 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002583 {
cristy4c08aed2011-07-01 19:47:50 +00002584 SetPixelRed(image,pixel.red,q);
2585 SetPixelGreen(image,pixel.green,q);
2586 SetPixelBlue(image,pixel.blue,q);
2587 if (image->colorspace == CMYKColorspace)
2588 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002589 }
cristyed231572011-07-14 02:18:59 +00002590 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002591 }
cristy3ed852e2009-09-05 21:47:34 +00002592 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2593 status=MagickFalse;
2594 }
2595 image_view=DestroyCacheView(image_view);
2596 return(status);
2597 }
2598 case DeactivateAlphaChannel:
2599 {
2600 image->matte=MagickFalse;
2601 break;
2602 }
2603 case ShapeAlphaChannel:
2604 case CopyAlphaChannel:
2605 {
2606 /*
cristy3139dc22011-07-08 00:11:42 +00002607 Special usage case for SeparateImage(): copy grayscale color to
cristy3ed852e2009-09-05 21:47:34 +00002608 the alpha channel.
2609 */
cristyed231572011-07-14 02:18:59 +00002610 PushPixelChannelMap(image,GrayChannel);
cristy3139dc22011-07-08 00:11:42 +00002611 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002612 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002613 image->matte=MagickTrue; /* make sure transparency is now on! */
2614 if (alpha_type == ShapeAlphaChannel)
2615 {
cristy4c08aed2011-07-01 19:47:50 +00002616 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002617 background;
2618
2619 /*
2620 Reset all color channels to background color.
2621 */
cristy4c08aed2011-07-01 19:47:50 +00002622 GetPixelInfo(image,&background);
2623 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002624 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002625 }
2626 break;
2627 }
2628 case ExtractAlphaChannel:
2629 {
cristyed231572011-07-14 02:18:59 +00002630 PushPixelChannelMap(image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002631 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002632 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002633 image->matte=MagickFalse;
2634 break;
2635 }
cristy3ed852e2009-09-05 21:47:34 +00002636 case OpaqueAlphaChannel:
2637 {
cristy4c08aed2011-07-01 19:47:50 +00002638 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002639 image->matte=MagickTrue;
2640 break;
2641 }
2642 case TransparentAlphaChannel:
2643 {
cristy4c08aed2011-07-01 19:47:50 +00002644 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002645 image->matte=MagickTrue;
2646 break;
2647 }
2648 case SetAlphaChannel:
2649 {
2650 if (image->matte == MagickFalse)
2651 {
cristy4c08aed2011-07-01 19:47:50 +00002652 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002653 image->matte=MagickTrue;
2654 }
2655 break;
2656 }
2657 case UndefinedAlphaChannel:
2658 break;
2659 }
cristy6e437132011-08-12 13:02:19 +00002660 if (status == MagickFalse)
2661 return(status);
2662 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
2670% S e t I m a g e B a c k g r o u n d C o l o r %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% SetImageBackgroundColor() initializes the image pixels to the image
2677% background color. The background color is defined by the background_color
2678% member of the image structure.
2679%
2680% The format of the SetImage method is:
2681%
2682% MagickBooleanType SetImageBackgroundColor(Image *image)
2683%
2684% A description of each parameter follows:
2685%
2686% o image: the image.
2687%
2688*/
2689MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2690{
2691 CacheView
2692 *image_view;
2693
2694 ExceptionInfo
2695 *exception;
2696
cristy3ed852e2009-09-05 21:47:34 +00002697 MagickBooleanType
2698 status;
2699
cristy4c08aed2011-07-01 19:47:50 +00002700 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002701 background;
2702
2703 PixelPacket
2704 pixel;
2705
cristycb6d09b2010-06-19 01:59:36 +00002706 ssize_t
2707 y;
2708
cristy3ed852e2009-09-05 21:47:34 +00002709 assert(image != (Image *) NULL);
2710 if (image->debug != MagickFalse)
2711 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2712 assert(image->signature == MagickSignature);
cristy574cc262011-08-05 01:23:58 +00002713 exception=(&image->exception);
2714 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002715 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002716 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002717 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002718 GetPixelInfo(image,&background);
2719 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002720 if (image->colorspace == CMYKColorspace)
2721 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002722 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002723 /*
2724 Set image background color.
2725 */
2726 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002727 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002728 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002729 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002730 {
cristy4c08aed2011-07-01 19:47:50 +00002731 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002732 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002733
cristycb6d09b2010-06-19 01:59:36 +00002734 register ssize_t
2735 x;
2736
cristy3ed852e2009-09-05 21:47:34 +00002737 if (status == MagickFalse)
2738 continue;
2739 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002740 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002741 {
2742 status=MagickFalse;
2743 continue;
2744 }
cristybb503372010-05-27 20:51:26 +00002745 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002746 {
2747 SetPixelPacket(image,&pixel,q);
2748 if (image->colorspace == CMYKColorspace)
2749 SetPixelBlack(image,pixel.black,q);
cristyed231572011-07-14 02:18:59 +00002750 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002751 }
cristy3ed852e2009-09-05 21:47:34 +00002752 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2753 status=MagickFalse;
2754 }
2755 image_view=DestroyCacheView(image_view);
2756 return(status);
2757}
2758
2759/*
2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761% %
2762% %
2763% %
cristya5b77cb2010-05-07 19:34:48 +00002764% S e t I m a g e C o l o r %
2765% %
2766% %
2767% %
2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769%
2770% SetImageColor() set the entire image canvas to the specified color.
2771%
2772% The format of the SetImageColor method is:
2773%
cristy08429172011-07-14 17:18:16 +00002774% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002775%
2776% A description of each parameter follows:
2777%
2778% o image: the image.
2779%
2780% o background: the image color.
2781%
2782*/
2783MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002784 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002785{
2786 CacheView
2787 *image_view;
2788
2789 ExceptionInfo
2790 *exception;
2791
cristya5b77cb2010-05-07 19:34:48 +00002792 MagickBooleanType
2793 status;
2794
cristycb6d09b2010-06-19 01:59:36 +00002795 ssize_t
2796 y;
2797
cristya5b77cb2010-05-07 19:34:48 +00002798 assert(image != (Image *) NULL);
2799 if (image->debug != MagickFalse)
2800 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2801 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002802 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002803 image->colorspace=color->colorspace;
2804 image->matte=color->matte;
2805 image->fuzz=color->fuzz;
2806 image->depth=color->depth;
2807 status=MagickTrue;
2808 exception=(&image->exception);
2809 image_view=AcquireCacheView(image);
2810#if defined(MAGICKCORE_OPENMP_SUPPORT)
2811 #pragma omp parallel for schedule(dynamic,4) shared(status)
2812#endif
cristybb503372010-05-27 20:51:26 +00002813 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002814 {
cristy4c08aed2011-07-01 19:47:50 +00002815 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002816 *restrict q;
2817
cristycb6d09b2010-06-19 01:59:36 +00002818 register ssize_t
2819 x;
2820
cristya5b77cb2010-05-07 19:34:48 +00002821 if (status == MagickFalse)
2822 continue;
2823 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002824 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002825 {
2826 status=MagickFalse;
2827 continue;
2828 }
cristybb503372010-05-27 20:51:26 +00002829 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002830 {
cristy4c08aed2011-07-01 19:47:50 +00002831 SetPixelPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002832 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002833 }
2834 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2835 status=MagickFalse;
2836 }
2837 image_view=DestroyCacheView(image_view);
2838 return(status);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristy3ed852e2009-09-05 21:47:34 +00002846% S e t I m a g e S t o r a g e C l a s s %
2847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% SetImageStorageClass() sets the image class: DirectClass for true color
2853% images or PseudoClass for colormapped images.
2854%
2855% The format of the SetImageStorageClass method is:
2856%
2857% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002858% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002859%
2860% A description of each parameter follows:
2861%
2862% o image: the image.
2863%
2864% o storage_class: The image class.
2865%
cristy574cc262011-08-05 01:23:58 +00002866% o exception: return any errors or warnings in this structure.
2867%
cristy3ed852e2009-09-05 21:47:34 +00002868*/
2869MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002870 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002871{
cristy3ed852e2009-09-05 21:47:34 +00002872 image->storage_class=storage_class;
cristy6e437132011-08-12 13:02:19 +00002873 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002874}
2875
2876/*
2877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878% %
2879% %
2880% %
2881% S e t I m a g e C l i p M a s k %
2882% %
2883% %
2884% %
2885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886%
2887% SetImageClipMask() associates a clip path with the image. The clip path
2888% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002889% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002890% pixel component from being updated when SyncAuthenticPixels() is applied.
2891%
2892% The format of the SetImageClipMask method is:
2893%
2894% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2895%
2896% A description of each parameter follows:
2897%
2898% o image: the image.
2899%
2900% o clip_mask: the image clip path.
2901%
2902*/
2903MagickExport MagickBooleanType SetImageClipMask(Image *image,
2904 const Image *clip_mask)
2905{
2906 assert(image != (Image *) NULL);
2907 if (image->debug != MagickFalse)
2908 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2909 assert(image->signature == MagickSignature);
2910 if (clip_mask != (const Image *) NULL)
2911 if ((clip_mask->columns != image->columns) ||
2912 (clip_mask->rows != image->rows))
2913 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2914 if (image->clip_mask != (Image *) NULL)
2915 image->clip_mask=DestroyImage(image->clip_mask);
2916 image->clip_mask=NewImageList();
2917 if (clip_mask == (Image *) NULL)
2918 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00002919 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002920 return(MagickFalse);
2921 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2922 if (image->clip_mask == (Image *) NULL)
2923 return(MagickFalse);
2924 return(MagickTrue);
2925}
2926
2927/*
2928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2929% %
2930% %
2931% %
2932% S e t I m a g e E x t e n t %
2933% %
2934% %
2935% %
2936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2937%
2938% SetImageExtent() sets the image size (i.e. columns & rows).
2939%
2940% The format of the SetImageExtent method is:
2941%
cristy08429172011-07-14 17:18:16 +00002942% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002943% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002944%
2945% A description of each parameter follows:
2946%
2947% o image: the image.
2948%
2949% o columns: The image width in pixels.
2950%
2951% o rows: The image height in pixels.
2952%
cristy63240882011-08-05 19:05:27 +00002953% o exception: return any errors or warnings in this structure.
2954%
cristy3ed852e2009-09-05 21:47:34 +00002955*/
cristy08429172011-07-14 17:18:16 +00002956MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002957 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002958{
cristy537e2722010-09-21 15:30:59 +00002959 if ((columns == 0) || (rows == 0))
2960 return(MagickFalse);
2961 image->columns=columns;
2962 image->rows=rows;
cristy6e437132011-08-12 13:02:19 +00002963 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002964}
2965
2966/*
2967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2968% %
2969% %
2970% %
2971+ S e t I m a g e I n f o %
2972% %
2973% %
2974% %
2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976%
2977% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
2978% It is set to a type of image format based on the prefix or suffix of the
2979% filename. For example, `ps:image' returns PS indicating a Postscript image.
2980% JPEG is returned for this filename: `image.jpg'. The filename prefix has
2981% precendence over the suffix. Use an optional index enclosed in brackets
2982% after a file name to specify a desired scene of a multi-resolution image
2983% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2984% indicates success.
2985%
2986% The format of the SetImageInfo method is:
2987%
2988% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002989% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002990%
2991% A description of each parameter follows:
2992%
cristyd965a422010-03-03 17:47:35 +00002993% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002994%
cristyd965a422010-03-03 17:47:35 +00002995% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002996%
2997% o exception: return any errors or warnings in this structure.
2998%
2999*/
3000MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003001 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003002{
3003 char
3004 extension[MaxTextExtent],
3005 filename[MaxTextExtent],
3006 magic[MaxTextExtent],
3007 *q,
3008 subimage[MaxTextExtent];
3009
3010 const MagicInfo
3011 *magic_info;
3012
3013 const MagickInfo
3014 *magick_info;
3015
3016 ExceptionInfo
3017 *sans_exception;
3018
3019 Image
3020 *image;
3021
3022 MagickBooleanType
3023 status;
3024
3025 register const char
3026 *p;
3027
3028 ssize_t
3029 count;
3030
3031 unsigned char
3032 magick[2*MaxTextExtent];
3033
3034 /*
3035 Look for 'image.format' in filename.
3036 */
3037 assert(image_info != (ImageInfo *) NULL);
3038 assert(image_info->signature == MagickSignature);
3039 if (image_info->debug != MagickFalse)
3040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3041 image_info->filename);
3042 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003043 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003044 {
cristyd965a422010-03-03 17:47:35 +00003045 GetPathComponent(image_info->filename,SubimagePath,subimage);
3046 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003047 {
cristyd965a422010-03-03 17:47:35 +00003048 /*
3049 Look for scene specification (e.g. img0001.pcd[4]).
3050 */
3051 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3052 {
3053 if (IsGeometry(subimage) != MagickFalse)
3054 (void) CloneString(&image_info->extract,subimage);
3055 }
3056 else
3057 {
cristybb503372010-05-27 20:51:26 +00003058 size_t
cristyd965a422010-03-03 17:47:35 +00003059 first,
3060 last;
cristy3ed852e2009-09-05 21:47:34 +00003061
cristyd965a422010-03-03 17:47:35 +00003062 (void) CloneString(&image_info->scenes,subimage);
3063 image_info->scene=StringToUnsignedLong(image_info->scenes);
3064 image_info->number_scenes=image_info->scene;
3065 p=image_info->scenes;
3066 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3067 {
3068 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3069 (*p == ','))
3070 p++;
cristybb503372010-05-27 20:51:26 +00003071 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003072 last=first;
3073 while (isspace((int) ((unsigned char) *q)) != 0)
3074 q++;
3075 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003076 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003077 if (first > last)
3078 Swap(first,last);
3079 if (first < image_info->scene)
3080 image_info->scene=first;
3081 if (last > image_info->number_scenes)
3082 image_info->number_scenes=last;
3083 p=q;
3084 }
3085 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003086 }
cristy3ed852e2009-09-05 21:47:34 +00003087 }
3088 }
3089 *extension='\0';
3090 GetPathComponent(image_info->filename,ExtensionPath,extension);
3091#if defined(MAGICKCORE_ZLIB_DELEGATE)
3092 if (*extension != '\0')
3093 if ((LocaleCompare(extension,"gz") == 0) ||
3094 (LocaleCompare(extension,"Z") == 0) ||
3095 (LocaleCompare(extension,"wmz") == 0))
3096 {
3097 char
3098 path[MaxTextExtent];
3099
3100 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3101 path[strlen(path)-strlen(extension)-1]='\0';
3102 GetPathComponent(path,ExtensionPath,extension);
3103 }
3104#endif
3105#if defined(MAGICKCORE_BZLIB_DELEGATE)
3106 if (*extension != '\0')
3107 if (LocaleCompare(extension,"bz2") == 0)
3108 {
3109 char
3110 path[MaxTextExtent];
3111
3112 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3113 path[strlen(path)-strlen(extension)-1]='\0';
3114 GetPathComponent(path,ExtensionPath,extension);
3115 }
3116#endif
3117 image_info->affirm=MagickFalse;
3118 sans_exception=AcquireExceptionInfo();
3119 if (*extension != '\0')
3120 {
3121 MagickFormatType
3122 format_type;
3123
cristybb503372010-05-27 20:51:26 +00003124 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003125 i;
3126
3127 static const char
3128 *format_type_formats[] =
3129 {
3130 "AUTOTRACE",
3131 "BROWSE",
3132 "DCRAW",
3133 "EDIT",
3134 "EPHEMERAL",
3135 "LAUNCH",
3136 "MPEG:DECODE",
3137 "MPEG:ENCODE",
3138 "PRINT",
3139 "PS:ALPHA",
3140 "PS:CMYK",
3141 "PS:COLOR",
3142 "PS:GRAY",
3143 "PS:MONO",
3144 "SCAN",
3145 "SHOW",
3146 "WIN",
3147 (char *) NULL
3148 };
3149
3150 /*
3151 User specified image format.
3152 */
3153 (void) CopyMagickString(magic,extension,MaxTextExtent);
3154 LocaleUpper(magic);
3155 /*
3156 Look for explicit image formats.
3157 */
3158 format_type=UndefinedFormatType;
3159 i=0;
cristydd9a2532010-02-20 19:26:46 +00003160 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003161 (format_type_formats[i] != (char *) NULL))
3162 {
3163 if ((*magic == *format_type_formats[i]) &&
3164 (LocaleCompare(magic,format_type_formats[i]) == 0))
3165 format_type=ExplicitFormatType;
3166 i++;
3167 }
3168 magick_info=GetMagickInfo(magic,sans_exception);
3169 if ((magick_info != (const MagickInfo *) NULL) &&
3170 (magick_info->format_type != UndefinedFormatType))
3171 format_type=magick_info->format_type;
3172 if (format_type == UndefinedFormatType)
3173 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3174 else
3175 if (format_type == ExplicitFormatType)
3176 {
3177 image_info->affirm=MagickTrue;
3178 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3179 }
3180 if (LocaleCompare(magic,"RGB") == 0)
3181 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3182 }
3183 /*
3184 Look for explicit 'format:image' in filename.
3185 */
3186 *magic='\0';
3187 GetPathComponent(image_info->filename,MagickPath,magic);
3188 if (*magic == '\0')
3189 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3190 else
3191 {
3192 /*
3193 User specified image format.
3194 */
3195 LocaleUpper(magic);
3196 if (IsMagickConflict(magic) == MagickFalse)
3197 {
3198 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3199 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3200 image_info->affirm=MagickTrue;
3201 else
3202 image_info->temporary=MagickTrue;
3203 }
3204 }
3205 magick_info=GetMagickInfo(magic,sans_exception);
3206 sans_exception=DestroyExceptionInfo(sans_exception);
3207 if ((magick_info == (const MagickInfo *) NULL) ||
3208 (GetMagickEndianSupport(magick_info) == MagickFalse))
3209 image_info->endian=UndefinedEndian;
3210 GetPathComponent(image_info->filename,CanonicalPath,filename);
3211 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003212 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003213 {
3214 /*
cristyd965a422010-03-03 17:47:35 +00003215 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003216 */
cristyd965a422010-03-03 17:47:35 +00003217 (void) InterpretImageFilename(image_info,(Image *) NULL,
3218 image_info->filename,(int) image_info->scene,filename);
3219 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3220 (strchr(filename,'%') == (char *) NULL))
3221 image_info->adjoin=MagickFalse;
3222 }
3223 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3224 {
3225 /*
3226 Some image formats do not support multiple frames per file.
3227 */
cristy3ed852e2009-09-05 21:47:34 +00003228 magick_info=GetMagickInfo(magic,exception);
3229 if (magick_info != (const MagickInfo *) NULL)
3230 if (GetMagickAdjoin(magick_info) == MagickFalse)
3231 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003232 }
3233 if (image_info->affirm != MagickFalse)
3234 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003235 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003236 {
3237 /*
cristyd965a422010-03-03 17:47:35 +00003238 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003239 */
cristyd965a422010-03-03 17:47:35 +00003240 image=AcquireImage(image_info);
3241 (void) CopyMagickString(image->filename,image_info->filename,
3242 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003243 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3244 if (status == MagickFalse)
3245 {
3246 image=DestroyImage(image);
3247 return(MagickFalse);
3248 }
cristyd965a422010-03-03 17:47:35 +00003249 if ((IsBlobSeekable(image) == MagickFalse) ||
3250 (IsBlobExempt(image) != MagickFalse))
3251 {
3252 /*
3253 Copy standard input or pipe to temporary file.
3254 */
3255 *filename='\0';
3256 status=ImageToFile(image,filename,exception);
3257 (void) CloseBlob(image);
3258 if (status == MagickFalse)
3259 {
3260 image=DestroyImage(image);
3261 return(MagickFalse);
3262 }
3263 SetImageInfoFile(image_info,(FILE *) NULL);
3264 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3265 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3266 if (status == MagickFalse)
3267 {
3268 image=DestroyImage(image);
3269 return(MagickFalse);
3270 }
3271 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3272 image_info->temporary=MagickTrue;
3273 }
3274 (void) ResetMagickMemory(magick,0,sizeof(magick));
3275 count=ReadBlob(image,2*MaxTextExtent,magick);
3276 (void) CloseBlob(image);
3277 image=DestroyImage(image);
3278 /*
3279 Check magic.xml configuration file.
3280 */
3281 sans_exception=AcquireExceptionInfo();
3282 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3283 if ((magic_info != (const MagicInfo *) NULL) &&
3284 (GetMagicName(magic_info) != (char *) NULL))
3285 {
3286 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3287 MaxTextExtent);
3288 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3289 if ((magick_info == (const MagickInfo *) NULL) ||
3290 (GetMagickEndianSupport(magick_info) == MagickFalse))
3291 image_info->endian=UndefinedEndian;
3292 sans_exception=DestroyExceptionInfo(sans_exception);
3293 return(MagickTrue);
3294 }
cristy3ed852e2009-09-05 21:47:34 +00003295 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3296 if ((magick_info == (const MagickInfo *) NULL) ||
3297 (GetMagickEndianSupport(magick_info) == MagickFalse))
3298 image_info->endian=UndefinedEndian;
3299 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003300 }
cristy3ed852e2009-09-05 21:47:34 +00003301 return(MagickTrue);
3302}
3303
3304/*
3305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3306% %
3307% %
3308% %
3309% S e t I m a g e I n f o B l o b %
3310% %
3311% %
3312% %
3313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3314%
3315% SetImageInfoBlob() sets the image info blob member.
3316%
3317% The format of the SetImageInfoBlob method is:
3318%
3319% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3320% const size_t length)
3321%
3322% A description of each parameter follows:
3323%
3324% o image_info: the image info.
3325%
3326% o blob: the blob.
3327%
3328% o length: the blob length.
3329%
3330*/
3331MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3332 const size_t length)
3333{
3334 assert(image_info != (ImageInfo *) NULL);
3335 assert(image_info->signature == MagickSignature);
3336 if (image_info->debug != MagickFalse)
3337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3338 image_info->filename);
3339 image_info->blob=(void *) blob;
3340 image_info->length=length;
3341}
3342
3343/*
3344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3345% %
3346% %
3347% %
3348% S e t I m a g e I n f o F i l e %
3349% %
3350% %
3351% %
3352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3353%
3354% SetImageInfoFile() sets the image info file member.
3355%
3356% The format of the SetImageInfoFile method is:
3357%
3358% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3359%
3360% A description of each parameter follows:
3361%
3362% o image_info: the image info.
3363%
3364% o file: the file.
3365%
3366*/
3367MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3368{
3369 assert(image_info != (ImageInfo *) NULL);
3370 assert(image_info->signature == MagickSignature);
3371 if (image_info->debug != MagickFalse)
3372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3373 image_info->filename);
3374 image_info->file=file;
3375}
3376
3377/*
3378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3379% %
3380% %
3381% %
3382% S e t I m a g e M a s k %
3383% %
3384% %
3385% %
3386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387%
3388% SetImageMask() associates a mask with the image. The mask must be the same
3389% dimensions as the image.
3390%
3391% The format of the SetImageMask method is:
3392%
3393% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3394%
3395% A description of each parameter follows:
3396%
3397% o image: the image.
3398%
3399% o mask: the image mask.
3400%
3401*/
3402MagickExport MagickBooleanType SetImageMask(Image *image,
3403 const Image *mask)
3404{
3405 assert(image != (Image *) NULL);
3406 if (image->debug != MagickFalse)
3407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3408 assert(image->signature == MagickSignature);
3409 if (mask != (const Image *) NULL)
3410 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3411 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3412 if (image->mask != (Image *) NULL)
3413 image->mask=DestroyImage(image->mask);
3414 image->mask=NewImageList();
3415 if (mask == (Image *) NULL)
3416 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00003417 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003418 return(MagickFalse);
3419 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3420 if (image->mask == (Image *) NULL)
3421 return(MagickFalse);
3422 return(MagickTrue);
3423}
3424
3425/*
3426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3427% %
3428% %
3429% %
3430% S e t I m a g e O p a c i t y %
3431% %
3432% %
3433% %
3434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3435%
3436% SetImageOpacity() sets the opacity levels of the image.
3437%
3438% The format of the SetImageOpacity method is:
3439%
3440% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3441%
3442% A description of each parameter follows:
3443%
3444% o image: the image.
3445%
3446% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3447% fully transparent.
3448%
3449*/
3450MagickExport MagickBooleanType SetImageOpacity(Image *image,
3451 const Quantum opacity)
3452{
3453 CacheView
3454 *image_view;
3455
3456 ExceptionInfo
3457 *exception;
3458
cristy3ed852e2009-09-05 21:47:34 +00003459 MagickBooleanType
3460 status;
3461
cristycb6d09b2010-06-19 01:59:36 +00003462 ssize_t
3463 y;
3464
cristy3ed852e2009-09-05 21:47:34 +00003465 assert(image != (Image *) NULL);
3466 if (image->debug != MagickFalse)
3467 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3468 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003469 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003470 status=MagickTrue;
3471 exception=(&image->exception);
3472 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003473#if defined(MAGICKCORE_OPENMP_SUPPORT)
3474 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003475#endif
cristybb503372010-05-27 20:51:26 +00003476 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003477 {
cristy4c08aed2011-07-01 19:47:50 +00003478 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003479 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003480
cristycb6d09b2010-06-19 01:59:36 +00003481 register ssize_t
3482 x;
3483
cristy3ed852e2009-09-05 21:47:34 +00003484 if (status == MagickFalse)
3485 continue;
3486 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003487 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003488 {
3489 status=MagickFalse;
3490 continue;
3491 }
cristybb503372010-05-27 20:51:26 +00003492 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003493 {
cristy4c08aed2011-07-01 19:47:50 +00003494 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00003495 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003496 }
3497 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3498 status=MagickFalse;
3499 }
3500 image_view=DestroyCacheView(image_view);
3501 return(status);
3502}
3503
3504/*
3505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3506% %
3507% %
3508% %
3509% S e t I m a g e T y p e %
3510% %
3511% %
3512% %
3513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3514%
3515% SetImageType() sets the type of image. Choose from these types:
3516%
3517% Bilevel Grayscale GrayscaleMatte
3518% Palette PaletteMatte TrueColor
3519% TrueColorMatte ColorSeparation ColorSeparationMatte
3520% OptimizeType
3521%
3522% The format of the SetImageType method is:
3523%
3524% MagickBooleanType SetImageType(Image *image,const ImageType type)
3525%
3526% A description of each parameter follows:
3527%
3528% o image: the image.
3529%
3530% o type: Image type.
3531%
3532*/
3533MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3534{
3535 const char
3536 *artifact;
3537
cristy63240882011-08-05 19:05:27 +00003538 ExceptionInfo
3539 *exception;
3540
cristy3ed852e2009-09-05 21:47:34 +00003541 ImageInfo
3542 *image_info;
3543
3544 MagickBooleanType
3545 status;
3546
3547 QuantizeInfo
3548 *quantize_info;
3549
3550 assert(image != (Image *) NULL);
3551 if (image->debug != MagickFalse)
3552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3553 assert(image->signature == MagickSignature);
3554 status=MagickTrue;
3555 image_info=AcquireImageInfo();
3556 image_info->dither=image->dither;
3557 artifact=GetImageArtifact(image,"dither");
3558 if (artifact != (const char *) NULL)
3559 (void) SetImageOption(image_info,"dither",artifact);
cristy63240882011-08-05 19:05:27 +00003560 exception=(&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003561 switch (type)
3562 {
3563 case BilevelType:
3564 {
cristy4c08aed2011-07-01 19:47:50 +00003565 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003566 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003567 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003568 {
3569 quantize_info=AcquireQuantizeInfo(image_info);
3570 quantize_info->number_colors=2;
3571 quantize_info->colorspace=GRAYColorspace;
3572 status=QuantizeImage(quantize_info,image);
3573 quantize_info=DestroyQuantizeInfo(quantize_info);
3574 }
3575 image->matte=MagickFalse;
3576 break;
3577 }
3578 case GrayscaleType:
3579 {
cristy4c08aed2011-07-01 19:47:50 +00003580 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003581 status=TransformImageColorspace(image,GRAYColorspace);
3582 image->matte=MagickFalse;
3583 break;
3584 }
3585 case GrayscaleMatteType:
3586 {
cristy4c08aed2011-07-01 19:47:50 +00003587 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003588 status=TransformImageColorspace(image,GRAYColorspace);
3589 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003590 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003591 break;
3592 }
3593 case PaletteType:
3594 {
cristy510d06a2011-07-06 23:43:54 +00003595 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003596 status=TransformImageColorspace(image,RGBColorspace);
3597 if ((image->storage_class == DirectClass) || (image->colors > 256))
3598 {
3599 quantize_info=AcquireQuantizeInfo(image_info);
3600 quantize_info->number_colors=256;
3601 status=QuantizeImage(quantize_info,image);
3602 quantize_info=DestroyQuantizeInfo(quantize_info);
3603 }
3604 image->matte=MagickFalse;
3605 break;
3606 }
3607 case PaletteBilevelMatteType:
3608 {
cristy510d06a2011-07-06 23:43:54 +00003609 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003610 status=TransformImageColorspace(image,RGBColorspace);
3611 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003612 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristyed231572011-07-14 02:18:59 +00003613 PushPixelChannelMap(image,AlphaChannel);
cristyf4ad9df2011-07-08 16:49:03 +00003614 (void) BilevelImage(image,(double) QuantumRange/2.0);
cristyed231572011-07-14 02:18:59 +00003615 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00003616 quantize_info=AcquireQuantizeInfo(image_info);
3617 status=QuantizeImage(quantize_info,image);
3618 quantize_info=DestroyQuantizeInfo(quantize_info);
3619 break;
3620 }
3621 case PaletteMatteType:
3622 {
cristy510d06a2011-07-06 23:43:54 +00003623 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003624 status=TransformImageColorspace(image,RGBColorspace);
3625 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003626 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003627 quantize_info=AcquireQuantizeInfo(image_info);
3628 quantize_info->colorspace=TransparentColorspace;
3629 status=QuantizeImage(quantize_info,image);
3630 quantize_info=DestroyQuantizeInfo(quantize_info);
3631 break;
3632 }
3633 case TrueColorType:
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)
cristy574cc262011-08-05 01:23:58 +00003638 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003639 image->matte=MagickFalse;
3640 break;
3641 }
3642 case TrueColorMatteType:
3643 {
cristy510d06a2011-07-06 23:43:54 +00003644 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003645 status=TransformImageColorspace(image,RGBColorspace);
3646 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003647 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003648 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003649 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003650 break;
3651 }
3652 case ColorSeparationType:
3653 {
3654 if (image->colorspace != CMYKColorspace)
3655 {
cristy510d06a2011-07-06 23:43:54 +00003656 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003657 status=TransformImageColorspace(image,RGBColorspace);
3658 status=TransformImageColorspace(image,CMYKColorspace);
3659 }
3660 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003661 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003662 image->matte=MagickFalse;
3663 break;
3664 }
3665 case ColorSeparationMatteType:
3666 {
3667 if (image->colorspace != CMYKColorspace)
3668 {
cristy510d06a2011-07-06 23:43:54 +00003669 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003670 status=TransformImageColorspace(image,RGBColorspace);
3671 status=TransformImageColorspace(image,CMYKColorspace);
3672 }
3673 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003674 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003675 if (image->matte == MagickFalse)
cristy327d5e92011-08-07 01:16:47 +00003676 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003677 break;
3678 }
3679 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003680 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003681 break;
3682 }
3683 image->type=type;
3684 image_info=DestroyImageInfo(image_info);
3685 return(status);
3686}
3687
3688/*
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690% %
3691% %
3692% %
3693% 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 %
3694% %
3695% %
3696% %
3697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3698%
3699% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3700% image and returns the previous setting. A virtual pixel is any pixel access
3701% that is outside the boundaries of the image cache.
3702%
3703% The format of the SetImageVirtualPixelMethod() method is:
3704%
3705% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3706% const VirtualPixelMethod virtual_pixel_method)
3707%
3708% A description of each parameter follows:
3709%
3710% o image: the image.
3711%
3712% o virtual_pixel_method: choose the type of virtual pixel.
3713%
3714*/
3715MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3716 const VirtualPixelMethod virtual_pixel_method)
3717{
3718 assert(image != (const Image *) NULL);
3719 assert(image->signature == MagickSignature);
3720 if (image->debug != MagickFalse)
3721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3722 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3723}
3724
3725/*
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727% %
3728% %
3729% %
cristy4285d782011-02-09 20:12:28 +00003730% S m u s h I m a g e s %
3731% %
3732% %
3733% %
3734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735%
3736% SmushImages() takes all images from the current image pointer to the end
3737% of the image list and smushes them to each other top-to-bottom if the
3738% stack parameter is true, otherwise left-to-right.
3739%
3740% The current gravity setting now effects how the image is justified in the
3741% final image.
3742%
3743% The format of the SmushImages method is:
3744%
cristy4ca38e22011-02-10 02:57:49 +00003745% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003746% ExceptionInfo *exception)
3747%
3748% A description of each parameter follows:
3749%
cristy4ca38e22011-02-10 02:57:49 +00003750% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003751%
3752% o stack: A value other than 0 stacks the images top-to-bottom.
3753%
3754% o offset: minimum distance in pixels between images.
3755%
3756% o exception: return any errors or warnings in this structure.
3757%
3758*/
cristy4ca38e22011-02-10 02:57:49 +00003759
cristy7c6dc152011-02-11 14:10:55 +00003760static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003761 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003762{
cristy4d727152011-02-10 19:57:21 +00003763 CacheView
3764 *left_view,
3765 *right_view;
3766
3767 const Image
3768 *left_image,
3769 *right_image;
3770
cristy4d727152011-02-10 19:57:21 +00003771 RectangleInfo
3772 left_geometry,
3773 right_geometry;
3774
cristy4c08aed2011-07-01 19:47:50 +00003775 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003776 *p;
3777
cristy4d727152011-02-10 19:57:21 +00003778 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003779 i,
cristy4d727152011-02-10 19:57:21 +00003780 y;
3781
cristy7c6dc152011-02-11 14:10:55 +00003782 size_t
3783 gap;
3784
cristy4d727152011-02-10 19:57:21 +00003785 ssize_t
cristy4d727152011-02-10 19:57:21 +00003786 x;
3787
3788 if (images->previous == (Image *) NULL)
3789 return(0);
3790 right_image=images;
3791 SetGeometry(smush_image,&right_geometry);
3792 GravityAdjustGeometry(right_image->columns,right_image->rows,
3793 right_image->gravity,&right_geometry);
3794 left_image=images->previous;
3795 SetGeometry(smush_image,&left_geometry);
3796 GravityAdjustGeometry(left_image->columns,left_image->rows,
3797 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003798 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003799 left_view=AcquireCacheView(left_image);
3800 right_view=AcquireCacheView(right_image);
3801 for (y=0; y < (ssize_t) smush_image->rows; y++)
3802 {
3803 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3804 {
cristydab7e912011-02-11 18:19:24 +00003805 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003806 if ((p == (const Quantum *) NULL) ||
3807 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003808 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003809 break;
3810 }
cristy4ef6f062011-02-10 20:30:22 +00003811 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003812 for (x=0; x < (ssize_t) right_image->columns; x++)
3813 {
cristydab7e912011-02-11 18:19:24 +00003814 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003815 exception);
cristy4c08aed2011-07-01 19:47:50 +00003816 if ((p == (const Quantum *) NULL) ||
3817 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3818 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003819 break;
3820 }
cristy7c6dc152011-02-11 14:10:55 +00003821 if ((x+i) < (ssize_t) gap)
3822 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003823 }
3824 right_view=DestroyCacheView(right_view);
3825 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003826 if (y < (ssize_t) smush_image->rows)
3827 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003828 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003829}
3830
cristy7c6dc152011-02-11 14:10:55 +00003831static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003832 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003833{
cristy4d727152011-02-10 19:57:21 +00003834 CacheView
3835 *bottom_view,
3836 *top_view;
3837
3838 const Image
3839 *bottom_image,
3840 *top_image;
3841
cristy4d727152011-02-10 19:57:21 +00003842 RectangleInfo
3843 bottom_geometry,
3844 top_geometry;
3845
cristy4c08aed2011-07-01 19:47:50 +00003846 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003847 *p;
3848
cristy4d727152011-02-10 19:57:21 +00003849 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003850 i,
cristy4d727152011-02-10 19:57:21 +00003851 x;
3852
cristy7c6dc152011-02-11 14:10:55 +00003853 size_t
3854 gap;
3855
cristy4d727152011-02-10 19:57:21 +00003856 ssize_t
cristy4d727152011-02-10 19:57:21 +00003857 y;
3858
3859 if (images->previous == (Image *) NULL)
3860 return(0);
3861 bottom_image=images;
3862 SetGeometry(smush_image,&bottom_geometry);
3863 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3864 bottom_image->gravity,&bottom_geometry);
3865 top_image=images->previous;
3866 SetGeometry(smush_image,&top_geometry);
3867 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3868 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003869 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003870 top_view=AcquireCacheView(top_image);
3871 bottom_view=AcquireCacheView(bottom_image);
3872 for (x=0; x < (ssize_t) smush_image->columns; x++)
3873 {
3874 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3875 {
cristydab7e912011-02-11 18:19:24 +00003876 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003877 if ((p == (const Quantum *) NULL) ||
3878 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3879 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003880 break;
3881 }
cristy4ef6f062011-02-10 20:30:22 +00003882 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003883 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3884 {
cristydab7e912011-02-11 18:19:24 +00003885 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3886 exception);
cristy4c08aed2011-07-01 19:47:50 +00003887 if ((p == (const Quantum *) NULL) ||
3888 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3889 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003890 break;
3891 }
cristy7c6dc152011-02-11 14:10:55 +00003892 if ((y+i) < (ssize_t) gap)
3893 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003894 }
3895 bottom_view=DestroyCacheView(bottom_view);
3896 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003897 if (x < (ssize_t) smush_image->columns)
3898 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003899 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003900}
3901
3902MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003903 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3904{
3905#define SmushImageTag "Smush/Image"
3906
3907 CacheView
cristybb5dced2011-02-10 02:17:16 +00003908 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003909
cristy4ca38e22011-02-10 02:57:49 +00003910 const Image
3911 *image;
3912
cristy4285d782011-02-09 20:12:28 +00003913 Image
3914 *smush_image;
3915
3916 MagickBooleanType
3917 matte,
3918 proceed,
3919 status;
3920
3921 MagickOffsetType
3922 n;
3923
3924 RectangleInfo
3925 geometry;
3926
3927 register const Image
3928 *next;
3929
3930 size_t
3931 height,
3932 number_images,
3933 width;
3934
3935 ssize_t
3936 x_offset,
cristy4285d782011-02-09 20:12:28 +00003937 y_offset;
3938
3939 /*
cristy7c6dc152011-02-11 14:10:55 +00003940 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003941 */
cristy4ca38e22011-02-10 02:57:49 +00003942 assert(images != (Image *) NULL);
3943 assert(images->signature == MagickSignature);
3944 if (images->debug != MagickFalse)
3945 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003946 assert(exception != (ExceptionInfo *) NULL);
3947 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003948 image=images;
cristy4285d782011-02-09 20:12:28 +00003949 matte=image->matte;
3950 number_images=1;
3951 width=image->columns;
3952 height=image->rows;
3953 next=GetNextImageInList(image);
3954 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3955 {
3956 if (next->matte != MagickFalse)
3957 matte=MagickTrue;
3958 number_images++;
3959 if (stack != MagickFalse)
3960 {
3961 if (next->columns > width)
3962 width=next->columns;
3963 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003964 if (next->previous != (Image *) NULL)
3965 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003966 continue;
3967 }
3968 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003969 if (next->previous != (Image *) NULL)
3970 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003971 if (next->rows > height)
3972 height=next->rows;
3973 }
3974 /*
cristy7c6dc152011-02-11 14:10:55 +00003975 Smush images.
cristy4285d782011-02-09 20:12:28 +00003976 */
3977 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3978 if (smush_image == (Image *) NULL)
3979 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003980 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003981 {
cristy4285d782011-02-09 20:12:28 +00003982 smush_image=DestroyImage(smush_image);
3983 return((Image *) NULL);
3984 }
3985 smush_image->matte=matte;
3986 (void) SetImageBackgroundColor(smush_image);
3987 status=MagickTrue;
3988 x_offset=0;
3989 y_offset=0;
3990 smush_view=AcquireCacheView(smush_image);
3991 for (n=0; n < (MagickOffsetType) number_images; n++)
3992 {
3993 SetGeometry(smush_image,&geometry);
3994 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3995 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003996 {
3997 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003998 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003999 }
cristy4285d782011-02-09 20:12:28 +00004000 else
cristy4ca38e22011-02-10 02:57:49 +00004001 {
cristy7c6dc152011-02-11 14:10:55 +00004002 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004003 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004004 }
cristybb5dced2011-02-10 02:17:16 +00004005 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004006 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4007 if (proceed == MagickFalse)
4008 break;
4009 if (stack == MagickFalse)
4010 {
4011 x_offset+=(ssize_t) image->columns;
4012 y_offset=0;
4013 }
4014 else
4015 {
4016 x_offset=0;
4017 y_offset+=(ssize_t) image->rows;
4018 }
4019 image=GetNextImageInList(image);
4020 }
cristy4ef6f062011-02-10 20:30:22 +00004021 if (stack == MagickFalse)
4022 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004023 else
cristy4ef6f062011-02-10 20:30:22 +00004024 smush_image->rows=(size_t) y_offset;
4025 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004026 if (status == MagickFalse)
4027 smush_image=DestroyImage(smush_image);
4028 return(smush_image);
4029}
4030
4031/*
4032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4033% %
4034% %
4035% %
cristy3ed852e2009-09-05 21:47:34 +00004036% S t r i p I m a g e %
4037% %
4038% %
4039% %
4040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4041%
cristy376bda92009-12-22 21:15:23 +00004042% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004043%
4044% The format of the StripImage method is:
4045%
4046% MagickBooleanType StripImage(Image *image)
4047%
4048% A description of each parameter follows:
4049%
4050% o image: the image.
4051%
4052*/
4053MagickExport MagickBooleanType StripImage(Image *image)
4054{
4055 assert(image != (Image *) NULL);
4056 if (image->debug != MagickFalse)
4057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4058 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004059 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004060 (void) DeleteImageProperty(image,"date:create");
4061 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004062 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004063 return(MagickTrue);
4064}
4065
4066/*
4067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4068% %
4069% %
4070% %
4071+ S y n c I m a g e %
4072% %
4073% %
4074% %
4075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4076%
4077% SyncImage() initializes the red, green, and blue intensities of each pixel
4078% as defined by the colormap index.
4079%
4080% The format of the SyncImage method is:
4081%
4082% MagickBooleanType SyncImage(Image *image)
4083%
4084% A description of each parameter follows:
4085%
4086% o image: the image.
4087%
4088*/
4089
cristy4c08aed2011-07-01 19:47:50 +00004090static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004091 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004092{
4093 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004094 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004095 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004096 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004097}
4098
4099MagickExport MagickBooleanType SyncImage(Image *image)
4100{
4101 CacheView
4102 *image_view;
4103
4104 ExceptionInfo
4105 *exception;
4106
cristy3ed852e2009-09-05 21:47:34 +00004107 MagickBooleanType
4108 range_exception,
4109 status;
4110
cristycb6d09b2010-06-19 01:59:36 +00004111 ssize_t
4112 y;
4113
cristy3ed852e2009-09-05 21:47:34 +00004114 assert(image != (Image *) NULL);
4115 if (image->debug != MagickFalse)
4116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4117 assert(image->signature == MagickSignature);
4118 if (image->storage_class == DirectClass)
4119 return(MagickFalse);
4120 range_exception=MagickFalse;
4121 status=MagickTrue;
4122 exception=(&image->exception);
4123 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004124#if defined(MAGICKCORE_OPENMP_SUPPORT)
4125 #pragma omp parallel for schedule(dynamic,4) shared(status)
4126#endif
cristybb503372010-05-27 20:51:26 +00004127 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004128 {
cristy4c08aed2011-07-01 19:47:50 +00004129 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004130 index;
4131
cristy4c08aed2011-07-01 19:47:50 +00004132 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004133 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004134
cristycb6d09b2010-06-19 01:59:36 +00004135 register ssize_t
4136 x;
4137
cristy48974b92009-12-19 02:36:06 +00004138 if (status == MagickFalse)
4139 continue;
cristy3ed852e2009-09-05 21:47:34 +00004140 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004141 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004142 {
4143 status=MagickFalse;
4144 continue;
4145 }
cristybb503372010-05-27 20:51:26 +00004146 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004147 {
cristy4c08aed2011-07-01 19:47:50 +00004148 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004149 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004150 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00004151 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004152 }
4153 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4154 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004155 }
4156 image_view=DestroyCacheView(image_view);
4157 if (range_exception != MagickFalse)
4158 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4159 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4160 return(status);
4161}
cristy1626d332009-11-10 16:58:17 +00004162
4163/*
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165% %
4166% %
4167% %
4168% S y n c I m a g e S e t t i n g s %
4169% %
4170% %
4171% %
4172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173%
4174% SyncImageSettings() sync the image info options to the image.
4175%
4176% The format of the SyncImageSettings method is:
4177%
4178% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4179% Image *image)
4180% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4181% Image *image)
4182%
4183% A description of each parameter follows:
4184%
4185% o image_info: the image info.
4186%
4187% o image: the image.
4188%
4189*/
4190
4191MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4192 Image *images)
4193{
4194 Image
4195 *image;
4196
4197 assert(image_info != (const ImageInfo *) NULL);
4198 assert(image_info->signature == MagickSignature);
4199 assert(images != (Image *) NULL);
4200 assert(images->signature == MagickSignature);
4201 if (images->debug != MagickFalse)
4202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4203 image=images;
4204 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4205 (void) SyncImageSettings(image_info,image);
4206 (void) DeleteImageOption(image_info,"page");
4207 return(MagickTrue);
4208}
4209
4210MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4211 Image *image)
4212{
4213 char
4214 property[MaxTextExtent];
4215
4216 const char
cristy9a703812010-07-26 14:50:29 +00004217 *option,
4218 *value;
cristy1626d332009-11-10 16:58:17 +00004219
4220 GeometryInfo
4221 geometry_info;
4222
4223 MagickStatusType
4224 flags;
4225
cristy19eb6412010-04-23 14:42:29 +00004226 ResolutionType
4227 units;
4228
cristy1626d332009-11-10 16:58:17 +00004229 /*
4230 Sync image options.
4231 */
4232 assert(image_info != (const ImageInfo *) NULL);
4233 assert(image_info->signature == MagickSignature);
4234 assert(image != (Image *) NULL);
4235 assert(image->signature == MagickSignature);
4236 if (image->debug != MagickFalse)
4237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4238 option=GetImageOption(image_info,"background");
4239 if (option != (const char *) NULL)
4240 (void) QueryColorDatabase(option,&image->background_color,
4241 &image->exception);
4242 option=GetImageOption(image_info,"bias");
4243 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004244 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004245 option=GetImageOption(image_info,"black-point-compensation");
4246 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004247 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004248 MagickBooleanOptions,MagickFalse,option);
4249 option=GetImageOption(image_info,"blue-primary");
4250 if (option != (const char *) NULL)
4251 {
4252 flags=ParseGeometry(option,&geometry_info);
4253 image->chromaticity.blue_primary.x=geometry_info.rho;
4254 image->chromaticity.blue_primary.y=geometry_info.sigma;
4255 if ((flags & SigmaValue) == 0)
4256 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4257 }
4258 option=GetImageOption(image_info,"bordercolor");
4259 if (option != (const char *) NULL)
4260 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4261 option=GetImageOption(image_info,"colors");
4262 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004263 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004264 option=GetImageOption(image_info,"compose");
4265 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004266 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004267 MagickFalse,option);
4268 option=GetImageOption(image_info,"compress");
4269 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004270 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004271 MagickCompressOptions,MagickFalse,option);
4272 option=GetImageOption(image_info,"debug");
4273 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004274 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004275 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004276 option=GetImageOption(image_info,"density");
4277 if (option != (const char *) NULL)
4278 {
4279 GeometryInfo
4280 geometry_info;
4281
4282 /*
4283 Set image density.
4284 */
4285 flags=ParseGeometry(option,&geometry_info);
4286 image->x_resolution=geometry_info.rho;
4287 image->y_resolution=geometry_info.sigma;
4288 if ((flags & SigmaValue) == 0)
4289 image->y_resolution=image->x_resolution;
4290 }
cristy1626d332009-11-10 16:58:17 +00004291 option=GetImageOption(image_info,"depth");
4292 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004293 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004294 option=GetImageOption(image_info,"endian");
4295 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004296 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004297 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004298 option=GetImageOption(image_info,"filter");
4299 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004300 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004301 MagickFalse,option);
4302 option=GetImageOption(image_info,"fuzz");
4303 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004304 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004305 option=GetImageOption(image_info,"gravity");
4306 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004307 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004308 MagickFalse,option);
4309 option=GetImageOption(image_info,"green-primary");
4310 if (option != (const char *) NULL)
4311 {
4312 flags=ParseGeometry(option,&geometry_info);
4313 image->chromaticity.green_primary.x=geometry_info.rho;
4314 image->chromaticity.green_primary.y=geometry_info.sigma;
4315 if ((flags & SigmaValue) == 0)
4316 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4317 }
4318 option=GetImageOption(image_info,"intent");
4319 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004320 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004321 MagickIntentOptions,MagickFalse,option);
4322 option=GetImageOption(image_info,"interlace");
4323 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004324 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004325 MagickFalse,option);
4326 option=GetImageOption(image_info,"interpolate");
4327 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004328 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004329 MagickInterpolateOptions,MagickFalse,option);
4330 option=GetImageOption(image_info,"loop");
4331 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004332 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004333 option=GetImageOption(image_info,"mattecolor");
4334 if (option != (const char *) NULL)
4335 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4336 option=GetImageOption(image_info,"orient");
4337 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004338 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004339 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004340 option=GetImageOption(image_info,"page");
4341 if (option != (const char *) NULL)
4342 {
4343 char
4344 *geometry;
4345
4346 geometry=GetPageGeometry(option);
4347 flags=ParseAbsoluteGeometry(geometry,&image->page);
4348 geometry=DestroyString(geometry);
4349 }
cristy1626d332009-11-10 16:58:17 +00004350 option=GetImageOption(image_info,"quality");
4351 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004352 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004353 option=GetImageOption(image_info,"red-primary");
4354 if (option != (const char *) NULL)
4355 {
4356 flags=ParseGeometry(option,&geometry_info);
4357 image->chromaticity.red_primary.x=geometry_info.rho;
4358 image->chromaticity.red_primary.y=geometry_info.sigma;
4359 if ((flags & SigmaValue) == 0)
4360 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4361 }
4362 if (image_info->quality != UndefinedCompressionQuality)
4363 image->quality=image_info->quality;
4364 option=GetImageOption(image_info,"scene");
4365 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004366 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004367 option=GetImageOption(image_info,"taint");
4368 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004369 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004370 MagickFalse,option);
4371 option=GetImageOption(image_info,"tile-offset");
4372 if (option != (const char *) NULL)
4373 {
4374 char
4375 *geometry;
4376
4377 geometry=GetPageGeometry(option);
4378 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4379 geometry=DestroyString(geometry);
4380 }
4381 option=GetImageOption(image_info,"transparent-color");
4382 if (option != (const char *) NULL)
4383 (void) QueryColorDatabase(option,&image->transparent_color,
4384 &image->exception);
4385 option=GetImageOption(image_info,"type");
4386 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004387 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004388 option);
4389 option=GetImageOption(image_info,"units");
4390 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004391 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004392 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004393 else
4394 units = image_info->units;
4395 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004396 {
cristy19eb6412010-04-23 14:42:29 +00004397 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004398 switch (image->units)
4399 {
4400 case PixelsPerInchResolution:
4401 {
cristy19eb6412010-04-23 14:42:29 +00004402 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004403 {
4404 image->x_resolution/=2.54;
4405 image->y_resolution/=2.54;
4406 }
4407 break;
4408 }
4409 case PixelsPerCentimeterResolution:
4410 {
cristy19eb6412010-04-23 14:42:29 +00004411 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004412 {
cristybb503372010-05-27 20:51:26 +00004413 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004414 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004415 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004416 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004417 }
4418 break;
4419 }
4420 default:
4421 break;
4422 }
cristy19eb6412010-04-23 14:42:29 +00004423 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004424 }
4425 option=GetImageOption(image_info,"white-point");
4426 if (option != (const char *) NULL)
4427 {
4428 flags=ParseGeometry(option,&geometry_info);
4429 image->chromaticity.white_point.x=geometry_info.rho;
4430 image->chromaticity.white_point.y=geometry_info.sigma;
4431 if ((flags & SigmaValue) == 0)
4432 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4433 }
4434 ResetImageOptionIterator(image_info);
4435 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4436 {
4437 value=GetImageOption(image_info,option);
4438 if (value != (const char *) NULL)
4439 {
cristyb51dff52011-05-19 16:55:47 +00004440 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004441 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004442 }
4443 option=GetNextImageOption(image_info);
4444 }
4445 return(MagickTrue);
4446}