blob: 5a6dc37d740c96f1864474f2d458973acfef6c58 [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;
cristy5e0890f2011-07-07 23:30:35 +0000808 clone_image->map=image->map;
cristyed231572011-07-14 02:18:59 +0000809 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +0000810 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
811 MaxTextExtent);
812 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
813 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
814 clone_image->progress_monitor=image->progress_monitor;
815 clone_image->client_data=image->client_data;
816 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000817 clone_image->next=image->next;
818 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000819 clone_image->list=NewImageList();
820 clone_image->clip_mask=NewImageList();
821 clone_image->mask=NewImageList();
822 if (detach == MagickFalse)
823 clone_image->blob=ReferenceBlob(image->blob);
824 else
cristybee00932011-01-15 20:28:27 +0000825 {
826 clone_image->next=NewImageList();
827 clone_image->previous=NewImageList();
828 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
829 }
cristy73724512010-04-12 14:43:14 +0000830 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000831 clone_image->debug=IsEventLogging();
832 clone_image->semaphore=AllocateSemaphoreInfo();
833 if ((columns == 0) && (rows == 0))
834 {
835 if (image->montage != (char *) NULL)
836 (void) CloneString(&clone_image->montage,image->montage);
837 if (image->directory != (char *) NULL)
838 (void) CloneString(&clone_image->directory,image->directory);
839 if (image->clip_mask != (Image *) NULL)
840 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
841 exception);
842 if (image->mask != (Image *) NULL)
843 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
844 clone_image->cache=ReferencePixelCache(image->cache);
845 return(clone_image);
846 }
cristy1ab35fb2011-04-15 01:25:56 +0000847 if ((columns == image->columns) && (rows == image->rows))
848 {
849 if (image->clip_mask != (Image *) NULL)
850 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
851 exception);
852 if (image->mask != (Image *) NULL)
853 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
854 }
cristy3ed852e2009-09-05 21:47:34 +0000855 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000856 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
857 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
858 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000859 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000860 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
861 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
862 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000863 clone_image->columns=columns;
864 clone_image->rows=rows;
865 clone_image->cache=ClonePixelCache(image->cache);
866 return(clone_image);
867}
868
869/*
870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871% %
872% %
873% %
874% C l o n e I m a g e I n f o %
875% %
876% %
877% %
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879%
880% CloneImageInfo() makes a copy of the given image info structure. If
881% NULL is specified, a new image info structure is created initialized to
882% default values.
883%
884% The format of the CloneImageInfo method is:
885%
886% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
887%
888% A description of each parameter follows:
889%
890% o image_info: the image info.
891%
892*/
893MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
894{
895 ImageInfo
896 *clone_info;
897
898 clone_info=AcquireImageInfo();
899 if (image_info == (ImageInfo *) NULL)
900 return(clone_info);
901 clone_info->compression=image_info->compression;
902 clone_info->temporary=image_info->temporary;
903 clone_info->adjoin=image_info->adjoin;
904 clone_info->antialias=image_info->antialias;
905 clone_info->scene=image_info->scene;
906 clone_info->number_scenes=image_info->number_scenes;
907 clone_info->depth=image_info->depth;
908 if (image_info->size != (char *) NULL)
909 (void) CloneString(&clone_info->size,image_info->size);
910 if (image_info->extract != (char *) NULL)
911 (void) CloneString(&clone_info->extract,image_info->extract);
912 if (image_info->scenes != (char *) NULL)
913 (void) CloneString(&clone_info->scenes,image_info->scenes);
914 if (image_info->page != (char *) NULL)
915 (void) CloneString(&clone_info->page,image_info->page);
916 clone_info->interlace=image_info->interlace;
917 clone_info->endian=image_info->endian;
918 clone_info->units=image_info->units;
919 clone_info->quality=image_info->quality;
920 if (image_info->sampling_factor != (char *) NULL)
921 (void) CloneString(&clone_info->sampling_factor,
922 image_info->sampling_factor);
923 if (image_info->server_name != (char *) NULL)
924 (void) CloneString(&clone_info->server_name,image_info->server_name);
925 if (image_info->font != (char *) NULL)
926 (void) CloneString(&clone_info->font,image_info->font);
927 if (image_info->texture != (char *) NULL)
928 (void) CloneString(&clone_info->texture,image_info->texture);
929 if (image_info->density != (char *) NULL)
930 (void) CloneString(&clone_info->density,image_info->density);
931 clone_info->pointsize=image_info->pointsize;
932 clone_info->fuzz=image_info->fuzz;
cristy3ed852e2009-09-05 21:47:34 +0000933 clone_info->background_color=image_info->background_color;
934 clone_info->border_color=image_info->border_color;
935 clone_info->matte_color=image_info->matte_color;
936 clone_info->transparent_color=image_info->transparent_color;
937 clone_info->dither=image_info->dither;
938 clone_info->monochrome=image_info->monochrome;
939 clone_info->colors=image_info->colors;
940 clone_info->colorspace=image_info->colorspace;
941 clone_info->type=image_info->type;
942 clone_info->orientation=image_info->orientation;
943 clone_info->preview_type=image_info->preview_type;
944 clone_info->group=image_info->group;
945 clone_info->ping=image_info->ping;
946 clone_info->verbose=image_info->verbose;
947 if (image_info->view != (char *) NULL)
948 (void) CloneString(&clone_info->view,image_info->view);
949 if (image_info->authenticate != (char *) NULL)
950 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
951 (void) CloneImageOptions(clone_info,image_info);
952 clone_info->progress_monitor=image_info->progress_monitor;
953 clone_info->client_data=image_info->client_data;
954 clone_info->cache=image_info->cache;
955 if (image_info->cache != (void *) NULL)
956 clone_info->cache=ReferencePixelCache(image_info->cache);
957 if (image_info->profile != (void *) NULL)
958 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
959 image_info->profile);
960 SetImageInfoFile(clone_info,image_info->file);
961 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
962 clone_info->stream=image_info->stream;
963 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
964 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
965 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
966 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
967 (void) CopyMagickString(clone_info->filename,image_info->filename,
968 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000969 clone_info->channel=image_info->channel;
970 clone_info->debug=IsEventLogging();
971 clone_info->signature=image_info->signature;
972 return(clone_info);
973}
974
975/*
976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
977% %
978% %
979% %
980% C o m b i n e I m a g e s %
981% %
982% %
983% %
984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985%
986% CombineImages() combines one or more images into a single image. The
987% grayscale value of the pixels of each image in the sequence is assigned in
988% order to the specified channels of the combined image. The typical
989% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
990%
991% The format of the CombineImages method is:
992%
cristy3139dc22011-07-08 00:11:42 +0000993% Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000994%
995% A description of each parameter follows:
996%
997% o image: the image.
998%
999% o exception: return any errors or warnings in this structure.
1000%
1001*/
cristy3139dc22011-07-08 00:11:42 +00001002MagickExport Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001003{
1004#define CombineImageTag "Combine/Image"
1005
1006 CacheView
1007 *combine_view;
1008
1009 const Image
1010 *next;
1011
1012 Image
1013 *combine_image;
1014
cristy3ed852e2009-09-05 21:47:34 +00001015 MagickBooleanType
1016 status;
1017
cristybb503372010-05-27 20:51:26 +00001018 MagickOffsetType
1019 progress;
1020
1021 ssize_t
1022 y;
1023
cristy3ed852e2009-09-05 21:47:34 +00001024 /*
1025 Ensure the image are the same size.
1026 */
1027 assert(image != (const Image *) NULL);
1028 assert(image->signature == MagickSignature);
1029 if (image->debug != MagickFalse)
1030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1031 assert(exception != (ExceptionInfo *) NULL);
1032 assert(exception->signature == MagickSignature);
1033 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1034 {
1035 if ((next->columns != image->columns) || (next->rows != image->rows))
1036 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1037 }
1038 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1039 if (combine_image == (Image *) NULL)
1040 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00001041 if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001042 {
cristy3ed852e2009-09-05 21:47:34 +00001043 combine_image=DestroyImage(combine_image);
1044 return((Image *) NULL);
1045 }
cristyed231572011-07-14 02:18:59 +00001046 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001047 combine_image->matte=MagickTrue;
1048 (void) SetImageBackgroundColor(combine_image);
1049 /*
1050 Combine images.
1051 */
1052 status=MagickTrue;
1053 progress=0;
1054 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001055 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001056 {
1057 CacheView
1058 *image_view;
1059
1060 const Image
1061 *next;
1062
cristy4c08aed2011-07-01 19:47:50 +00001063 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001064 *pixels;
1065
cristy4c08aed2011-07-01 19:47:50 +00001066 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001067 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001068
cristy4c08aed2011-07-01 19:47:50 +00001069 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001070 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001071
cristycb6d09b2010-06-19 01:59:36 +00001072 register ssize_t
1073 x;
1074
cristy3ed852e2009-09-05 21:47:34 +00001075 if (status == MagickFalse)
1076 continue;
1077 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1078 1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001079 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001080 {
1081 status=MagickFalse;
1082 continue;
1083 }
1084 next=image;
cristyed231572011-07-14 02:18:59 +00001085 if (((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001086 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001087 {
1088 image_view=AcquireCacheView(next);
1089 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001090 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001091 continue;
1092 q=pixels;
cristybb503372010-05-27 20:51:26 +00001093 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001094 {
cristy4c08aed2011-07-01 19:47:50 +00001095 SetPixelRed(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001096 p+=GetPixelChannels(image);
1097 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001098 }
1099 image_view=DestroyCacheView(image_view);
1100 next=GetNextImageInList(next);
1101 }
cristyed231572011-07-14 02:18:59 +00001102 if (((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001103 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 image_view=AcquireCacheView(next);
1106 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001107 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001108 continue;
1109 q=pixels;
cristybb503372010-05-27 20:51:26 +00001110 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001111 {
cristy4c08aed2011-07-01 19:47:50 +00001112 SetPixelGreen(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001113 p+=GetPixelChannels(image);
1114 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001115 }
1116 image_view=DestroyCacheView(image_view);
1117 next=GetNextImageInList(next);
1118 }
cristyed231572011-07-14 02:18:59 +00001119 if (((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001120 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001121 {
1122 image_view=AcquireCacheView(next);
1123 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001124 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001125 continue;
1126 q=pixels;
cristybb503372010-05-27 20:51:26 +00001127 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
cristy4c08aed2011-07-01 19:47:50 +00001129 SetPixelBlue(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001130 p+=GetPixelChannels(image);
1131 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001132 }
1133 image_view=DestroyCacheView(image_view);
1134 next=GetNextImageInList(next);
1135 }
cristyed231572011-07-14 02:18:59 +00001136 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +00001137 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1138 {
cristy3ed852e2009-09-05 21:47:34 +00001139 image_view=AcquireCacheView(next);
1140 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001141 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001142 continue;
cristy4c08aed2011-07-01 19:47:50 +00001143 q=pixels;
cristybb503372010-05-27 20:51:26 +00001144 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001145 {
cristy4c08aed2011-07-01 19:47:50 +00001146 SetPixelBlack(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001147 p+=GetPixelChannels(image);
1148 q+=GetPixelChannels(combine_image);
cristy4c08aed2011-07-01 19:47:50 +00001149 }
1150 image_view=DestroyCacheView(image_view);
1151 next=GetNextImageInList(next);
1152 }
cristyed231572011-07-14 02:18:59 +00001153 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
cristy2b9582a2011-07-04 17:38:56 +00001154 (next != (Image *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00001155 {
1156 image_view=AcquireCacheView(next);
1157 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1158 if (p == (const Quantum *) NULL)
1159 continue;
1160 q=pixels;
1161 for (x=0; x < (ssize_t) combine_image->columns; x++)
1162 {
1163 SetPixelAlpha(image,GetPixelIntensity(image,p),q);
cristyed231572011-07-14 02:18:59 +00001164 p+=GetPixelChannels(image);
1165 q+=GetPixelChannels(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001166 }
1167 image_view=DestroyCacheView(image_view);
1168 next=GetNextImageInList(next);
1169 }
1170 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1171 status=MagickFalse;
1172 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1173 {
1174 MagickBooleanType
1175 proceed;
1176
cristy3ed852e2009-09-05 21:47:34 +00001177 proceed=SetImageProgress(image,CombineImageTag,progress++,
1178 combine_image->rows);
1179 if (proceed == MagickFalse)
1180 status=MagickFalse;
1181 }
1182 }
1183 combine_view=DestroyCacheView(combine_view);
1184 if (status == MagickFalse)
1185 combine_image=DestroyImage(combine_image);
1186 return(combine_image);
1187}
1188
1189/*
1190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191% %
1192% %
1193% %
cristy3ed852e2009-09-05 21:47:34 +00001194% D e s t r o y I m a g e %
1195% %
1196% %
1197% %
1198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199%
1200% DestroyImage() dereferences an image, deallocating memory associated with
1201% the image if the reference count becomes zero.
1202%
1203% The format of the DestroyImage method is:
1204%
1205% Image *DestroyImage(Image *image)
1206%
1207% A description of each parameter follows:
1208%
1209% o image: the image.
1210%
1211*/
1212MagickExport Image *DestroyImage(Image *image)
1213{
1214 MagickBooleanType
1215 destroy;
1216
1217 /*
1218 Dereference image.
1219 */
1220 assert(image != (Image *) NULL);
1221 assert(image->signature == MagickSignature);
1222 if (image->debug != MagickFalse)
1223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1224 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001225 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001226 image->reference_count--;
1227 if (image->reference_count == 0)
1228 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001229 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001230 if (destroy == MagickFalse)
1231 return((Image *) NULL);
1232 /*
1233 Destroy image.
1234 */
1235 DestroyImagePixels(image);
cristyed231572011-07-14 02:18:59 +00001236 image->channel_map=DestroyPixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +00001237 if (image->clip_mask != (Image *) NULL)
1238 image->clip_mask=DestroyImage(image->clip_mask);
1239 if (image->mask != (Image *) NULL)
1240 image->mask=DestroyImage(image->mask);
1241 if (image->montage != (char *) NULL)
1242 image->montage=DestroyString(image->montage);
1243 if (image->directory != (char *) NULL)
1244 image->directory=DestroyString(image->directory);
1245 if (image->colormap != (PixelPacket *) NULL)
1246 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1247 if (image->geometry != (char *) NULL)
1248 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001249 DestroyImageProfiles(image);
1250 DestroyImageProperties(image);
1251 DestroyImageArtifacts(image);
1252 if (image->ascii85 != (Ascii85Info*) NULL)
1253 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1254 DestroyBlob(image);
1255 (void) DestroyExceptionInfo(&image->exception);
1256 if (image->semaphore != (SemaphoreInfo *) NULL)
1257 DestroySemaphoreInfo(&image->semaphore);
1258 image->signature=(~MagickSignature);
1259 image=(Image *) RelinquishMagickMemory(image);
1260 return(image);
1261}
1262
1263/*
1264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1265% %
1266% %
1267% %
1268% D e s t r o y I m a g e I n f o %
1269% %
1270% %
1271% %
1272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1273%
1274% DestroyImageInfo() deallocates memory associated with an ImageInfo
1275% structure.
1276%
1277% The format of the DestroyImageInfo method is:
1278%
1279% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1280%
1281% A description of each parameter follows:
1282%
1283% o image_info: the image info.
1284%
1285*/
1286MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1287{
1288 assert(image_info != (ImageInfo *) NULL);
1289 assert(image_info->signature == MagickSignature);
1290 if (image_info->debug != MagickFalse)
1291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1292 image_info->filename);
1293 if (image_info->size != (char *) NULL)
1294 image_info->size=DestroyString(image_info->size);
1295 if (image_info->extract != (char *) NULL)
1296 image_info->extract=DestroyString(image_info->extract);
1297 if (image_info->scenes != (char *) NULL)
1298 image_info->scenes=DestroyString(image_info->scenes);
1299 if (image_info->page != (char *) NULL)
1300 image_info->page=DestroyString(image_info->page);
1301 if (image_info->sampling_factor != (char *) NULL)
1302 image_info->sampling_factor=DestroyString(
1303 image_info->sampling_factor);
1304 if (image_info->server_name != (char *) NULL)
1305 image_info->server_name=DestroyString(
1306 image_info->server_name);
1307 if (image_info->font != (char *) NULL)
1308 image_info->font=DestroyString(image_info->font);
1309 if (image_info->texture != (char *) NULL)
1310 image_info->texture=DestroyString(image_info->texture);
1311 if (image_info->density != (char *) NULL)
1312 image_info->density=DestroyString(image_info->density);
1313 if (image_info->view != (char *) NULL)
1314 image_info->view=DestroyString(image_info->view);
1315 if (image_info->authenticate != (char *) NULL)
1316 image_info->authenticate=DestroyString(
1317 image_info->authenticate);
1318 DestroyImageOptions(image_info);
1319 if (image_info->cache != (void *) NULL)
1320 image_info->cache=DestroyPixelCache(image_info->cache);
1321 if (image_info->profile != (StringInfo *) NULL)
1322 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1323 image_info->profile);
1324 image_info->signature=(~MagickSignature);
1325 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1326 return(image_info);
1327}
1328
1329/*
1330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331% %
1332% %
1333% %
1334+ D i s a s s o c i a t e I m a g e S t r e a m %
1335% %
1336% %
1337% %
1338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339%
1340% DisassociateImageStream() disassociates the image stream.
1341%
1342% The format of the DisassociateImageStream method is:
1343%
1344% MagickBooleanType DisassociateImageStream(const Image *image)
1345%
1346% A description of each parameter follows:
1347%
1348% o image: the image.
1349%
1350*/
1351MagickExport void DisassociateImageStream(Image *image)
1352{
1353 assert(image != (const Image *) NULL);
1354 assert(image->signature == MagickSignature);
1355 if (image->debug != MagickFalse)
1356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1357 (void) DetachBlob(image->blob);
1358}
1359
1360/*
1361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362% %
1363% %
1364% %
1365% G e t I m a g e A l p h a C h a n n e l %
1366% %
1367% %
1368% %
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370%
1371% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1372% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1373% than CMYKA.
1374%
1375% The format of the GetImageAlphaChannel method is:
1376%
1377% MagickBooleanType GetImageAlphaChannel(const Image *image)
1378%
1379% A description of each parameter follows:
1380%
1381% o image: the image.
1382%
1383*/
1384MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1385{
1386 assert(image != (const Image *) NULL);
1387 if (image->debug != MagickFalse)
1388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1389 assert(image->signature == MagickSignature);
1390 return(image->matte);
1391}
1392
1393/*
1394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1395% %
1396% %
1397% %
1398% G e t I m a g e C l i p M a s k %
1399% %
1400% %
1401% %
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403%
1404% GetImageClipMask() returns the clip path associated with the image.
1405%
1406% The format of the GetImageClipMask method is:
1407%
1408% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1409%
1410% A description of each parameter follows:
1411%
1412% o image: the image.
1413%
1414*/
1415MagickExport Image *GetImageClipMask(const Image *image,
1416 ExceptionInfo *exception)
1417{
1418 assert(image != (const Image *) NULL);
1419 if (image->debug != MagickFalse)
1420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1421 assert(image->signature == MagickSignature);
1422 if (image->clip_mask == (Image *) NULL)
1423 return((Image *) NULL);
1424 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1425}
1426
1427/*
1428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429% %
1430% %
1431% %
1432% G e t I m a g e E x c e p t i o n %
1433% %
1434% %
1435% %
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437%
1438% GetImageException() traverses an image sequence and returns any
1439% error more severe than noted by the exception parameter.
1440%
1441% The format of the GetImageException method is:
1442%
1443% void GetImageException(Image *image,ExceptionInfo *exception)
1444%
1445% A description of each parameter follows:
1446%
1447% o image: Specifies a pointer to a list of one or more images.
1448%
1449% o exception: return the highest severity exception.
1450%
1451*/
1452MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1453{
1454 register Image
1455 *next;
1456
1457 assert(image != (Image *) NULL);
1458 assert(image->signature == MagickSignature);
1459 if (image->debug != MagickFalse)
1460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1461 assert(exception != (ExceptionInfo *) NULL);
1462 assert(exception->signature == MagickSignature);
1463 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1464 {
1465 if (next->exception.severity == UndefinedException)
1466 continue;
1467 if (next->exception.severity > exception->severity)
1468 InheritException(exception,&next->exception);
1469 next->exception.severity=UndefinedException;
1470 }
1471}
1472
1473/*
1474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475% %
1476% %
1477% %
1478% G e t I m a g e I n f o %
1479% %
1480% %
1481% %
1482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483%
1484% GetImageInfo() initializes image_info to default values.
1485%
1486% The format of the GetImageInfo method is:
1487%
1488% void GetImageInfo(ImageInfo *image_info)
1489%
1490% A description of each parameter follows:
1491%
1492% o image_info: the image info.
1493%
1494*/
1495MagickExport void GetImageInfo(ImageInfo *image_info)
1496{
cristyd9a29192010-10-16 16:49:53 +00001497 const char
1498 *synchronize;
1499
cristy3ed852e2009-09-05 21:47:34 +00001500 ExceptionInfo
1501 *exception;
1502
1503 /*
1504 File and image dimension members.
1505 */
1506 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1507 assert(image_info != (ImageInfo *) NULL);
1508 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1509 image_info->adjoin=MagickTrue;
1510 image_info->interlace=NoInterlace;
1511 image_info->channel=DefaultChannels;
1512 image_info->quality=UndefinedCompressionQuality;
1513 image_info->antialias=MagickTrue;
1514 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001515 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1516 if (synchronize != (const char *) NULL)
1517 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001518 exception=AcquireExceptionInfo();
1519 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1520 exception);
1521 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1522 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1523 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1524 exception);
1525 exception=DestroyExceptionInfo(exception);
1526 image_info->debug=IsEventLogging();
1527 image_info->signature=MagickSignature;
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
cristy15781e52009-12-05 23:05:27 +00001535% G e t I m a g e I n f o F i l e %
1536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541% GetImageInfoFile() returns the image info file member.
1542%
1543% The format of the GetImageInfoFile method is:
1544%
1545% FILE *GetImageInfoFile(const ImageInfo *image_info)
1546%
1547% A description of each parameter follows:
1548%
1549% o image_info: the image info.
1550%
1551*/
1552MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1553{
1554 return(image_info->file);
1555}
1556
1557/*
1558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559% %
1560% %
1561% %
cristy3ed852e2009-09-05 21:47:34 +00001562% G e t I m a g e M a s k %
1563% %
1564% %
1565% %
1566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567%
1568% GetImageMask() returns the mask associated with the image.
1569%
1570% The format of the GetImageMask method is:
1571%
1572% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1573%
1574% A description of each parameter follows:
1575%
1576% o image: the image.
1577%
1578*/
1579MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1580{
1581 assert(image != (const Image *) NULL);
1582 if (image->debug != MagickFalse)
1583 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1584 assert(image->signature == MagickSignature);
1585 if (image->mask == (Image *) NULL)
1586 return((Image *) NULL);
1587 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1588}
1589
1590/*
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592% %
1593% %
1594% %
1595+ G e t I m a g e R e f e r e n c e C o u n t %
1596% %
1597% %
1598% %
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600%
1601% GetImageReferenceCount() returns the image reference count.
1602%
1603% The format of the GetReferenceCount method is:
1604%
cristybb503372010-05-27 20:51:26 +00001605% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001606%
1607% A description of each parameter follows:
1608%
1609% o image: the image.
1610%
1611*/
cristybb503372010-05-27 20:51:26 +00001612MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001613{
cristybb503372010-05-27 20:51:26 +00001614 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001615 reference_count;
1616
1617 assert(image != (Image *) NULL);
1618 assert(image->signature == MagickSignature);
1619 if (image->debug != MagickFalse)
1620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001621 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001622 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001623 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001624 return(reference_count);
1625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
cristy3ed852e2009-09-05 21:47:34 +00001632% 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 %
1633% %
1634% %
1635% %
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637%
1638% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1639% image. A virtual pixel is any pixel access that is outside the boundaries
1640% of the image cache.
1641%
1642% The format of the GetImageVirtualPixelMethod() method is:
1643%
1644% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1645%
1646% A description of each parameter follows:
1647%
1648% o image: the image.
1649%
1650*/
1651MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1652{
1653 assert(image != (Image *) NULL);
1654 assert(image->signature == MagickSignature);
1655 if (image->debug != MagickFalse)
1656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1657 return(GetPixelCacheVirtualMethod(image));
1658}
1659
1660/*
1661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662% %
1663% %
1664% %
1665% I n t e r p r e t I m a g e F i l e n a m e %
1666% %
1667% %
1668% %
1669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1670%
1671% InterpretImageFilename() interprets embedded characters in an image filename.
1672% The filename length is returned.
1673%
1674% The format of the InterpretImageFilename method is:
1675%
1676% size_t InterpretImageFilename(const ImageInfo *image_info,
1677% Image *image,const char *format,int value,char *filename)
1678%
1679% A description of each parameter follows.
1680%
1681% o image_info: the image info..
1682%
1683% o image: the image.
1684%
1685% o format: A filename describing the format to use to write the numeric
1686% argument. Only the first numeric format identifier is replaced.
1687%
1688% o value: Numeric value to substitute into format filename.
1689%
1690% o filename: return the formatted filename in this character buffer.
1691%
1692*/
1693MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1694 Image *image,const char *format,int value,char *filename)
1695{
1696 char
1697 *q;
1698
1699 int
1700 c;
1701
1702 MagickBooleanType
1703 canonical;
1704
1705 register const char
1706 *p;
1707
cristyad785752011-07-27 23:13:03 +00001708 size_t
1709 length;
1710
cristy3ed852e2009-09-05 21:47:34 +00001711 canonical=MagickFalse;
cristyc7b79fc2011-07-28 00:24:17 +00001712 length=0;
cristy3ed852e2009-09-05 21:47:34 +00001713 (void) CopyMagickString(filename,format,MaxTextExtent);
1714 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1715 {
1716 q=(char *) p+1;
1717 if (*q == '%')
1718 {
1719 p=q+1;
1720 continue;
1721 }
1722 if (*q == '0')
1723 {
cristybb503372010-05-27 20:51:26 +00001724 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001725 value;
1726
cristybb503372010-05-27 20:51:26 +00001727 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001728 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001729 }
1730 switch (*q)
1731 {
1732 case 'd':
1733 case 'o':
1734 case 'x':
1735 {
1736 q++;
1737 c=(*q);
1738 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001739 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001740 (p-format)),p,value);
1741 *q=c;
1742 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1743 canonical=MagickTrue;
1744 if (*(q-1) != '%')
1745 break;
1746 p++;
1747 break;
1748 }
1749 case '[':
1750 {
1751 char
1752 pattern[MaxTextExtent];
1753
1754 const char
1755 *value;
1756
cristy3ed852e2009-09-05 21:47:34 +00001757 register char
1758 *r;
1759
cristybb503372010-05-27 20:51:26 +00001760 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001761 i;
1762
cristycb6d09b2010-06-19 01:59:36 +00001763 ssize_t
1764 depth;
1765
cristy3ed852e2009-09-05 21:47:34 +00001766 /*
1767 Image option.
1768 */
1769 if (strchr(p,']') == (char *) NULL)
1770 break;
1771 depth=1;
1772 r=q+1;
1773 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1774 {
1775 if (*r == '[')
1776 depth++;
1777 if (*r == ']')
1778 depth--;
1779 if (depth <= 0)
1780 break;
1781 pattern[i]=(*r++);
1782 }
1783 pattern[i]='\0';
1784 if (LocaleNCompare(pattern,"filename:",9) != 0)
1785 break;
1786 value=(const char *) NULL;
1787 if ((image_info != (const ImageInfo *) NULL) &&
1788 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001789 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001790 else
1791 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001792 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001793 else
1794 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001795 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001796 if (value == (const char *) NULL)
1797 break;
1798 q--;
1799 c=(*q);
1800 *q='\0';
cristyad785752011-07-27 23:13:03 +00001801 (void) CopyMagickString(filename+(p-format-length),value,(size_t)
1802 (MaxTextExtent-(p-format-length)));
1803 length+=strlen(pattern)-1;
cristy3ed852e2009-09-05 21:47:34 +00001804 *q=c;
1805 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1806 canonical=MagickTrue;
1807 if (*(q-1) != '%')
1808 break;
1809 p++;
1810 break;
1811 }
1812 default:
1813 break;
1814 }
1815 }
1816 for (q=filename; *q != '\0'; q++)
1817 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001818 {
1819 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1820 canonical=MagickTrue;
1821 }
cristy3ed852e2009-09-05 21:47:34 +00001822 if (canonical == MagickFalse)
1823 (void) CopyMagickString(filename,format,MaxTextExtent);
1824 return(strlen(filename));
1825}
1826
1827/*
1828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829% %
1830% %
1831% %
1832% I s H i g h D y n a m i c R a n g e I m a g e %
1833% %
1834% %
1835% %
1836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837%
1838% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1839% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1840% 0..65535.
1841%
1842% The format of the IsHighDynamicRangeImage method is:
1843%
1844% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1845% ExceptionInfo *exception)
1846%
1847% A description of each parameter follows:
1848%
1849% o image: the image.
1850%
1851% o exception: return any errors or warnings in this structure.
1852%
1853*/
1854MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1855 ExceptionInfo *exception)
1856{
1857#if !defined(MAGICKCORE_HDRI_SUPPORT)
1858 (void) image;
1859 (void) exception;
1860 return(MagickFalse);
1861#else
1862 CacheView
1863 *image_view;
1864
cristy3ed852e2009-09-05 21:47:34 +00001865 MagickBooleanType
1866 status;
1867
cristy4c08aed2011-07-01 19:47:50 +00001868 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001869 zero;
1870
cristycb6d09b2010-06-19 01:59:36 +00001871 ssize_t
1872 y;
1873
cristy3ed852e2009-09-05 21:47:34 +00001874 assert(image != (Image *) NULL);
1875 assert(image->signature == MagickSignature);
1876 if (image->debug != MagickFalse)
1877 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1878 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00001879 GetPixelInfo(image,&zero);
cristy3ed852e2009-09-05 21:47:34 +00001880 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001881#if defined(MAGICKCORE_OPENMP_SUPPORT)
1882 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001883#endif
cristybb503372010-05-27 20:51:26 +00001884 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001885 {
cristy4c08aed2011-07-01 19:47:50 +00001886 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001887 pixel;
1888
cristy4c08aed2011-07-01 19:47:50 +00001889 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001890 *p;
1891
cristybb503372010-05-27 20:51:26 +00001892 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001893 x;
1894
1895 if (status == MagickFalse)
1896 continue;
1897 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001898 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001899 {
1900 status=MagickFalse;
1901 continue;
1902 }
cristy3ed852e2009-09-05 21:47:34 +00001903 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001904 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001905 {
cristy4c08aed2011-07-01 19:47:50 +00001906 SetPixelInfo(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001907 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1908 (pixel.red != (QuantumAny) pixel.red))
1909 break;
1910 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1911 (pixel.green != (QuantumAny) pixel.green))
1912 break;
1913 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1914 (pixel.blue != (QuantumAny) pixel.blue))
1915 break;
cristy3ed852e2009-09-05 21:47:34 +00001916 if (pixel.colorspace == CMYKColorspace)
1917 {
cristy4c08aed2011-07-01 19:47:50 +00001918 if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
1919 (pixel.black != (QuantumAny) pixel.black))
cristy3ed852e2009-09-05 21:47:34 +00001920 break;
1921 }
cristy4c08aed2011-07-01 19:47:50 +00001922 if (pixel.matte != MagickFalse)
1923 {
1924 if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
1925 (pixel.alpha != (QuantumAny) pixel.alpha))
1926 break;
1927 }
cristyed231572011-07-14 02:18:59 +00001928 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001929 }
cristybb503372010-05-27 20:51:26 +00001930 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001931 status=MagickFalse;
1932 }
1933 image_view=DestroyCacheView(image_view);
1934 return(status != MagickFalse ? MagickFalse : MagickTrue);
1935#endif
1936}
1937
1938/*
1939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1940% %
1941% %
1942% %
1943% I s I m a g e O b j e c t %
1944% %
1945% %
1946% %
1947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1948%
1949% IsImageObject() returns MagickTrue if the image sequence contains a valid
1950% set of image objects.
1951%
1952% The format of the IsImageObject method is:
1953%
1954% MagickBooleanType IsImageObject(const Image *image)
1955%
1956% A description of each parameter follows:
1957%
1958% o image: the image.
1959%
1960*/
1961MagickExport MagickBooleanType IsImageObject(const Image *image)
1962{
1963 register const Image
1964 *p;
1965
1966 assert(image != (Image *) NULL);
1967 if (image->debug != MagickFalse)
1968 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1969 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1970 if (p->signature != MagickSignature)
1971 return(MagickFalse);
1972 return(MagickTrue);
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980% I s T a i n t I m a g e %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1987% since it was first constituted.
1988%
1989% The format of the IsTaintImage method is:
1990%
1991% MagickBooleanType IsTaintImage(const Image *image)
1992%
1993% A description of each parameter follows:
1994%
1995% o image: the image.
1996%
1997*/
1998MagickExport MagickBooleanType IsTaintImage(const Image *image)
1999{
2000 char
2001 magick[MaxTextExtent],
2002 filename[MaxTextExtent];
2003
2004 register const Image
2005 *p;
2006
2007 assert(image != (Image *) NULL);
2008 if (image->debug != MagickFalse)
2009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2010 assert(image->signature == MagickSignature);
2011 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2012 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2013 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2014 {
2015 if (p->taint != MagickFalse)
2016 return(MagickTrue);
2017 if (LocaleCompare(p->magick,magick) != 0)
2018 return(MagickTrue);
2019 if (LocaleCompare(p->filename,filename) != 0)
2020 return(MagickTrue);
2021 }
2022 return(MagickFalse);
2023}
2024
2025/*
2026%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2027% %
2028% %
2029% %
2030% M o d i f y I m a g e %
2031% %
2032% %
2033% %
2034%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035%
2036% ModifyImage() ensures that there is only a single reference to the image
2037% to be modified, updating the provided image pointer to point to a clone of
2038% the original image if necessary.
2039%
2040% The format of the ModifyImage method is:
2041%
2042% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2043%
2044% A description of each parameter follows:
2045%
2046% o image: the image.
2047%
2048% o exception: return any errors or warnings in this structure.
2049%
2050*/
2051MagickExport MagickBooleanType ModifyImage(Image **image,
2052 ExceptionInfo *exception)
2053{
2054 Image
2055 *clone_image;
2056
2057 assert(image != (Image **) NULL);
2058 assert(*image != (Image *) NULL);
2059 assert((*image)->signature == MagickSignature);
2060 if ((*image)->debug != MagickFalse)
2061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2062 if (GetImageReferenceCount(*image) <= 1)
2063 return(MagickTrue);
2064 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002065 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002066 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002067 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002068 *image=clone_image;
2069 return(MagickTrue);
2070}
2071
2072/*
2073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2074% %
2075% %
2076% %
2077% N e w M a g i c k I m a g e %
2078% %
2079% %
2080% %
2081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2082%
2083% NewMagickImage() creates a blank image canvas of the specified size and
2084% background color.
2085%
2086% The format of the NewMagickImage method is:
2087%
2088% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002089% const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002090% const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002091%
2092% A description of each parameter follows:
2093%
2094% o image: the image.
2095%
2096% o width: the image width.
2097%
2098% o height: the image height.
2099%
2100% o background: the image color.
2101%
2102*/
2103MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002104 const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002105 const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002106{
2107 CacheView
2108 *image_view;
2109
2110 ExceptionInfo
2111 *exception;
2112
2113 Image
2114 *image;
2115
cristybb503372010-05-27 20:51:26 +00002116 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002117 y;
2118
2119 MagickBooleanType
2120 status;
2121
2122 assert(image_info != (const ImageInfo *) NULL);
2123 if (image_info->debug != MagickFalse)
2124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2125 assert(image_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002126 assert(background != (const PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002127 image=AcquireImage(image_info);
2128 image->columns=width;
2129 image->rows=height;
2130 image->colorspace=background->colorspace;
2131 image->matte=background->matte;
2132 image->fuzz=background->fuzz;
2133 image->depth=background->depth;
2134 status=MagickTrue;
2135 exception=(&image->exception);
2136 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002137#if defined(MAGICKCORE_OPENMP_SUPPORT)
2138 #pragma omp parallel for schedule(dynamic,4) shared(status)
2139#endif
cristybb503372010-05-27 20:51:26 +00002140 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002141 {
cristy4c08aed2011-07-01 19:47:50 +00002142 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002143 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002144
cristycb6d09b2010-06-19 01:59:36 +00002145 register ssize_t
2146 x;
2147
cristy48974b92009-12-19 02:36:06 +00002148 if (status == MagickFalse)
2149 continue;
cristy3ed852e2009-09-05 21:47:34 +00002150 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002151 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002152 {
2153 status=MagickFalse;
2154 continue;
2155 }
cristybb503372010-05-27 20:51:26 +00002156 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002157 {
cristy4c08aed2011-07-01 19:47:50 +00002158 SetPixelPixelInfo(image,background,q);
cristyed231572011-07-14 02:18:59 +00002159 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002160 }
2161 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2162 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002163 }
2164 image_view=DestroyCacheView(image_view);
2165 if (status == MagickFalse)
2166 image=DestroyImage(image);
2167 return(image);
2168}
2169
2170/*
2171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172% %
2173% %
2174% %
2175% R e f e r e n c e I m a g e %
2176% %
2177% %
2178% %
2179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180%
2181% ReferenceImage() increments the reference count associated with an image
2182% returning a pointer to the image.
2183%
2184% The format of the ReferenceImage method is:
2185%
2186% Image *ReferenceImage(Image *image)
2187%
2188% A description of each parameter follows:
2189%
2190% o image: the image.
2191%
2192*/
2193MagickExport Image *ReferenceImage(Image *image)
2194{
2195 assert(image != (Image *) NULL);
2196 if (image->debug != MagickFalse)
2197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2198 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002199 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002200 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002201 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002202 return(image);
2203}
2204
2205/*
2206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207% %
2208% %
2209% %
2210% R e s e t I m a g e P a g e %
2211% %
2212% %
2213% %
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215%
2216% ResetImagePage() resets the image page canvas and position.
2217%
2218% The format of the ResetImagePage method is:
2219%
2220% MagickBooleanType ResetImagePage(Image *image,const char *page)
2221%
2222% A description of each parameter follows:
2223%
2224% o image: the image.
2225%
2226% o page: the relative page specification.
2227%
2228*/
2229MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2230{
2231 MagickStatusType
2232 flags;
2233
2234 RectangleInfo
2235 geometry;
2236
2237 assert(image != (Image *) NULL);
2238 assert(image->signature == MagickSignature);
2239 if (image->debug != MagickFalse)
2240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2241 flags=ParseAbsoluteGeometry(page,&geometry);
2242 if ((flags & WidthValue) != 0)
2243 {
2244 if ((flags & HeightValue) == 0)
2245 geometry.height=geometry.width;
2246 image->page.width=geometry.width;
2247 image->page.height=geometry.height;
2248 }
2249 if ((flags & AspectValue) != 0)
2250 {
2251 if ((flags & XValue) != 0)
2252 image->page.x+=geometry.x;
2253 if ((flags & YValue) != 0)
2254 image->page.y+=geometry.y;
2255 }
2256 else
2257 {
2258 if ((flags & XValue) != 0)
2259 {
2260 image->page.x=geometry.x;
2261 if ((image->page.width == 0) && (geometry.x > 0))
2262 image->page.width=image->columns+geometry.x;
2263 }
2264 if ((flags & YValue) != 0)
2265 {
2266 image->page.y=geometry.y;
2267 if ((image->page.height == 0) && (geometry.y > 0))
2268 image->page.height=image->rows+geometry.y;
2269 }
2270 }
2271 return(MagickTrue);
2272}
2273
2274/*
2275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276% %
2277% %
2278% %
2279% S e p a r a t e I m a g e C h a n n e l %
2280% %
2281% %
2282% %
2283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284%
cristy3139dc22011-07-08 00:11:42 +00002285% SeparateImage() separates a channel from the image and returns it as
cristy3ed852e2009-09-05 21:47:34 +00002286% a grayscale image. A channel is a particular color component of each pixel
2287% in the image.
2288%
cristy3139dc22011-07-08 00:11:42 +00002289% The format of the SeparateImage method is:
cristy3ed852e2009-09-05 21:47:34 +00002290%
cristy3139dc22011-07-08 00:11:42 +00002291% MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002292%
2293% A description of each parameter follows:
2294%
2295% o image: the image.
2296%
cristy3ed852e2009-09-05 21:47:34 +00002297*/
cristy3139dc22011-07-08 00:11:42 +00002298MagickExport MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002299{
2300#define SeparateImageTag "Separate/Image"
2301
2302 CacheView
2303 *image_view;
2304
2305 ExceptionInfo
2306 *exception;
2307
cristy3ed852e2009-09-05 21:47:34 +00002308 MagickBooleanType
2309 status;
2310
cristybb503372010-05-27 20:51:26 +00002311 MagickOffsetType
2312 progress;
2313
2314 ssize_t
2315 y;
2316
cristy3ed852e2009-09-05 21:47:34 +00002317 assert(image != (Image *) NULL);
2318 assert(image->signature == MagickSignature);
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy47fa6ee2011-08-05 17:35:33 +00002321 exception=(&image->exception);
cristy574cc262011-08-05 01:23:58 +00002322 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002323 return(MagickFalse);
2324 /*
2325 Separate image channels.
2326 */
2327 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002328 progress=0;
cristy3ed852e2009-09-05 21:47:34 +00002329 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002330#if defined(MAGICKCORE_OPENMP_SUPPORT)
2331 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002332#endif
cristybb503372010-05-27 20:51:26 +00002333 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002334 {
cristy4c08aed2011-07-01 19:47:50 +00002335 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002336 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002337
cristycb6d09b2010-06-19 01:59:36 +00002338 register ssize_t
2339 x;
2340
cristy3ed852e2009-09-05 21:47:34 +00002341 if (status == MagickFalse)
2342 continue;
2343 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002344 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002345 {
2346 status=MagickFalse;
2347 continue;
2348 }
cristy3139dc22011-07-08 00:11:42 +00002349 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002350 {
cristyed231572011-07-14 02:18:59 +00002351 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002352 {
cristy4c08aed2011-07-01 19:47:50 +00002353 SetPixelGreen(image,GetPixelRed(image,q),q);
2354 SetPixelBlue(image,GetPixelRed(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002355 }
cristyed231572011-07-14 02:18:59 +00002356 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002357 {
cristy4c08aed2011-07-01 19:47:50 +00002358 SetPixelRed(image,GetPixelGreen(image,q),q);
2359 SetPixelBlue(image,GetPixelGreen(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002360 }
cristyed231572011-07-14 02:18:59 +00002361 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002362 {
cristy4c08aed2011-07-01 19:47:50 +00002363 SetPixelRed(image,GetPixelBlue(image,q),q);
2364 SetPixelGreen(image,GetPixelBlue(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002365 }
cristyed231572011-07-14 02:18:59 +00002366 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002367 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002368 {
cristy4c08aed2011-07-01 19:47:50 +00002369 SetPixelRed(image,GetPixelBlack(image,q),q);
2370 SetPixelGreen(image,GetPixelBlack(image,q),q);
2371 SetPixelBlue(image,GetPixelBlack(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002372 }
cristyed231572011-07-14 02:18:59 +00002373 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002374 (image->matte != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002375 {
cristy4c08aed2011-07-01 19:47:50 +00002376 SetPixelRed(image,GetPixelAlpha(image,q),q);
2377 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2378 SetPixelBlue(image,GetPixelAlpha(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002379 }
cristyed231572011-07-14 02:18:59 +00002380 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002381 }
2382 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2383 status=MagickFalse;
2384 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2385 {
2386 MagickBooleanType
2387 proceed;
2388
cristyb5d5f722009-11-04 03:03:49 +00002389#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3139dc22011-07-08 00:11:42 +00002390 #pragma omp critical (MagickCore_SeparateImage)
cristy3ed852e2009-09-05 21:47:34 +00002391#endif
2392 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2393 if (proceed == MagickFalse)
2394 status=MagickFalse;
2395 }
2396 }
2397 image_view=DestroyCacheView(image_view);
cristy63240882011-08-05 19:05:27 +00002398 (void) SetImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00002399 return(status);
2400}
2401
2402/*
2403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404% %
2405% %
2406% %
2407% S e p a r a t e I m a g e s %
2408% %
2409% %
2410% %
2411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412%
2413% SeparateImages() returns a separate grayscale image for each channel
2414% specified.
2415%
2416% The format of the SeparateImages method is:
2417%
2418% MagickBooleanType SeparateImages(const Image *image,
cristy3139dc22011-07-08 00:11:42 +00002419% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002420%
2421% A description of each parameter follows:
2422%
2423% o image: the image.
2424%
cristy3ed852e2009-09-05 21:47:34 +00002425% o exception: return any errors or warnings in this structure.
2426%
2427*/
cristy3139dc22011-07-08 00:11:42 +00002428MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002429{
2430 Image
2431 *images,
2432 *separate_image;
2433
2434 assert(image != (Image *) NULL);
2435 assert(image->signature == MagickSignature);
2436 if (image->debug != MagickFalse)
2437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2438 images=NewImageList();
cristyed231572011-07-14 02:18:59 +00002439 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002440 {
2441 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002442 PushPixelChannelMap(separate_image,RedChannel);
cristy3139dc22011-07-08 00:11:42 +00002443 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002444 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002445 AppendImageToList(&images,separate_image);
2446 }
cristyed231572011-07-14 02:18:59 +00002447 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002448 {
2449 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002450 PushPixelChannelMap(separate_image,GreenChannel);
cristy3139dc22011-07-08 00:11:42 +00002451 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002452 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002453 AppendImageToList(&images,separate_image);
2454 }
cristyed231572011-07-14 02:18:59 +00002455 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002456 {
2457 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002458 PushPixelChannelMap(separate_image,BlueChannel);
cristy3139dc22011-07-08 00:11:42 +00002459 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002460 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002461 AppendImageToList(&images,separate_image);
2462 }
cristyed231572011-07-14 02:18:59 +00002463 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
cristy3139dc22011-07-08 00:11:42 +00002464 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002465 {
2466 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002467 PushPixelChannelMap(separate_image,BlackChannel);
cristy3139dc22011-07-08 00:11:42 +00002468 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002469 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002470 AppendImageToList(&images,separate_image);
2471 }
cristyed231572011-07-14 02:18:59 +00002472 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002473 {
2474 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristyed231572011-07-14 02:18:59 +00002475 PushPixelChannelMap(separate_image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002476 (void) SeparateImage(separate_image);
cristyed231572011-07-14 02:18:59 +00002477 PopPixelChannelMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002478 AppendImageToList(&images,separate_image);
2479 }
2480 return(images);
2481}
2482
2483/*
2484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485% %
2486% %
2487% %
2488% S e t I m a g e A l p h a C h a n n e l %
2489% %
2490% %
2491% %
2492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493%
2494% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2495% channel.
2496%
2497% The format of the SetImageAlphaChannel method is:
2498%
2499% MagickBooleanType SetImageAlphaChannel(Image *image,
cristy63240882011-08-05 19:05:27 +00002500% const AlphaChannelType alpha_type,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002501%
2502% A description of each parameter follows:
2503%
2504% o image: the image.
2505%
2506% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2507% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
cristy4c08aed2011-07-01 19:47:50 +00002508% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
2509% TransparentAlphaChannel.
cristy3ed852e2009-09-05 21:47:34 +00002510%
cristy63240882011-08-05 19:05:27 +00002511% o exception: return any errors or warnings in this structure.
2512%
cristy3ed852e2009-09-05 21:47:34 +00002513*/
2514MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
cristy63240882011-08-05 19:05:27 +00002515 const AlphaChannelType alpha_type,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002516{
2517 MagickBooleanType
2518 status;
2519
2520 assert(image != (Image *) NULL);
2521 if (image->debug != MagickFalse)
2522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2523 assert(image->signature == MagickSignature);
2524 status=MagickFalse;
2525 switch (alpha_type)
2526 {
2527 case ActivateAlphaChannel:
2528 {
2529 image->matte=MagickTrue;
2530 break;
2531 }
2532 case BackgroundAlphaChannel:
2533 {
2534 CacheView
2535 *image_view;
2536
cristy3ed852e2009-09-05 21:47:34 +00002537 MagickBooleanType
2538 status;
2539
cristy4c08aed2011-07-01 19:47:50 +00002540 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002541 background;
2542
2543 PixelPacket
2544 pixel;
2545
cristycb6d09b2010-06-19 01:59:36 +00002546 ssize_t
2547 y;
2548
cristy3ed852e2009-09-05 21:47:34 +00002549 /*
2550 Set transparent pixels to background color.
2551 */
2552 if (image->matte == MagickFalse)
2553 break;
cristy574cc262011-08-05 01:23:58 +00002554 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002555 break;
cristy4c08aed2011-07-01 19:47:50 +00002556 GetPixelInfo(image,&background);
2557 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002558 if (image->colorspace == CMYKColorspace)
2559 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002560 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002561 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002562 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002563 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2564 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002565 #endif
cristybb503372010-05-27 20:51:26 +00002566 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002567 {
cristy4c08aed2011-07-01 19:47:50 +00002568 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002569 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002570
cristycb6d09b2010-06-19 01:59:36 +00002571 register ssize_t
2572 x;
2573
cristy3ed852e2009-09-05 21:47:34 +00002574 if (status == MagickFalse)
2575 continue;
2576 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2577 exception);
cristy4c08aed2011-07-01 19:47:50 +00002578 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002579 {
2580 status=MagickFalse;
2581 continue;
2582 }
cristybb503372010-05-27 20:51:26 +00002583 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002584 {
cristy4c08aed2011-07-01 19:47:50 +00002585 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002586 {
cristy4c08aed2011-07-01 19:47:50 +00002587 SetPixelRed(image,pixel.red,q);
2588 SetPixelGreen(image,pixel.green,q);
2589 SetPixelBlue(image,pixel.blue,q);
2590 if (image->colorspace == CMYKColorspace)
2591 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002592 }
cristyed231572011-07-14 02:18:59 +00002593 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002594 }
cristy3ed852e2009-09-05 21:47:34 +00002595 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2596 status=MagickFalse;
2597 }
2598 image_view=DestroyCacheView(image_view);
2599 return(status);
2600 }
2601 case DeactivateAlphaChannel:
2602 {
2603 image->matte=MagickFalse;
2604 break;
2605 }
2606 case ShapeAlphaChannel:
2607 case CopyAlphaChannel:
2608 {
2609 /*
cristy3139dc22011-07-08 00:11:42 +00002610 Special usage case for SeparateImage(): copy grayscale color to
cristy3ed852e2009-09-05 21:47:34 +00002611 the alpha channel.
2612 */
cristyed231572011-07-14 02:18:59 +00002613 PushPixelChannelMap(image,GrayChannel);
cristy3139dc22011-07-08 00:11:42 +00002614 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002615 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002616 image->matte=MagickTrue; /* make sure transparency is now on! */
2617 if (alpha_type == ShapeAlphaChannel)
2618 {
cristy4c08aed2011-07-01 19:47:50 +00002619 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002620 background;
2621
2622 /*
2623 Reset all color channels to background color.
2624 */
cristy4c08aed2011-07-01 19:47:50 +00002625 GetPixelInfo(image,&background);
2626 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002627 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002628 }
2629 break;
2630 }
2631 case ExtractAlphaChannel:
2632 {
cristyed231572011-07-14 02:18:59 +00002633 PushPixelChannelMap(image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002634 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002635 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002636 image->matte=MagickFalse;
2637 break;
2638 }
cristy3ed852e2009-09-05 21:47:34 +00002639 case OpaqueAlphaChannel:
2640 {
cristy4c08aed2011-07-01 19:47:50 +00002641 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002642 image->matte=MagickTrue;
2643 break;
2644 }
2645 case TransparentAlphaChannel:
2646 {
cristy4c08aed2011-07-01 19:47:50 +00002647 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002648 image->matte=MagickTrue;
2649 break;
2650 }
2651 case SetAlphaChannel:
2652 {
2653 if (image->matte == MagickFalse)
2654 {
cristy4c08aed2011-07-01 19:47:50 +00002655 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002656 image->matte=MagickTrue;
2657 }
2658 break;
2659 }
2660 case UndefinedAlphaChannel:
2661 break;
2662 }
cristycd01fae2011-08-06 23:52:42 +00002663 return(status);
cristy3ed852e2009-09-05 21:47:34 +00002664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
2671% S e t I m a g e B a c k g r o u n d C o l o r %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% SetImageBackgroundColor() initializes the image pixels to the image
2678% background color. The background color is defined by the background_color
2679% member of the image structure.
2680%
2681% The format of the SetImage method is:
2682%
2683% MagickBooleanType SetImageBackgroundColor(Image *image)
2684%
2685% A description of each parameter follows:
2686%
2687% o image: the image.
2688%
2689*/
2690MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2691{
2692 CacheView
2693 *image_view;
2694
2695 ExceptionInfo
2696 *exception;
2697
cristy3ed852e2009-09-05 21:47:34 +00002698 MagickBooleanType
2699 status;
2700
cristy4c08aed2011-07-01 19:47:50 +00002701 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002702 background;
2703
2704 PixelPacket
2705 pixel;
2706
cristycb6d09b2010-06-19 01:59:36 +00002707 ssize_t
2708 y;
2709
cristy3ed852e2009-09-05 21:47:34 +00002710 assert(image != (Image *) NULL);
2711 if (image->debug != MagickFalse)
2712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2713 assert(image->signature == MagickSignature);
cristy574cc262011-08-05 01:23:58 +00002714 exception=(&image->exception);
2715 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002716 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002717 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002718 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002719 GetPixelInfo(image,&background);
2720 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002721 if (image->colorspace == CMYKColorspace)
2722 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002723 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002724 /*
2725 Set image background color.
2726 */
2727 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002728 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002729 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002730 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002731 {
cristy4c08aed2011-07-01 19:47:50 +00002732 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002733 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002734
cristycb6d09b2010-06-19 01:59:36 +00002735 register ssize_t
2736 x;
2737
cristy3ed852e2009-09-05 21:47:34 +00002738 if (status == MagickFalse)
2739 continue;
2740 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002741 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002742 {
2743 status=MagickFalse;
2744 continue;
2745 }
cristybb503372010-05-27 20:51:26 +00002746 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002747 {
2748 SetPixelPacket(image,&pixel,q);
2749 if (image->colorspace == CMYKColorspace)
2750 SetPixelBlack(image,pixel.black,q);
cristyed231572011-07-14 02:18:59 +00002751 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002752 }
cristy3ed852e2009-09-05 21:47:34 +00002753 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2754 status=MagickFalse;
2755 }
2756 image_view=DestroyCacheView(image_view);
2757 return(status);
2758}
2759
2760/*
2761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762% %
2763% %
2764% %
cristya5b77cb2010-05-07 19:34:48 +00002765% S e t I m a g e C o l o r %
2766% %
2767% %
2768% %
2769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2770%
2771% SetImageColor() set the entire image canvas to the specified color.
2772%
2773% The format of the SetImageColor method is:
2774%
cristy08429172011-07-14 17:18:16 +00002775% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002776%
2777% A description of each parameter follows:
2778%
2779% o image: the image.
2780%
2781% o background: the image color.
2782%
2783*/
2784MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002785 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002786{
2787 CacheView
2788 *image_view;
2789
2790 ExceptionInfo
2791 *exception;
2792
cristya5b77cb2010-05-07 19:34:48 +00002793 MagickBooleanType
2794 status;
2795
cristycb6d09b2010-06-19 01:59:36 +00002796 ssize_t
2797 y;
2798
cristya5b77cb2010-05-07 19:34:48 +00002799 assert(image != (Image *) NULL);
2800 if (image->debug != MagickFalse)
2801 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2802 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002803 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002804 image->colorspace=color->colorspace;
2805 image->matte=color->matte;
2806 image->fuzz=color->fuzz;
2807 image->depth=color->depth;
2808 status=MagickTrue;
2809 exception=(&image->exception);
2810 image_view=AcquireCacheView(image);
2811#if defined(MAGICKCORE_OPENMP_SUPPORT)
2812 #pragma omp parallel for schedule(dynamic,4) shared(status)
2813#endif
cristybb503372010-05-27 20:51:26 +00002814 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002815 {
cristy4c08aed2011-07-01 19:47:50 +00002816 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002817 *restrict q;
2818
cristycb6d09b2010-06-19 01:59:36 +00002819 register ssize_t
2820 x;
2821
cristya5b77cb2010-05-07 19:34:48 +00002822 if (status == MagickFalse)
2823 continue;
2824 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002825 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002826 {
2827 status=MagickFalse;
2828 continue;
2829 }
cristybb503372010-05-27 20:51:26 +00002830 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002831 {
cristy4c08aed2011-07-01 19:47:50 +00002832 SetPixelPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002833 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002834 }
2835 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2836 status=MagickFalse;
2837 }
2838 image_view=DestroyCacheView(image_view);
2839 return(status);
2840}
2841
2842/*
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844% %
2845% %
2846% %
cristy3ed852e2009-09-05 21:47:34 +00002847% S e t I m a g e S t o r a g e C l a s s %
2848% %
2849% %
2850% %
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852%
2853% SetImageStorageClass() sets the image class: DirectClass for true color
2854% images or PseudoClass for colormapped images.
2855%
2856% The format of the SetImageStorageClass method is:
2857%
2858% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002859% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002860%
2861% A description of each parameter follows:
2862%
2863% o image: the image.
2864%
2865% o storage_class: The image class.
2866%
cristy574cc262011-08-05 01:23:58 +00002867% o exception: return any errors or warnings in this structure.
2868%
cristy3ed852e2009-09-05 21:47:34 +00002869*/
2870MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002871 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002872{
cristy3ed852e2009-09-05 21:47:34 +00002873 image->storage_class=storage_class;
cristycd01fae2011-08-06 23:52:42 +00002874 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002875}
2876
2877/*
2878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2879% %
2880% %
2881% %
2882% S e t I m a g e C l i p M a s k %
2883% %
2884% %
2885% %
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887%
2888% SetImageClipMask() associates a clip path with the image. The clip path
2889% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002890% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002891% pixel component from being updated when SyncAuthenticPixels() is applied.
2892%
2893% The format of the SetImageClipMask method is:
2894%
2895% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o clip_mask: the image clip path.
2902%
2903*/
2904MagickExport MagickBooleanType SetImageClipMask(Image *image,
2905 const Image *clip_mask)
2906{
2907 assert(image != (Image *) NULL);
2908 if (image->debug != MagickFalse)
2909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2910 assert(image->signature == MagickSignature);
2911 if (clip_mask != (const Image *) NULL)
2912 if ((clip_mask->columns != image->columns) ||
2913 (clip_mask->rows != image->rows))
2914 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2915 if (image->clip_mask != (Image *) NULL)
2916 image->clip_mask=DestroyImage(image->clip_mask);
2917 image->clip_mask=NewImageList();
2918 if (clip_mask == (Image *) NULL)
2919 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00002920 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002921 return(MagickFalse);
2922 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2923 if (image->clip_mask == (Image *) NULL)
2924 return(MagickFalse);
2925 return(MagickTrue);
2926}
2927
2928/*
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930% %
2931% %
2932% %
2933% S e t I m a g e E x t e n t %
2934% %
2935% %
2936% %
2937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938%
2939% SetImageExtent() sets the image size (i.e. columns & rows).
2940%
2941% The format of the SetImageExtent method is:
2942%
cristy08429172011-07-14 17:18:16 +00002943% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002944% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002945%
2946% A description of each parameter follows:
2947%
2948% o image: the image.
2949%
2950% o columns: The image width in pixels.
2951%
2952% o rows: The image height in pixels.
2953%
cristy63240882011-08-05 19:05:27 +00002954% o exception: return any errors or warnings in this structure.
2955%
cristy3ed852e2009-09-05 21:47:34 +00002956*/
cristy08429172011-07-14 17:18:16 +00002957MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002958 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002959{
cristy537e2722010-09-21 15:30:59 +00002960 if ((columns == 0) || (rows == 0))
2961 return(MagickFalse);
2962 image->columns=columns;
2963 image->rows=rows;
cristycd01fae2011-08-06 23:52:42 +00002964 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002965}
2966
2967/*
2968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2969% %
2970% %
2971% %
2972+ S e t I m a g e I n f o %
2973% %
2974% %
2975% %
2976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977%
2978% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
2979% It is set to a type of image format based on the prefix or suffix of the
2980% filename. For example, `ps:image' returns PS indicating a Postscript image.
2981% JPEG is returned for this filename: `image.jpg'. The filename prefix has
2982% precendence over the suffix. Use an optional index enclosed in brackets
2983% after a file name to specify a desired scene of a multi-resolution image
2984% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2985% indicates success.
2986%
2987% The format of the SetImageInfo method is:
2988%
2989% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002990% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002991%
2992% A description of each parameter follows:
2993%
cristyd965a422010-03-03 17:47:35 +00002994% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002995%
cristyd965a422010-03-03 17:47:35 +00002996% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002997%
2998% o exception: return any errors or warnings in this structure.
2999%
3000*/
3001MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003002 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003003{
3004 char
3005 extension[MaxTextExtent],
3006 filename[MaxTextExtent],
3007 magic[MaxTextExtent],
3008 *q,
3009 subimage[MaxTextExtent];
3010
3011 const MagicInfo
3012 *magic_info;
3013
3014 const MagickInfo
3015 *magick_info;
3016
3017 ExceptionInfo
3018 *sans_exception;
3019
3020 Image
3021 *image;
3022
3023 MagickBooleanType
3024 status;
3025
3026 register const char
3027 *p;
3028
3029 ssize_t
3030 count;
3031
3032 unsigned char
3033 magick[2*MaxTextExtent];
3034
3035 /*
3036 Look for 'image.format' in filename.
3037 */
3038 assert(image_info != (ImageInfo *) NULL);
3039 assert(image_info->signature == MagickSignature);
3040 if (image_info->debug != MagickFalse)
3041 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3042 image_info->filename);
3043 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003044 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003045 {
cristyd965a422010-03-03 17:47:35 +00003046 GetPathComponent(image_info->filename,SubimagePath,subimage);
3047 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003048 {
cristyd965a422010-03-03 17:47:35 +00003049 /*
3050 Look for scene specification (e.g. img0001.pcd[4]).
3051 */
3052 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3053 {
3054 if (IsGeometry(subimage) != MagickFalse)
3055 (void) CloneString(&image_info->extract,subimage);
3056 }
3057 else
3058 {
cristybb503372010-05-27 20:51:26 +00003059 size_t
cristyd965a422010-03-03 17:47:35 +00003060 first,
3061 last;
cristy3ed852e2009-09-05 21:47:34 +00003062
cristyd965a422010-03-03 17:47:35 +00003063 (void) CloneString(&image_info->scenes,subimage);
3064 image_info->scene=StringToUnsignedLong(image_info->scenes);
3065 image_info->number_scenes=image_info->scene;
3066 p=image_info->scenes;
3067 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3068 {
3069 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3070 (*p == ','))
3071 p++;
cristybb503372010-05-27 20:51:26 +00003072 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003073 last=first;
3074 while (isspace((int) ((unsigned char) *q)) != 0)
3075 q++;
3076 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003077 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003078 if (first > last)
3079 Swap(first,last);
3080 if (first < image_info->scene)
3081 image_info->scene=first;
3082 if (last > image_info->number_scenes)
3083 image_info->number_scenes=last;
3084 p=q;
3085 }
3086 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003087 }
cristy3ed852e2009-09-05 21:47:34 +00003088 }
3089 }
3090 *extension='\0';
3091 GetPathComponent(image_info->filename,ExtensionPath,extension);
3092#if defined(MAGICKCORE_ZLIB_DELEGATE)
3093 if (*extension != '\0')
3094 if ((LocaleCompare(extension,"gz") == 0) ||
3095 (LocaleCompare(extension,"Z") == 0) ||
3096 (LocaleCompare(extension,"wmz") == 0))
3097 {
3098 char
3099 path[MaxTextExtent];
3100
3101 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3102 path[strlen(path)-strlen(extension)-1]='\0';
3103 GetPathComponent(path,ExtensionPath,extension);
3104 }
3105#endif
3106#if defined(MAGICKCORE_BZLIB_DELEGATE)
3107 if (*extension != '\0')
3108 if (LocaleCompare(extension,"bz2") == 0)
3109 {
3110 char
3111 path[MaxTextExtent];
3112
3113 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3114 path[strlen(path)-strlen(extension)-1]='\0';
3115 GetPathComponent(path,ExtensionPath,extension);
3116 }
3117#endif
3118 image_info->affirm=MagickFalse;
3119 sans_exception=AcquireExceptionInfo();
3120 if (*extension != '\0')
3121 {
3122 MagickFormatType
3123 format_type;
3124
cristybb503372010-05-27 20:51:26 +00003125 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003126 i;
3127
3128 static const char
3129 *format_type_formats[] =
3130 {
3131 "AUTOTRACE",
3132 "BROWSE",
3133 "DCRAW",
3134 "EDIT",
3135 "EPHEMERAL",
3136 "LAUNCH",
3137 "MPEG:DECODE",
3138 "MPEG:ENCODE",
3139 "PRINT",
3140 "PS:ALPHA",
3141 "PS:CMYK",
3142 "PS:COLOR",
3143 "PS:GRAY",
3144 "PS:MONO",
3145 "SCAN",
3146 "SHOW",
3147 "WIN",
3148 (char *) NULL
3149 };
3150
3151 /*
3152 User specified image format.
3153 */
3154 (void) CopyMagickString(magic,extension,MaxTextExtent);
3155 LocaleUpper(magic);
3156 /*
3157 Look for explicit image formats.
3158 */
3159 format_type=UndefinedFormatType;
3160 i=0;
cristydd9a2532010-02-20 19:26:46 +00003161 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003162 (format_type_formats[i] != (char *) NULL))
3163 {
3164 if ((*magic == *format_type_formats[i]) &&
3165 (LocaleCompare(magic,format_type_formats[i]) == 0))
3166 format_type=ExplicitFormatType;
3167 i++;
3168 }
3169 magick_info=GetMagickInfo(magic,sans_exception);
3170 if ((magick_info != (const MagickInfo *) NULL) &&
3171 (magick_info->format_type != UndefinedFormatType))
3172 format_type=magick_info->format_type;
3173 if (format_type == UndefinedFormatType)
3174 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3175 else
3176 if (format_type == ExplicitFormatType)
3177 {
3178 image_info->affirm=MagickTrue;
3179 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3180 }
3181 if (LocaleCompare(magic,"RGB") == 0)
3182 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3183 }
3184 /*
3185 Look for explicit 'format:image' in filename.
3186 */
3187 *magic='\0';
3188 GetPathComponent(image_info->filename,MagickPath,magic);
3189 if (*magic == '\0')
3190 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3191 else
3192 {
3193 /*
3194 User specified image format.
3195 */
3196 LocaleUpper(magic);
3197 if (IsMagickConflict(magic) == MagickFalse)
3198 {
3199 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3200 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3201 image_info->affirm=MagickTrue;
3202 else
3203 image_info->temporary=MagickTrue;
3204 }
3205 }
3206 magick_info=GetMagickInfo(magic,sans_exception);
3207 sans_exception=DestroyExceptionInfo(sans_exception);
3208 if ((magick_info == (const MagickInfo *) NULL) ||
3209 (GetMagickEndianSupport(magick_info) == MagickFalse))
3210 image_info->endian=UndefinedEndian;
3211 GetPathComponent(image_info->filename,CanonicalPath,filename);
3212 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003213 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003214 {
3215 /*
cristyd965a422010-03-03 17:47:35 +00003216 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003217 */
cristyd965a422010-03-03 17:47:35 +00003218 (void) InterpretImageFilename(image_info,(Image *) NULL,
3219 image_info->filename,(int) image_info->scene,filename);
3220 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3221 (strchr(filename,'%') == (char *) NULL))
3222 image_info->adjoin=MagickFalse;
3223 }
3224 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3225 {
3226 /*
3227 Some image formats do not support multiple frames per file.
3228 */
cristy3ed852e2009-09-05 21:47:34 +00003229 magick_info=GetMagickInfo(magic,exception);
3230 if (magick_info != (const MagickInfo *) NULL)
3231 if (GetMagickAdjoin(magick_info) == MagickFalse)
3232 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003233 }
3234 if (image_info->affirm != MagickFalse)
3235 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003236 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003237 {
3238 /*
cristyd965a422010-03-03 17:47:35 +00003239 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003240 */
cristyd965a422010-03-03 17:47:35 +00003241 image=AcquireImage(image_info);
3242 (void) CopyMagickString(image->filename,image_info->filename,
3243 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003244 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3245 if (status == MagickFalse)
3246 {
3247 image=DestroyImage(image);
3248 return(MagickFalse);
3249 }
cristyd965a422010-03-03 17:47:35 +00003250 if ((IsBlobSeekable(image) == MagickFalse) ||
3251 (IsBlobExempt(image) != MagickFalse))
3252 {
3253 /*
3254 Copy standard input or pipe to temporary file.
3255 */
3256 *filename='\0';
3257 status=ImageToFile(image,filename,exception);
3258 (void) CloseBlob(image);
3259 if (status == MagickFalse)
3260 {
3261 image=DestroyImage(image);
3262 return(MagickFalse);
3263 }
3264 SetImageInfoFile(image_info,(FILE *) NULL);
3265 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3266 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3267 if (status == MagickFalse)
3268 {
3269 image=DestroyImage(image);
3270 return(MagickFalse);
3271 }
3272 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3273 image_info->temporary=MagickTrue;
3274 }
3275 (void) ResetMagickMemory(magick,0,sizeof(magick));
3276 count=ReadBlob(image,2*MaxTextExtent,magick);
3277 (void) CloseBlob(image);
3278 image=DestroyImage(image);
3279 /*
3280 Check magic.xml configuration file.
3281 */
3282 sans_exception=AcquireExceptionInfo();
3283 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3284 if ((magic_info != (const MagicInfo *) NULL) &&
3285 (GetMagicName(magic_info) != (char *) NULL))
3286 {
3287 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3288 MaxTextExtent);
3289 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3290 if ((magick_info == (const MagickInfo *) NULL) ||
3291 (GetMagickEndianSupport(magick_info) == MagickFalse))
3292 image_info->endian=UndefinedEndian;
3293 sans_exception=DestroyExceptionInfo(sans_exception);
3294 return(MagickTrue);
3295 }
cristy3ed852e2009-09-05 21:47:34 +00003296 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3297 if ((magick_info == (const MagickInfo *) NULL) ||
3298 (GetMagickEndianSupport(magick_info) == MagickFalse))
3299 image_info->endian=UndefinedEndian;
3300 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003301 }
cristy3ed852e2009-09-05 21:47:34 +00003302 return(MagickTrue);
3303}
3304
3305/*
3306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3307% %
3308% %
3309% %
3310% S e t I m a g e I n f o B l o b %
3311% %
3312% %
3313% %
3314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3315%
3316% SetImageInfoBlob() sets the image info blob member.
3317%
3318% The format of the SetImageInfoBlob method is:
3319%
3320% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3321% const size_t length)
3322%
3323% A description of each parameter follows:
3324%
3325% o image_info: the image info.
3326%
3327% o blob: the blob.
3328%
3329% o length: the blob length.
3330%
3331*/
3332MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3333 const size_t length)
3334{
3335 assert(image_info != (ImageInfo *) NULL);
3336 assert(image_info->signature == MagickSignature);
3337 if (image_info->debug != MagickFalse)
3338 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3339 image_info->filename);
3340 image_info->blob=(void *) blob;
3341 image_info->length=length;
3342}
3343
3344/*
3345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3346% %
3347% %
3348% %
3349% S e t I m a g e I n f o F i l e %
3350% %
3351% %
3352% %
3353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3354%
3355% SetImageInfoFile() sets the image info file member.
3356%
3357% The format of the SetImageInfoFile method is:
3358%
3359% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3360%
3361% A description of each parameter follows:
3362%
3363% o image_info: the image info.
3364%
3365% o file: the file.
3366%
3367*/
3368MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3369{
3370 assert(image_info != (ImageInfo *) NULL);
3371 assert(image_info->signature == MagickSignature);
3372 if (image_info->debug != MagickFalse)
3373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3374 image_info->filename);
3375 image_info->file=file;
3376}
3377
3378/*
3379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3380% %
3381% %
3382% %
3383% S e t I m a g e M a s k %
3384% %
3385% %
3386% %
3387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388%
3389% SetImageMask() associates a mask with the image. The mask must be the same
3390% dimensions as the image.
3391%
3392% The format of the SetImageMask method is:
3393%
3394% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3395%
3396% A description of each parameter follows:
3397%
3398% o image: the image.
3399%
3400% o mask: the image mask.
3401%
3402*/
3403MagickExport MagickBooleanType SetImageMask(Image *image,
3404 const Image *mask)
3405{
3406 assert(image != (Image *) NULL);
3407 if (image->debug != MagickFalse)
3408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3409 assert(image->signature == MagickSignature);
3410 if (mask != (const Image *) NULL)
3411 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3412 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3413 if (image->mask != (Image *) NULL)
3414 image->mask=DestroyImage(image->mask);
3415 image->mask=NewImageList();
3416 if (mask == (Image *) NULL)
3417 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00003418 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003419 return(MagickFalse);
3420 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3421 if (image->mask == (Image *) NULL)
3422 return(MagickFalse);
3423 return(MagickTrue);
3424}
3425
3426/*
3427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3428% %
3429% %
3430% %
3431% S e t I m a g e O p a c i t y %
3432% %
3433% %
3434% %
3435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3436%
3437% SetImageOpacity() sets the opacity levels of the image.
3438%
3439% The format of the SetImageOpacity method is:
3440%
3441% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3442%
3443% A description of each parameter follows:
3444%
3445% o image: the image.
3446%
3447% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3448% fully transparent.
3449%
3450*/
3451MagickExport MagickBooleanType SetImageOpacity(Image *image,
3452 const Quantum opacity)
3453{
3454 CacheView
3455 *image_view;
3456
3457 ExceptionInfo
3458 *exception;
3459
cristy3ed852e2009-09-05 21:47:34 +00003460 MagickBooleanType
3461 status;
3462
cristycb6d09b2010-06-19 01:59:36 +00003463 ssize_t
3464 y;
3465
cristy3ed852e2009-09-05 21:47:34 +00003466 assert(image != (Image *) NULL);
3467 if (image->debug != MagickFalse)
3468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3469 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003470 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003471 status=MagickTrue;
3472 exception=(&image->exception);
3473 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003474#if defined(MAGICKCORE_OPENMP_SUPPORT)
3475 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003476#endif
cristybb503372010-05-27 20:51:26 +00003477 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003478 {
cristy4c08aed2011-07-01 19:47:50 +00003479 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003480 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003481
cristycb6d09b2010-06-19 01:59:36 +00003482 register ssize_t
3483 x;
3484
cristy3ed852e2009-09-05 21:47:34 +00003485 if (status == MagickFalse)
3486 continue;
3487 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003488 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003489 {
3490 status=MagickFalse;
3491 continue;
3492 }
cristybb503372010-05-27 20:51:26 +00003493 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003494 {
cristy4c08aed2011-07-01 19:47:50 +00003495 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00003496 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003497 }
3498 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3499 status=MagickFalse;
3500 }
3501 image_view=DestroyCacheView(image_view);
3502 return(status);
3503}
3504
3505/*
3506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507% %
3508% %
3509% %
3510% S e t I m a g e T y p e %
3511% %
3512% %
3513% %
3514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3515%
3516% SetImageType() sets the type of image. Choose from these types:
3517%
3518% Bilevel Grayscale GrayscaleMatte
3519% Palette PaletteMatte TrueColor
3520% TrueColorMatte ColorSeparation ColorSeparationMatte
3521% OptimizeType
3522%
3523% The format of the SetImageType method is:
3524%
3525% MagickBooleanType SetImageType(Image *image,const ImageType type)
3526%
3527% A description of each parameter follows:
3528%
3529% o image: the image.
3530%
3531% o type: Image type.
3532%
3533*/
3534MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3535{
3536 const char
3537 *artifact;
3538
cristy63240882011-08-05 19:05:27 +00003539 ExceptionInfo
3540 *exception;
3541
cristy3ed852e2009-09-05 21:47:34 +00003542 ImageInfo
3543 *image_info;
3544
3545 MagickBooleanType
3546 status;
3547
3548 QuantizeInfo
3549 *quantize_info;
3550
3551 assert(image != (Image *) NULL);
3552 if (image->debug != MagickFalse)
3553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3554 assert(image->signature == MagickSignature);
3555 status=MagickTrue;
3556 image_info=AcquireImageInfo();
3557 image_info->dither=image->dither;
3558 artifact=GetImageArtifact(image,"dither");
3559 if (artifact != (const char *) NULL)
3560 (void) SetImageOption(image_info,"dither",artifact);
cristy63240882011-08-05 19:05:27 +00003561 exception=(&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003562 switch (type)
3563 {
3564 case BilevelType:
3565 {
cristy4c08aed2011-07-01 19:47:50 +00003566 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003567 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003568 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003569 {
3570 quantize_info=AcquireQuantizeInfo(image_info);
3571 quantize_info->number_colors=2;
3572 quantize_info->colorspace=GRAYColorspace;
3573 status=QuantizeImage(quantize_info,image);
3574 quantize_info=DestroyQuantizeInfo(quantize_info);
3575 }
3576 image->matte=MagickFalse;
3577 break;
3578 }
3579 case GrayscaleType:
3580 {
cristy4c08aed2011-07-01 19:47:50 +00003581 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003582 status=TransformImageColorspace(image,GRAYColorspace);
3583 image->matte=MagickFalse;
3584 break;
3585 }
3586 case GrayscaleMatteType:
3587 {
cristy4c08aed2011-07-01 19:47:50 +00003588 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003589 status=TransformImageColorspace(image,GRAYColorspace);
3590 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003591 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003592 break;
3593 }
3594 case PaletteType:
3595 {
cristy510d06a2011-07-06 23:43:54 +00003596 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003597 status=TransformImageColorspace(image,RGBColorspace);
3598 if ((image->storage_class == DirectClass) || (image->colors > 256))
3599 {
3600 quantize_info=AcquireQuantizeInfo(image_info);
3601 quantize_info->number_colors=256;
3602 status=QuantizeImage(quantize_info,image);
3603 quantize_info=DestroyQuantizeInfo(quantize_info);
3604 }
3605 image->matte=MagickFalse;
3606 break;
3607 }
3608 case PaletteBilevelMatteType:
3609 {
cristy510d06a2011-07-06 23:43:54 +00003610 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003611 status=TransformImageColorspace(image,RGBColorspace);
3612 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003613 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristyed231572011-07-14 02:18:59 +00003614 PushPixelChannelMap(image,AlphaChannel);
cristyf4ad9df2011-07-08 16:49:03 +00003615 (void) BilevelImage(image,(double) QuantumRange/2.0);
cristyed231572011-07-14 02:18:59 +00003616 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00003617 quantize_info=AcquireQuantizeInfo(image_info);
3618 status=QuantizeImage(quantize_info,image);
3619 quantize_info=DestroyQuantizeInfo(quantize_info);
3620 break;
3621 }
3622 case PaletteMatteType:
3623 {
cristy510d06a2011-07-06 23:43:54 +00003624 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003625 status=TransformImageColorspace(image,RGBColorspace);
3626 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003627 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003628 quantize_info=AcquireQuantizeInfo(image_info);
3629 quantize_info->colorspace=TransparentColorspace;
3630 status=QuantizeImage(quantize_info,image);
3631 quantize_info=DestroyQuantizeInfo(quantize_info);
3632 break;
3633 }
3634 case TrueColorType:
3635 {
cristy510d06a2011-07-06 23:43:54 +00003636 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003637 status=TransformImageColorspace(image,RGBColorspace);
3638 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003639 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003640 image->matte=MagickFalse;
3641 break;
3642 }
3643 case TrueColorMatteType:
3644 {
cristy510d06a2011-07-06 23:43:54 +00003645 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003646 status=TransformImageColorspace(image,RGBColorspace);
3647 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003648 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003649 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003650 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003651 break;
3652 }
3653 case ColorSeparationType:
3654 {
3655 if (image->colorspace != CMYKColorspace)
3656 {
cristy510d06a2011-07-06 23:43:54 +00003657 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003658 status=TransformImageColorspace(image,RGBColorspace);
3659 status=TransformImageColorspace(image,CMYKColorspace);
3660 }
3661 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003662 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003663 image->matte=MagickFalse;
3664 break;
3665 }
3666 case ColorSeparationMatteType:
3667 {
3668 if (image->colorspace != CMYKColorspace)
3669 {
cristy510d06a2011-07-06 23:43:54 +00003670 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003671 status=TransformImageColorspace(image,RGBColorspace);
3672 status=TransformImageColorspace(image,CMYKColorspace);
3673 }
3674 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003675 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003676 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003677 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003678 break;
3679 }
3680 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003681 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003682 break;
3683 }
3684 image->type=type;
3685 image_info=DestroyImageInfo(image_info);
3686 return(status);
3687}
3688
3689/*
3690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3691% %
3692% %
3693% %
3694% 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 %
3695% %
3696% %
3697% %
3698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3699%
3700% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3701% image and returns the previous setting. A virtual pixel is any pixel access
3702% that is outside the boundaries of the image cache.
3703%
3704% The format of the SetImageVirtualPixelMethod() method is:
3705%
3706% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3707% const VirtualPixelMethod virtual_pixel_method)
3708%
3709% A description of each parameter follows:
3710%
3711% o image: the image.
3712%
3713% o virtual_pixel_method: choose the type of virtual pixel.
3714%
3715*/
3716MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3717 const VirtualPixelMethod virtual_pixel_method)
3718{
3719 assert(image != (const Image *) NULL);
3720 assert(image->signature == MagickSignature);
3721 if (image->debug != MagickFalse)
3722 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3723 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3724}
3725
3726/*
3727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3728% %
3729% %
3730% %
cristy4285d782011-02-09 20:12:28 +00003731% S m u s h I m a g e s %
3732% %
3733% %
3734% %
3735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736%
3737% SmushImages() takes all images from the current image pointer to the end
3738% of the image list and smushes them to each other top-to-bottom if the
3739% stack parameter is true, otherwise left-to-right.
3740%
3741% The current gravity setting now effects how the image is justified in the
3742% final image.
3743%
3744% The format of the SmushImages method is:
3745%
cristy4ca38e22011-02-10 02:57:49 +00003746% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003747% ExceptionInfo *exception)
3748%
3749% A description of each parameter follows:
3750%
cristy4ca38e22011-02-10 02:57:49 +00003751% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003752%
3753% o stack: A value other than 0 stacks the images top-to-bottom.
3754%
3755% o offset: minimum distance in pixels between images.
3756%
3757% o exception: return any errors or warnings in this structure.
3758%
3759*/
cristy4ca38e22011-02-10 02:57:49 +00003760
cristy7c6dc152011-02-11 14:10:55 +00003761static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003762 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003763{
cristy4d727152011-02-10 19:57:21 +00003764 CacheView
3765 *left_view,
3766 *right_view;
3767
3768 const Image
3769 *left_image,
3770 *right_image;
3771
cristy4d727152011-02-10 19:57:21 +00003772 RectangleInfo
3773 left_geometry,
3774 right_geometry;
3775
cristy4c08aed2011-07-01 19:47:50 +00003776 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003777 *p;
3778
cristy4d727152011-02-10 19:57:21 +00003779 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003780 i,
cristy4d727152011-02-10 19:57:21 +00003781 y;
3782
cristy7c6dc152011-02-11 14:10:55 +00003783 size_t
3784 gap;
3785
cristy4d727152011-02-10 19:57:21 +00003786 ssize_t
cristy4d727152011-02-10 19:57:21 +00003787 x;
3788
3789 if (images->previous == (Image *) NULL)
3790 return(0);
3791 right_image=images;
3792 SetGeometry(smush_image,&right_geometry);
3793 GravityAdjustGeometry(right_image->columns,right_image->rows,
3794 right_image->gravity,&right_geometry);
3795 left_image=images->previous;
3796 SetGeometry(smush_image,&left_geometry);
3797 GravityAdjustGeometry(left_image->columns,left_image->rows,
3798 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003799 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003800 left_view=AcquireCacheView(left_image);
3801 right_view=AcquireCacheView(right_image);
3802 for (y=0; y < (ssize_t) smush_image->rows; y++)
3803 {
3804 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3805 {
cristydab7e912011-02-11 18:19:24 +00003806 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003807 if ((p == (const Quantum *) NULL) ||
3808 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003809 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003810 break;
3811 }
cristy4ef6f062011-02-10 20:30:22 +00003812 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003813 for (x=0; x < (ssize_t) right_image->columns; x++)
3814 {
cristydab7e912011-02-11 18:19:24 +00003815 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003816 exception);
cristy4c08aed2011-07-01 19:47:50 +00003817 if ((p == (const Quantum *) NULL) ||
3818 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3819 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003820 break;
3821 }
cristy7c6dc152011-02-11 14:10:55 +00003822 if ((x+i) < (ssize_t) gap)
3823 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003824 }
3825 right_view=DestroyCacheView(right_view);
3826 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003827 if (y < (ssize_t) smush_image->rows)
3828 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003829 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003830}
3831
cristy7c6dc152011-02-11 14:10:55 +00003832static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003833 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003834{
cristy4d727152011-02-10 19:57:21 +00003835 CacheView
3836 *bottom_view,
3837 *top_view;
3838
3839 const Image
3840 *bottom_image,
3841 *top_image;
3842
cristy4d727152011-02-10 19:57:21 +00003843 RectangleInfo
3844 bottom_geometry,
3845 top_geometry;
3846
cristy4c08aed2011-07-01 19:47:50 +00003847 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003848 *p;
3849
cristy4d727152011-02-10 19:57:21 +00003850 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003851 i,
cristy4d727152011-02-10 19:57:21 +00003852 x;
3853
cristy7c6dc152011-02-11 14:10:55 +00003854 size_t
3855 gap;
3856
cristy4d727152011-02-10 19:57:21 +00003857 ssize_t
cristy4d727152011-02-10 19:57:21 +00003858 y;
3859
3860 if (images->previous == (Image *) NULL)
3861 return(0);
3862 bottom_image=images;
3863 SetGeometry(smush_image,&bottom_geometry);
3864 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3865 bottom_image->gravity,&bottom_geometry);
3866 top_image=images->previous;
3867 SetGeometry(smush_image,&top_geometry);
3868 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3869 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003870 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003871 top_view=AcquireCacheView(top_image);
3872 bottom_view=AcquireCacheView(bottom_image);
3873 for (x=0; x < (ssize_t) smush_image->columns; x++)
3874 {
3875 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3876 {
cristydab7e912011-02-11 18:19:24 +00003877 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003878 if ((p == (const Quantum *) NULL) ||
3879 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3880 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003881 break;
3882 }
cristy4ef6f062011-02-10 20:30:22 +00003883 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003884 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3885 {
cristydab7e912011-02-11 18:19:24 +00003886 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3887 exception);
cristy4c08aed2011-07-01 19:47:50 +00003888 if ((p == (const Quantum *) NULL) ||
3889 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3890 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003891 break;
3892 }
cristy7c6dc152011-02-11 14:10:55 +00003893 if ((y+i) < (ssize_t) gap)
3894 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003895 }
3896 bottom_view=DestroyCacheView(bottom_view);
3897 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003898 if (x < (ssize_t) smush_image->columns)
3899 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003900 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003901}
3902
3903MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003904 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3905{
3906#define SmushImageTag "Smush/Image"
3907
3908 CacheView
cristybb5dced2011-02-10 02:17:16 +00003909 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003910
cristy4ca38e22011-02-10 02:57:49 +00003911 const Image
3912 *image;
3913
cristy4285d782011-02-09 20:12:28 +00003914 Image
3915 *smush_image;
3916
3917 MagickBooleanType
3918 matte,
3919 proceed,
3920 status;
3921
3922 MagickOffsetType
3923 n;
3924
3925 RectangleInfo
3926 geometry;
3927
3928 register const Image
3929 *next;
3930
3931 size_t
3932 height,
3933 number_images,
3934 width;
3935
3936 ssize_t
3937 x_offset,
cristy4285d782011-02-09 20:12:28 +00003938 y_offset;
3939
3940 /*
cristy7c6dc152011-02-11 14:10:55 +00003941 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003942 */
cristy4ca38e22011-02-10 02:57:49 +00003943 assert(images != (Image *) NULL);
3944 assert(images->signature == MagickSignature);
3945 if (images->debug != MagickFalse)
3946 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003947 assert(exception != (ExceptionInfo *) NULL);
3948 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003949 image=images;
cristy4285d782011-02-09 20:12:28 +00003950 matte=image->matte;
3951 number_images=1;
3952 width=image->columns;
3953 height=image->rows;
3954 next=GetNextImageInList(image);
3955 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3956 {
3957 if (next->matte != MagickFalse)
3958 matte=MagickTrue;
3959 number_images++;
3960 if (stack != MagickFalse)
3961 {
3962 if (next->columns > width)
3963 width=next->columns;
3964 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003965 if (next->previous != (Image *) NULL)
3966 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003967 continue;
3968 }
3969 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003970 if (next->previous != (Image *) NULL)
3971 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003972 if (next->rows > height)
3973 height=next->rows;
3974 }
3975 /*
cristy7c6dc152011-02-11 14:10:55 +00003976 Smush images.
cristy4285d782011-02-09 20:12:28 +00003977 */
3978 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3979 if (smush_image == (Image *) NULL)
3980 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003981 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003982 {
cristy4285d782011-02-09 20:12:28 +00003983 smush_image=DestroyImage(smush_image);
3984 return((Image *) NULL);
3985 }
3986 smush_image->matte=matte;
3987 (void) SetImageBackgroundColor(smush_image);
3988 status=MagickTrue;
3989 x_offset=0;
3990 y_offset=0;
3991 smush_view=AcquireCacheView(smush_image);
3992 for (n=0; n < (MagickOffsetType) number_images; n++)
3993 {
3994 SetGeometry(smush_image,&geometry);
3995 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3996 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003997 {
3998 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003999 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004000 }
cristy4285d782011-02-09 20:12:28 +00004001 else
cristy4ca38e22011-02-10 02:57:49 +00004002 {
cristy7c6dc152011-02-11 14:10:55 +00004003 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004004 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004005 }
cristybb5dced2011-02-10 02:17:16 +00004006 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004007 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4008 if (proceed == MagickFalse)
4009 break;
4010 if (stack == MagickFalse)
4011 {
4012 x_offset+=(ssize_t) image->columns;
4013 y_offset=0;
4014 }
4015 else
4016 {
4017 x_offset=0;
4018 y_offset+=(ssize_t) image->rows;
4019 }
4020 image=GetNextImageInList(image);
4021 }
cristy4ef6f062011-02-10 20:30:22 +00004022 if (stack == MagickFalse)
4023 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004024 else
cristy4ef6f062011-02-10 20:30:22 +00004025 smush_image->rows=(size_t) y_offset;
4026 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004027 if (status == MagickFalse)
4028 smush_image=DestroyImage(smush_image);
4029 return(smush_image);
4030}
4031
4032/*
4033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4034% %
4035% %
4036% %
cristy3ed852e2009-09-05 21:47:34 +00004037% S t r i p I m a g e %
4038% %
4039% %
4040% %
4041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4042%
cristy376bda92009-12-22 21:15:23 +00004043% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004044%
4045% The format of the StripImage method is:
4046%
4047% MagickBooleanType StripImage(Image *image)
4048%
4049% A description of each parameter follows:
4050%
4051% o image: the image.
4052%
4053*/
4054MagickExport MagickBooleanType StripImage(Image *image)
4055{
4056 assert(image != (Image *) NULL);
4057 if (image->debug != MagickFalse)
4058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4059 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004060 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004061 (void) DeleteImageProperty(image,"date:create");
4062 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004063 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004064 return(MagickTrue);
4065}
4066
4067/*
4068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4069% %
4070% %
4071% %
4072+ S y n c I m a g e %
4073% %
4074% %
4075% %
4076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077%
4078% SyncImage() initializes the red, green, and blue intensities of each pixel
4079% as defined by the colormap index.
4080%
4081% The format of the SyncImage method is:
4082%
4083% MagickBooleanType SyncImage(Image *image)
4084%
4085% A description of each parameter follows:
4086%
4087% o image: the image.
4088%
4089*/
4090
cristy4c08aed2011-07-01 19:47:50 +00004091static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004092 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004093{
4094 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004095 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004096 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004097 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004098}
4099
4100MagickExport MagickBooleanType SyncImage(Image *image)
4101{
4102 CacheView
4103 *image_view;
4104
4105 ExceptionInfo
4106 *exception;
4107
cristy3ed852e2009-09-05 21:47:34 +00004108 MagickBooleanType
4109 range_exception,
4110 status;
4111
cristycb6d09b2010-06-19 01:59:36 +00004112 ssize_t
4113 y;
4114
cristy3ed852e2009-09-05 21:47:34 +00004115 assert(image != (Image *) NULL);
4116 if (image->debug != MagickFalse)
4117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4118 assert(image->signature == MagickSignature);
4119 if (image->storage_class == DirectClass)
4120 return(MagickFalse);
4121 range_exception=MagickFalse;
4122 status=MagickTrue;
4123 exception=(&image->exception);
4124 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004125#if defined(MAGICKCORE_OPENMP_SUPPORT)
4126 #pragma omp parallel for schedule(dynamic,4) shared(status)
4127#endif
cristybb503372010-05-27 20:51:26 +00004128 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004129 {
cristy4c08aed2011-07-01 19:47:50 +00004130 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004131 index;
4132
cristy4c08aed2011-07-01 19:47:50 +00004133 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004134 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004135
cristycb6d09b2010-06-19 01:59:36 +00004136 register ssize_t
4137 x;
4138
cristy48974b92009-12-19 02:36:06 +00004139 if (status == MagickFalse)
4140 continue;
cristy3ed852e2009-09-05 21:47:34 +00004141 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004142 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004143 {
4144 status=MagickFalse;
4145 continue;
4146 }
cristybb503372010-05-27 20:51:26 +00004147 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004148 {
cristy4c08aed2011-07-01 19:47:50 +00004149 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004150 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004151 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00004152 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004153 }
4154 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4155 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004156 }
4157 image_view=DestroyCacheView(image_view);
4158 if (range_exception != MagickFalse)
4159 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4160 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4161 return(status);
4162}
cristy1626d332009-11-10 16:58:17 +00004163
4164/*
4165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4166% %
4167% %
4168% %
4169% S y n c I m a g e S e t t i n g s %
4170% %
4171% %
4172% %
4173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174%
4175% SyncImageSettings() sync the image info options to the image.
4176%
4177% The format of the SyncImageSettings method is:
4178%
4179% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4180% Image *image)
4181% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4182% Image *image)
4183%
4184% A description of each parameter follows:
4185%
4186% o image_info: the image info.
4187%
4188% o image: the image.
4189%
4190*/
4191
4192MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4193 Image *images)
4194{
4195 Image
4196 *image;
4197
4198 assert(image_info != (const ImageInfo *) NULL);
4199 assert(image_info->signature == MagickSignature);
4200 assert(images != (Image *) NULL);
4201 assert(images->signature == MagickSignature);
4202 if (images->debug != MagickFalse)
4203 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4204 image=images;
4205 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4206 (void) SyncImageSettings(image_info,image);
4207 (void) DeleteImageOption(image_info,"page");
4208 return(MagickTrue);
4209}
4210
4211MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4212 Image *image)
4213{
4214 char
4215 property[MaxTextExtent];
4216
4217 const char
cristy9a703812010-07-26 14:50:29 +00004218 *option,
4219 *value;
cristy1626d332009-11-10 16:58:17 +00004220
4221 GeometryInfo
4222 geometry_info;
4223
4224 MagickStatusType
4225 flags;
4226
cristy19eb6412010-04-23 14:42:29 +00004227 ResolutionType
4228 units;
4229
cristy1626d332009-11-10 16:58:17 +00004230 /*
4231 Sync image options.
4232 */
4233 assert(image_info != (const ImageInfo *) NULL);
4234 assert(image_info->signature == MagickSignature);
4235 assert(image != (Image *) NULL);
4236 assert(image->signature == MagickSignature);
4237 if (image->debug != MagickFalse)
4238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4239 option=GetImageOption(image_info,"background");
4240 if (option != (const char *) NULL)
4241 (void) QueryColorDatabase(option,&image->background_color,
4242 &image->exception);
4243 option=GetImageOption(image_info,"bias");
4244 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004245 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004246 option=GetImageOption(image_info,"black-point-compensation");
4247 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004248 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004249 MagickBooleanOptions,MagickFalse,option);
4250 option=GetImageOption(image_info,"blue-primary");
4251 if (option != (const char *) NULL)
4252 {
4253 flags=ParseGeometry(option,&geometry_info);
4254 image->chromaticity.blue_primary.x=geometry_info.rho;
4255 image->chromaticity.blue_primary.y=geometry_info.sigma;
4256 if ((flags & SigmaValue) == 0)
4257 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4258 }
4259 option=GetImageOption(image_info,"bordercolor");
4260 if (option != (const char *) NULL)
4261 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4262 option=GetImageOption(image_info,"colors");
4263 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004264 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004265 option=GetImageOption(image_info,"compose");
4266 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004267 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004268 MagickFalse,option);
4269 option=GetImageOption(image_info,"compress");
4270 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004271 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004272 MagickCompressOptions,MagickFalse,option);
4273 option=GetImageOption(image_info,"debug");
4274 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004275 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004276 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004277 option=GetImageOption(image_info,"density");
4278 if (option != (const char *) NULL)
4279 {
4280 GeometryInfo
4281 geometry_info;
4282
4283 /*
4284 Set image density.
4285 */
4286 flags=ParseGeometry(option,&geometry_info);
4287 image->x_resolution=geometry_info.rho;
4288 image->y_resolution=geometry_info.sigma;
4289 if ((flags & SigmaValue) == 0)
4290 image->y_resolution=image->x_resolution;
4291 }
cristy1626d332009-11-10 16:58:17 +00004292 option=GetImageOption(image_info,"depth");
4293 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004294 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004295 option=GetImageOption(image_info,"endian");
4296 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004297 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004298 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004299 option=GetImageOption(image_info,"filter");
4300 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004301 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004302 MagickFalse,option);
4303 option=GetImageOption(image_info,"fuzz");
4304 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004305 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004306 option=GetImageOption(image_info,"gravity");
4307 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004308 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004309 MagickFalse,option);
4310 option=GetImageOption(image_info,"green-primary");
4311 if (option != (const char *) NULL)
4312 {
4313 flags=ParseGeometry(option,&geometry_info);
4314 image->chromaticity.green_primary.x=geometry_info.rho;
4315 image->chromaticity.green_primary.y=geometry_info.sigma;
4316 if ((flags & SigmaValue) == 0)
4317 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4318 }
4319 option=GetImageOption(image_info,"intent");
4320 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004321 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004322 MagickIntentOptions,MagickFalse,option);
4323 option=GetImageOption(image_info,"interlace");
4324 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004325 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004326 MagickFalse,option);
4327 option=GetImageOption(image_info,"interpolate");
4328 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004329 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004330 MagickInterpolateOptions,MagickFalse,option);
4331 option=GetImageOption(image_info,"loop");
4332 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004333 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004334 option=GetImageOption(image_info,"mattecolor");
4335 if (option != (const char *) NULL)
4336 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4337 option=GetImageOption(image_info,"orient");
4338 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004339 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004340 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004341 option=GetImageOption(image_info,"page");
4342 if (option != (const char *) NULL)
4343 {
4344 char
4345 *geometry;
4346
4347 geometry=GetPageGeometry(option);
4348 flags=ParseAbsoluteGeometry(geometry,&image->page);
4349 geometry=DestroyString(geometry);
4350 }
cristy1626d332009-11-10 16:58:17 +00004351 option=GetImageOption(image_info,"quality");
4352 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004353 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004354 option=GetImageOption(image_info,"red-primary");
4355 if (option != (const char *) NULL)
4356 {
4357 flags=ParseGeometry(option,&geometry_info);
4358 image->chromaticity.red_primary.x=geometry_info.rho;
4359 image->chromaticity.red_primary.y=geometry_info.sigma;
4360 if ((flags & SigmaValue) == 0)
4361 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4362 }
4363 if (image_info->quality != UndefinedCompressionQuality)
4364 image->quality=image_info->quality;
4365 option=GetImageOption(image_info,"scene");
4366 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004367 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004368 option=GetImageOption(image_info,"taint");
4369 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004370 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004371 MagickFalse,option);
4372 option=GetImageOption(image_info,"tile-offset");
4373 if (option != (const char *) NULL)
4374 {
4375 char
4376 *geometry;
4377
4378 geometry=GetPageGeometry(option);
4379 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4380 geometry=DestroyString(geometry);
4381 }
4382 option=GetImageOption(image_info,"transparent-color");
4383 if (option != (const char *) NULL)
4384 (void) QueryColorDatabase(option,&image->transparent_color,
4385 &image->exception);
4386 option=GetImageOption(image_info,"type");
4387 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004388 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004389 option);
4390 option=GetImageOption(image_info,"units");
4391 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004392 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004393 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004394 else
4395 units = image_info->units;
4396 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004397 {
cristy19eb6412010-04-23 14:42:29 +00004398 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004399 switch (image->units)
4400 {
4401 case PixelsPerInchResolution:
4402 {
cristy19eb6412010-04-23 14:42:29 +00004403 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004404 {
4405 image->x_resolution/=2.54;
4406 image->y_resolution/=2.54;
4407 }
4408 break;
4409 }
4410 case PixelsPerCentimeterResolution:
4411 {
cristy19eb6412010-04-23 14:42:29 +00004412 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004413 {
cristybb503372010-05-27 20:51:26 +00004414 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004415 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004416 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004417 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004418 }
4419 break;
4420 }
4421 default:
4422 break;
4423 }
cristy19eb6412010-04-23 14:42:29 +00004424 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004425 }
4426 option=GetImageOption(image_info,"white-point");
4427 if (option != (const char *) NULL)
4428 {
4429 flags=ParseGeometry(option,&geometry_info);
4430 image->chromaticity.white_point.x=geometry_info.rho;
4431 image->chromaticity.white_point.y=geometry_info.sigma;
4432 if ((flags & SigmaValue) == 0)
4433 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4434 }
4435 ResetImageOptionIterator(image_info);
4436 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4437 {
4438 value=GetImageOption(image_info,option);
4439 if (value != (const char *) NULL)
4440 {
cristyb51dff52011-05-19 16:55:47 +00004441 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004442 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004443 }
4444 option=GetNextImageOption(image_info);
4445 }
4446 return(MagickTrue);
4447}