blob: f926196b3ee9fd41e7c8e271a66f559181bb0081 [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);
cristy327d5e92011-08-07 01:16:47 +00002524 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002525 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
cristy4c08aed2011-07-01 19:47:50 +00002537 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002538 background;
2539
2540 PixelPacket
2541 pixel;
2542
cristycb6d09b2010-06-19 01:59:36 +00002543 ssize_t
2544 y;
2545
cristy3ed852e2009-09-05 21:47:34 +00002546 /*
2547 Set transparent pixels to background color.
2548 */
2549 if (image->matte == MagickFalse)
2550 break;
cristy574cc262011-08-05 01:23:58 +00002551 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002552 break;
cristy4c08aed2011-07-01 19:47:50 +00002553 GetPixelInfo(image,&background);
2554 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002555 if (image->colorspace == CMYKColorspace)
2556 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002557 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002558 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002559 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2560 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002561 #endif
cristybb503372010-05-27 20:51:26 +00002562 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002563 {
cristy4c08aed2011-07-01 19:47:50 +00002564 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002565 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002566
cristycb6d09b2010-06-19 01:59:36 +00002567 register ssize_t
2568 x;
2569
cristy3ed852e2009-09-05 21:47:34 +00002570 if (status == MagickFalse)
2571 continue;
2572 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2573 exception);
cristy4c08aed2011-07-01 19:47:50 +00002574 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002575 {
2576 status=MagickFalse;
2577 continue;
2578 }
cristybb503372010-05-27 20:51:26 +00002579 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002580 {
cristy4c08aed2011-07-01 19:47:50 +00002581 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002582 {
cristy4c08aed2011-07-01 19:47:50 +00002583 SetPixelRed(image,pixel.red,q);
2584 SetPixelGreen(image,pixel.green,q);
2585 SetPixelBlue(image,pixel.blue,q);
2586 if (image->colorspace == CMYKColorspace)
2587 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002588 }
cristyed231572011-07-14 02:18:59 +00002589 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002590 }
cristy3ed852e2009-09-05 21:47:34 +00002591 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2592 status=MagickFalse;
2593 }
2594 image_view=DestroyCacheView(image_view);
2595 return(status);
2596 }
2597 case DeactivateAlphaChannel:
2598 {
2599 image->matte=MagickFalse;
2600 break;
2601 }
2602 case ShapeAlphaChannel:
2603 case CopyAlphaChannel:
2604 {
2605 /*
cristy3139dc22011-07-08 00:11:42 +00002606 Special usage case for SeparateImage(): copy grayscale color to
cristy3ed852e2009-09-05 21:47:34 +00002607 the alpha channel.
2608 */
cristyed231572011-07-14 02:18:59 +00002609 PushPixelChannelMap(image,GrayChannel);
cristy3139dc22011-07-08 00:11:42 +00002610 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002611 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002612 image->matte=MagickTrue; /* make sure transparency is now on! */
2613 if (alpha_type == ShapeAlphaChannel)
2614 {
cristy4c08aed2011-07-01 19:47:50 +00002615 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002616 background;
2617
2618 /*
2619 Reset all color channels to background color.
2620 */
cristy4c08aed2011-07-01 19:47:50 +00002621 GetPixelInfo(image,&background);
2622 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002623 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002624 }
2625 break;
2626 }
2627 case ExtractAlphaChannel:
2628 {
cristyed231572011-07-14 02:18:59 +00002629 PushPixelChannelMap(image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002630 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002631 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002632 image->matte=MagickFalse;
2633 break;
2634 }
cristy3ed852e2009-09-05 21:47:34 +00002635 case OpaqueAlphaChannel:
2636 {
cristy4c08aed2011-07-01 19:47:50 +00002637 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002638 image->matte=MagickTrue;
2639 break;
2640 }
2641 case TransparentAlphaChannel:
2642 {
cristy4c08aed2011-07-01 19:47:50 +00002643 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002644 image->matte=MagickTrue;
2645 break;
2646 }
2647 case SetAlphaChannel:
2648 {
2649 if (image->matte == MagickFalse)
2650 {
cristy4c08aed2011-07-01 19:47:50 +00002651 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002652 image->matte=MagickTrue;
2653 }
2654 break;
2655 }
2656 case UndefinedAlphaChannel:
2657 break;
2658 }
cristy6e437132011-08-12 13:02:19 +00002659 if (status == MagickFalse)
2660 return(status);
2661 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002662}
2663
2664/*
2665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2666% %
2667% %
2668% %
2669% S e t I m a g e B a c k g r o u n d C o l o r %
2670% %
2671% %
2672% %
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674%
2675% SetImageBackgroundColor() initializes the image pixels to the image
2676% background color. The background color is defined by the background_color
2677% member of the image structure.
2678%
2679% The format of the SetImage method is:
2680%
2681% MagickBooleanType SetImageBackgroundColor(Image *image)
2682%
2683% A description of each parameter follows:
2684%
2685% o image: the image.
2686%
2687*/
2688MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2689{
2690 CacheView
2691 *image_view;
2692
2693 ExceptionInfo
2694 *exception;
2695
cristy3ed852e2009-09-05 21:47:34 +00002696 MagickBooleanType
2697 status;
2698
cristy4c08aed2011-07-01 19:47:50 +00002699 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002700 background;
2701
2702 PixelPacket
2703 pixel;
2704
cristycb6d09b2010-06-19 01:59:36 +00002705 ssize_t
2706 y;
2707
cristy3ed852e2009-09-05 21:47:34 +00002708 assert(image != (Image *) NULL);
2709 if (image->debug != MagickFalse)
2710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2711 assert(image->signature == MagickSignature);
cristy574cc262011-08-05 01:23:58 +00002712 exception=(&image->exception);
2713 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002714 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002715 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002716 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002717 GetPixelInfo(image,&background);
2718 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002719 if (image->colorspace == CMYKColorspace)
2720 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002721 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002722 /*
2723 Set image background color.
2724 */
2725 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002726 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002727 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002728 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002729 {
cristy4c08aed2011-07-01 19:47:50 +00002730 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002731 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002732
cristycb6d09b2010-06-19 01:59:36 +00002733 register ssize_t
2734 x;
2735
cristy3ed852e2009-09-05 21:47:34 +00002736 if (status == MagickFalse)
2737 continue;
2738 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002739 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002740 {
2741 status=MagickFalse;
2742 continue;
2743 }
cristybb503372010-05-27 20:51:26 +00002744 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002745 {
2746 SetPixelPacket(image,&pixel,q);
2747 if (image->colorspace == CMYKColorspace)
2748 SetPixelBlack(image,pixel.black,q);
cristyed231572011-07-14 02:18:59 +00002749 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002750 }
cristy3ed852e2009-09-05 21:47:34 +00002751 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2752 status=MagickFalse;
2753 }
2754 image_view=DestroyCacheView(image_view);
2755 return(status);
2756}
2757
2758/*
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760% %
2761% %
2762% %
cristya5b77cb2010-05-07 19:34:48 +00002763% S e t I m a g e C o l o r %
2764% %
2765% %
2766% %
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768%
2769% SetImageColor() set the entire image canvas to the specified color.
2770%
2771% The format of the SetImageColor method is:
2772%
cristy08429172011-07-14 17:18:16 +00002773% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002774%
2775% A description of each parameter follows:
2776%
2777% o image: the image.
2778%
2779% o background: the image color.
2780%
2781*/
2782MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002783 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002784{
2785 CacheView
2786 *image_view;
2787
2788 ExceptionInfo
2789 *exception;
2790
cristya5b77cb2010-05-07 19:34:48 +00002791 MagickBooleanType
2792 status;
2793
cristycb6d09b2010-06-19 01:59:36 +00002794 ssize_t
2795 y;
2796
cristya5b77cb2010-05-07 19:34:48 +00002797 assert(image != (Image *) NULL);
2798 if (image->debug != MagickFalse)
2799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2800 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002801 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002802 image->colorspace=color->colorspace;
2803 image->matte=color->matte;
2804 image->fuzz=color->fuzz;
2805 image->depth=color->depth;
2806 status=MagickTrue;
2807 exception=(&image->exception);
2808 image_view=AcquireCacheView(image);
2809#if defined(MAGICKCORE_OPENMP_SUPPORT)
2810 #pragma omp parallel for schedule(dynamic,4) shared(status)
2811#endif
cristybb503372010-05-27 20:51:26 +00002812 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002813 {
cristy4c08aed2011-07-01 19:47:50 +00002814 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002815 *restrict q;
2816
cristycb6d09b2010-06-19 01:59:36 +00002817 register ssize_t
2818 x;
2819
cristya5b77cb2010-05-07 19:34:48 +00002820 if (status == MagickFalse)
2821 continue;
2822 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002823 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002824 {
2825 status=MagickFalse;
2826 continue;
2827 }
cristybb503372010-05-27 20:51:26 +00002828 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002829 {
cristy4c08aed2011-07-01 19:47:50 +00002830 SetPixelPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002831 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002832 }
2833 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2834 status=MagickFalse;
2835 }
2836 image_view=DestroyCacheView(image_view);
2837 return(status);
2838}
2839
2840/*
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842% %
2843% %
2844% %
cristy3ed852e2009-09-05 21:47:34 +00002845% S e t I m a g e S t o r a g e C l a s s %
2846% %
2847% %
2848% %
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850%
2851% SetImageStorageClass() sets the image class: DirectClass for true color
2852% images or PseudoClass for colormapped images.
2853%
2854% The format of the SetImageStorageClass method is:
2855%
2856% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002857% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002858%
2859% A description of each parameter follows:
2860%
2861% o image: the image.
2862%
2863% o storage_class: The image class.
2864%
cristy574cc262011-08-05 01:23:58 +00002865% o exception: return any errors or warnings in this structure.
2866%
cristy3ed852e2009-09-05 21:47:34 +00002867*/
2868MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002869 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002870{
cristy3ed852e2009-09-05 21:47:34 +00002871 image->storage_class=storage_class;
cristy6e437132011-08-12 13:02:19 +00002872 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002873}
2874
2875/*
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877% %
2878% %
2879% %
2880% S e t I m a g e C l i p M a s k %
2881% %
2882% %
2883% %
2884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885%
2886% SetImageClipMask() associates a clip path with the image. The clip path
2887% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002888% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002889% pixel component from being updated when SyncAuthenticPixels() is applied.
2890%
2891% The format of the SetImageClipMask method is:
2892%
2893% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2894%
2895% A description of each parameter follows:
2896%
2897% o image: the image.
2898%
2899% o clip_mask: the image clip path.
2900%
2901*/
2902MagickExport MagickBooleanType SetImageClipMask(Image *image,
2903 const Image *clip_mask)
2904{
2905 assert(image != (Image *) NULL);
2906 if (image->debug != MagickFalse)
2907 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2908 assert(image->signature == MagickSignature);
2909 if (clip_mask != (const Image *) NULL)
2910 if ((clip_mask->columns != image->columns) ||
2911 (clip_mask->rows != image->rows))
2912 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2913 if (image->clip_mask != (Image *) NULL)
2914 image->clip_mask=DestroyImage(image->clip_mask);
2915 image->clip_mask=NewImageList();
2916 if (clip_mask == (Image *) NULL)
2917 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00002918 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002919 return(MagickFalse);
2920 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2921 if (image->clip_mask == (Image *) NULL)
2922 return(MagickFalse);
2923 return(MagickTrue);
2924}
2925
2926/*
2927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2928% %
2929% %
2930% %
2931% S e t I m a g e E x t e n t %
2932% %
2933% %
2934% %
2935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2936%
2937% SetImageExtent() sets the image size (i.e. columns & rows).
2938%
2939% The format of the SetImageExtent method is:
2940%
cristy08429172011-07-14 17:18:16 +00002941% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002942% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002943%
2944% A description of each parameter follows:
2945%
2946% o image: the image.
2947%
2948% o columns: The image width in pixels.
2949%
2950% o rows: The image height in pixels.
2951%
cristy63240882011-08-05 19:05:27 +00002952% o exception: return any errors or warnings in this structure.
2953%
cristy3ed852e2009-09-05 21:47:34 +00002954*/
cristy08429172011-07-14 17:18:16 +00002955MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002956 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002957{
cristy537e2722010-09-21 15:30:59 +00002958 if ((columns == 0) || (rows == 0))
2959 return(MagickFalse);
2960 image->columns=columns;
2961 image->rows=rows;
cristy6e437132011-08-12 13:02:19 +00002962 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002963}
2964
2965/*
2966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2967% %
2968% %
2969% %
2970+ S e t I m a g e I n f o %
2971% %
2972% %
2973% %
2974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2975%
2976% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
2977% It is set to a type of image format based on the prefix or suffix of the
2978% filename. For example, `ps:image' returns PS indicating a Postscript image.
2979% JPEG is returned for this filename: `image.jpg'. The filename prefix has
2980% precendence over the suffix. Use an optional index enclosed in brackets
2981% after a file name to specify a desired scene of a multi-resolution image
2982% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2983% indicates success.
2984%
2985% The format of the SetImageInfo method is:
2986%
2987% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002988% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002989%
2990% A description of each parameter follows:
2991%
cristyd965a422010-03-03 17:47:35 +00002992% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002993%
cristyd965a422010-03-03 17:47:35 +00002994% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002995%
2996% o exception: return any errors or warnings in this structure.
2997%
2998*/
2999MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003000 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003001{
3002 char
3003 extension[MaxTextExtent],
3004 filename[MaxTextExtent],
3005 magic[MaxTextExtent],
3006 *q,
3007 subimage[MaxTextExtent];
3008
3009 const MagicInfo
3010 *magic_info;
3011
3012 const MagickInfo
3013 *magick_info;
3014
3015 ExceptionInfo
3016 *sans_exception;
3017
3018 Image
3019 *image;
3020
3021 MagickBooleanType
3022 status;
3023
3024 register const char
3025 *p;
3026
3027 ssize_t
3028 count;
3029
3030 unsigned char
3031 magick[2*MaxTextExtent];
3032
3033 /*
3034 Look for 'image.format' in filename.
3035 */
3036 assert(image_info != (ImageInfo *) NULL);
3037 assert(image_info->signature == MagickSignature);
3038 if (image_info->debug != MagickFalse)
3039 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3040 image_info->filename);
3041 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003042 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003043 {
cristyd965a422010-03-03 17:47:35 +00003044 GetPathComponent(image_info->filename,SubimagePath,subimage);
3045 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003046 {
cristyd965a422010-03-03 17:47:35 +00003047 /*
3048 Look for scene specification (e.g. img0001.pcd[4]).
3049 */
3050 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3051 {
3052 if (IsGeometry(subimage) != MagickFalse)
3053 (void) CloneString(&image_info->extract,subimage);
3054 }
3055 else
3056 {
cristybb503372010-05-27 20:51:26 +00003057 size_t
cristyd965a422010-03-03 17:47:35 +00003058 first,
3059 last;
cristy3ed852e2009-09-05 21:47:34 +00003060
cristyd965a422010-03-03 17:47:35 +00003061 (void) CloneString(&image_info->scenes,subimage);
3062 image_info->scene=StringToUnsignedLong(image_info->scenes);
3063 image_info->number_scenes=image_info->scene;
3064 p=image_info->scenes;
3065 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3066 {
3067 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3068 (*p == ','))
3069 p++;
cristybb503372010-05-27 20:51:26 +00003070 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003071 last=first;
3072 while (isspace((int) ((unsigned char) *q)) != 0)
3073 q++;
3074 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003075 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003076 if (first > last)
3077 Swap(first,last);
3078 if (first < image_info->scene)
3079 image_info->scene=first;
3080 if (last > image_info->number_scenes)
3081 image_info->number_scenes=last;
3082 p=q;
3083 }
3084 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003085 }
cristy3ed852e2009-09-05 21:47:34 +00003086 }
3087 }
3088 *extension='\0';
3089 GetPathComponent(image_info->filename,ExtensionPath,extension);
3090#if defined(MAGICKCORE_ZLIB_DELEGATE)
3091 if (*extension != '\0')
3092 if ((LocaleCompare(extension,"gz") == 0) ||
3093 (LocaleCompare(extension,"Z") == 0) ||
3094 (LocaleCompare(extension,"wmz") == 0))
3095 {
3096 char
3097 path[MaxTextExtent];
3098
3099 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3100 path[strlen(path)-strlen(extension)-1]='\0';
3101 GetPathComponent(path,ExtensionPath,extension);
3102 }
3103#endif
3104#if defined(MAGICKCORE_BZLIB_DELEGATE)
3105 if (*extension != '\0')
3106 if (LocaleCompare(extension,"bz2") == 0)
3107 {
3108 char
3109 path[MaxTextExtent];
3110
3111 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3112 path[strlen(path)-strlen(extension)-1]='\0';
3113 GetPathComponent(path,ExtensionPath,extension);
3114 }
3115#endif
3116 image_info->affirm=MagickFalse;
3117 sans_exception=AcquireExceptionInfo();
3118 if (*extension != '\0')
3119 {
3120 MagickFormatType
3121 format_type;
3122
cristybb503372010-05-27 20:51:26 +00003123 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003124 i;
3125
3126 static const char
3127 *format_type_formats[] =
3128 {
3129 "AUTOTRACE",
3130 "BROWSE",
3131 "DCRAW",
3132 "EDIT",
3133 "EPHEMERAL",
3134 "LAUNCH",
3135 "MPEG:DECODE",
3136 "MPEG:ENCODE",
3137 "PRINT",
3138 "PS:ALPHA",
3139 "PS:CMYK",
3140 "PS:COLOR",
3141 "PS:GRAY",
3142 "PS:MONO",
3143 "SCAN",
3144 "SHOW",
3145 "WIN",
3146 (char *) NULL
3147 };
3148
3149 /*
3150 User specified image format.
3151 */
3152 (void) CopyMagickString(magic,extension,MaxTextExtent);
3153 LocaleUpper(magic);
3154 /*
3155 Look for explicit image formats.
3156 */
3157 format_type=UndefinedFormatType;
3158 i=0;
cristydd9a2532010-02-20 19:26:46 +00003159 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003160 (format_type_formats[i] != (char *) NULL))
3161 {
3162 if ((*magic == *format_type_formats[i]) &&
3163 (LocaleCompare(magic,format_type_formats[i]) == 0))
3164 format_type=ExplicitFormatType;
3165 i++;
3166 }
3167 magick_info=GetMagickInfo(magic,sans_exception);
3168 if ((magick_info != (const MagickInfo *) NULL) &&
3169 (magick_info->format_type != UndefinedFormatType))
3170 format_type=magick_info->format_type;
3171 if (format_type == UndefinedFormatType)
3172 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3173 else
3174 if (format_type == ExplicitFormatType)
3175 {
3176 image_info->affirm=MagickTrue;
3177 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3178 }
3179 if (LocaleCompare(magic,"RGB") == 0)
3180 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3181 }
3182 /*
3183 Look for explicit 'format:image' in filename.
3184 */
3185 *magic='\0';
3186 GetPathComponent(image_info->filename,MagickPath,magic);
3187 if (*magic == '\0')
3188 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3189 else
3190 {
3191 /*
3192 User specified image format.
3193 */
3194 LocaleUpper(magic);
3195 if (IsMagickConflict(magic) == MagickFalse)
3196 {
3197 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3198 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3199 image_info->affirm=MagickTrue;
3200 else
3201 image_info->temporary=MagickTrue;
3202 }
3203 }
3204 magick_info=GetMagickInfo(magic,sans_exception);
3205 sans_exception=DestroyExceptionInfo(sans_exception);
3206 if ((magick_info == (const MagickInfo *) NULL) ||
3207 (GetMagickEndianSupport(magick_info) == MagickFalse))
3208 image_info->endian=UndefinedEndian;
3209 GetPathComponent(image_info->filename,CanonicalPath,filename);
3210 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003211 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003212 {
3213 /*
cristyd965a422010-03-03 17:47:35 +00003214 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003215 */
cristyd965a422010-03-03 17:47:35 +00003216 (void) InterpretImageFilename(image_info,(Image *) NULL,
3217 image_info->filename,(int) image_info->scene,filename);
3218 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3219 (strchr(filename,'%') == (char *) NULL))
3220 image_info->adjoin=MagickFalse;
3221 }
3222 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3223 {
3224 /*
3225 Some image formats do not support multiple frames per file.
3226 */
cristy3ed852e2009-09-05 21:47:34 +00003227 magick_info=GetMagickInfo(magic,exception);
3228 if (magick_info != (const MagickInfo *) NULL)
3229 if (GetMagickAdjoin(magick_info) == MagickFalse)
3230 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003231 }
3232 if (image_info->affirm != MagickFalse)
3233 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003234 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003235 {
3236 /*
cristyd965a422010-03-03 17:47:35 +00003237 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003238 */
cristyd965a422010-03-03 17:47:35 +00003239 image=AcquireImage(image_info);
3240 (void) CopyMagickString(image->filename,image_info->filename,
3241 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003242 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3243 if (status == MagickFalse)
3244 {
3245 image=DestroyImage(image);
3246 return(MagickFalse);
3247 }
cristyd965a422010-03-03 17:47:35 +00003248 if ((IsBlobSeekable(image) == MagickFalse) ||
3249 (IsBlobExempt(image) != MagickFalse))
3250 {
3251 /*
3252 Copy standard input or pipe to temporary file.
3253 */
3254 *filename='\0';
3255 status=ImageToFile(image,filename,exception);
3256 (void) CloseBlob(image);
3257 if (status == MagickFalse)
3258 {
3259 image=DestroyImage(image);
3260 return(MagickFalse);
3261 }
3262 SetImageInfoFile(image_info,(FILE *) NULL);
3263 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3264 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3265 if (status == MagickFalse)
3266 {
3267 image=DestroyImage(image);
3268 return(MagickFalse);
3269 }
3270 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3271 image_info->temporary=MagickTrue;
3272 }
3273 (void) ResetMagickMemory(magick,0,sizeof(magick));
3274 count=ReadBlob(image,2*MaxTextExtent,magick);
3275 (void) CloseBlob(image);
3276 image=DestroyImage(image);
3277 /*
3278 Check magic.xml configuration file.
3279 */
3280 sans_exception=AcquireExceptionInfo();
3281 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3282 if ((magic_info != (const MagicInfo *) NULL) &&
3283 (GetMagicName(magic_info) != (char *) NULL))
3284 {
3285 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3286 MaxTextExtent);
3287 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3288 if ((magick_info == (const MagickInfo *) NULL) ||
3289 (GetMagickEndianSupport(magick_info) == MagickFalse))
3290 image_info->endian=UndefinedEndian;
3291 sans_exception=DestroyExceptionInfo(sans_exception);
3292 return(MagickTrue);
3293 }
cristy3ed852e2009-09-05 21:47:34 +00003294 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3295 if ((magick_info == (const MagickInfo *) NULL) ||
3296 (GetMagickEndianSupport(magick_info) == MagickFalse))
3297 image_info->endian=UndefinedEndian;
3298 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003299 }
cristy3ed852e2009-09-05 21:47:34 +00003300 return(MagickTrue);
3301}
3302
3303/*
3304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3305% %
3306% %
3307% %
3308% S e t I m a g e I n f o B l o b %
3309% %
3310% %
3311% %
3312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3313%
3314% SetImageInfoBlob() sets the image info blob member.
3315%
3316% The format of the SetImageInfoBlob method is:
3317%
3318% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3319% const size_t length)
3320%
3321% A description of each parameter follows:
3322%
3323% o image_info: the image info.
3324%
3325% o blob: the blob.
3326%
3327% o length: the blob length.
3328%
3329*/
3330MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3331 const size_t length)
3332{
3333 assert(image_info != (ImageInfo *) NULL);
3334 assert(image_info->signature == MagickSignature);
3335 if (image_info->debug != MagickFalse)
3336 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3337 image_info->filename);
3338 image_info->blob=(void *) blob;
3339 image_info->length=length;
3340}
3341
3342/*
3343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3344% %
3345% %
3346% %
3347% S e t I m a g e I n f o F i l e %
3348% %
3349% %
3350% %
3351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3352%
3353% SetImageInfoFile() sets the image info file member.
3354%
3355% The format of the SetImageInfoFile method is:
3356%
3357% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3358%
3359% A description of each parameter follows:
3360%
3361% o image_info: the image info.
3362%
3363% o file: the file.
3364%
3365*/
3366MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3367{
3368 assert(image_info != (ImageInfo *) NULL);
3369 assert(image_info->signature == MagickSignature);
3370 if (image_info->debug != MagickFalse)
3371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3372 image_info->filename);
3373 image_info->file=file;
3374}
3375
3376/*
3377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3378% %
3379% %
3380% %
3381% S e t I m a g e M a s k %
3382% %
3383% %
3384% %
3385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3386%
3387% SetImageMask() associates a mask with the image. The mask must be the same
3388% dimensions as the image.
3389%
3390% The format of the SetImageMask method is:
3391%
3392% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3393%
3394% A description of each parameter follows:
3395%
3396% o image: the image.
3397%
3398% o mask: the image mask.
3399%
3400*/
3401MagickExport MagickBooleanType SetImageMask(Image *image,
3402 const Image *mask)
3403{
3404 assert(image != (Image *) NULL);
3405 if (image->debug != MagickFalse)
3406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3407 assert(image->signature == MagickSignature);
3408 if (mask != (const Image *) NULL)
3409 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3410 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3411 if (image->mask != (Image *) NULL)
3412 image->mask=DestroyImage(image->mask);
3413 image->mask=NewImageList();
3414 if (mask == (Image *) NULL)
3415 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00003416 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003417 return(MagickFalse);
3418 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3419 if (image->mask == (Image *) NULL)
3420 return(MagickFalse);
3421 return(MagickTrue);
3422}
3423
3424/*
3425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3426% %
3427% %
3428% %
3429% S e t I m a g e O p a c i t y %
3430% %
3431% %
3432% %
3433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3434%
3435% SetImageOpacity() sets the opacity levels of the image.
3436%
3437% The format of the SetImageOpacity method is:
3438%
3439% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3440%
3441% A description of each parameter follows:
3442%
3443% o image: the image.
3444%
3445% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3446% fully transparent.
3447%
3448*/
3449MagickExport MagickBooleanType SetImageOpacity(Image *image,
3450 const Quantum opacity)
3451{
3452 CacheView
3453 *image_view;
3454
3455 ExceptionInfo
3456 *exception;
3457
cristy3ed852e2009-09-05 21:47:34 +00003458 MagickBooleanType
3459 status;
3460
cristycb6d09b2010-06-19 01:59:36 +00003461 ssize_t
3462 y;
3463
cristy3ed852e2009-09-05 21:47:34 +00003464 assert(image != (Image *) NULL);
3465 if (image->debug != MagickFalse)
3466 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3467 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003468 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003469 status=MagickTrue;
3470 exception=(&image->exception);
3471 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003472#if defined(MAGICKCORE_OPENMP_SUPPORT)
3473 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003474#endif
cristybb503372010-05-27 20:51:26 +00003475 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003476 {
cristy4c08aed2011-07-01 19:47:50 +00003477 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003478 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003479
cristycb6d09b2010-06-19 01:59:36 +00003480 register ssize_t
3481 x;
3482
cristy3ed852e2009-09-05 21:47:34 +00003483 if (status == MagickFalse)
3484 continue;
3485 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003486 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003487 {
3488 status=MagickFalse;
3489 continue;
3490 }
cristybb503372010-05-27 20:51:26 +00003491 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003492 {
cristy4c08aed2011-07-01 19:47:50 +00003493 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00003494 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003495 }
3496 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3497 status=MagickFalse;
3498 }
3499 image_view=DestroyCacheView(image_view);
3500 return(status);
3501}
3502
3503/*
3504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3505% %
3506% %
3507% %
3508% S e t I m a g e T y p e %
3509% %
3510% %
3511% %
3512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513%
3514% SetImageType() sets the type of image. Choose from these types:
3515%
3516% Bilevel Grayscale GrayscaleMatte
3517% Palette PaletteMatte TrueColor
3518% TrueColorMatte ColorSeparation ColorSeparationMatte
3519% OptimizeType
3520%
3521% The format of the SetImageType method is:
3522%
3523% MagickBooleanType SetImageType(Image *image,const ImageType type)
3524%
3525% A description of each parameter follows:
3526%
3527% o image: the image.
3528%
3529% o type: Image type.
3530%
3531*/
3532MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3533{
3534 const char
3535 *artifact;
3536
cristy63240882011-08-05 19:05:27 +00003537 ExceptionInfo
3538 *exception;
3539
cristy3ed852e2009-09-05 21:47:34 +00003540 ImageInfo
3541 *image_info;
3542
3543 MagickBooleanType
3544 status;
3545
3546 QuantizeInfo
3547 *quantize_info;
3548
3549 assert(image != (Image *) NULL);
3550 if (image->debug != MagickFalse)
3551 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3552 assert(image->signature == MagickSignature);
3553 status=MagickTrue;
3554 image_info=AcquireImageInfo();
3555 image_info->dither=image->dither;
3556 artifact=GetImageArtifact(image,"dither");
3557 if (artifact != (const char *) NULL)
3558 (void) SetImageOption(image_info,"dither",artifact);
cristy63240882011-08-05 19:05:27 +00003559 exception=(&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003560 switch (type)
3561 {
3562 case BilevelType:
3563 {
cristy4c08aed2011-07-01 19:47:50 +00003564 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003565 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003566 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003567 {
3568 quantize_info=AcquireQuantizeInfo(image_info);
3569 quantize_info->number_colors=2;
3570 quantize_info->colorspace=GRAYColorspace;
3571 status=QuantizeImage(quantize_info,image);
3572 quantize_info=DestroyQuantizeInfo(quantize_info);
3573 }
3574 image->matte=MagickFalse;
3575 break;
3576 }
3577 case GrayscaleType:
3578 {
cristy4c08aed2011-07-01 19:47:50 +00003579 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003580 status=TransformImageColorspace(image,GRAYColorspace);
3581 image->matte=MagickFalse;
3582 break;
3583 }
3584 case GrayscaleMatteType:
3585 {
cristy4c08aed2011-07-01 19:47:50 +00003586 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003587 status=TransformImageColorspace(image,GRAYColorspace);
3588 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003589 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003590 break;
3591 }
3592 case PaletteType:
3593 {
cristy510d06a2011-07-06 23:43:54 +00003594 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003595 status=TransformImageColorspace(image,RGBColorspace);
3596 if ((image->storage_class == DirectClass) || (image->colors > 256))
3597 {
3598 quantize_info=AcquireQuantizeInfo(image_info);
3599 quantize_info->number_colors=256;
3600 status=QuantizeImage(quantize_info,image);
3601 quantize_info=DestroyQuantizeInfo(quantize_info);
3602 }
3603 image->matte=MagickFalse;
3604 break;
3605 }
3606 case PaletteBilevelMatteType:
3607 {
cristy510d06a2011-07-06 23:43:54 +00003608 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003609 status=TransformImageColorspace(image,RGBColorspace);
3610 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003611 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristyed231572011-07-14 02:18:59 +00003612 PushPixelChannelMap(image,AlphaChannel);
cristyf4ad9df2011-07-08 16:49:03 +00003613 (void) BilevelImage(image,(double) QuantumRange/2.0);
cristyed231572011-07-14 02:18:59 +00003614 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00003615 quantize_info=AcquireQuantizeInfo(image_info);
3616 status=QuantizeImage(quantize_info,image);
3617 quantize_info=DestroyQuantizeInfo(quantize_info);
3618 break;
3619 }
3620 case PaletteMatteType:
3621 {
cristy510d06a2011-07-06 23:43:54 +00003622 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003623 status=TransformImageColorspace(image,RGBColorspace);
3624 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003625 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003626 quantize_info=AcquireQuantizeInfo(image_info);
3627 quantize_info->colorspace=TransparentColorspace;
3628 status=QuantizeImage(quantize_info,image);
3629 quantize_info=DestroyQuantizeInfo(quantize_info);
3630 break;
3631 }
3632 case TrueColorType:
3633 {
cristy510d06a2011-07-06 23:43:54 +00003634 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003635 status=TransformImageColorspace(image,RGBColorspace);
3636 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003637 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003638 image->matte=MagickFalse;
3639 break;
3640 }
3641 case TrueColorMatteType:
3642 {
cristy510d06a2011-07-06 23:43:54 +00003643 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003644 status=TransformImageColorspace(image,RGBColorspace);
3645 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003646 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003647 if (image->matte == MagickFalse)
cristy63240882011-08-05 19:05:27 +00003648 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003649 break;
3650 }
3651 case ColorSeparationType:
3652 {
3653 if (image->colorspace != CMYKColorspace)
3654 {
cristy510d06a2011-07-06 23:43:54 +00003655 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003656 status=TransformImageColorspace(image,RGBColorspace);
3657 status=TransformImageColorspace(image,CMYKColorspace);
3658 }
3659 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003660 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003661 image->matte=MagickFalse;
3662 break;
3663 }
3664 case ColorSeparationMatteType:
3665 {
3666 if (image->colorspace != CMYKColorspace)
3667 {
cristy510d06a2011-07-06 23:43:54 +00003668 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003669 status=TransformImageColorspace(image,RGBColorspace);
3670 status=TransformImageColorspace(image,CMYKColorspace);
3671 }
3672 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003673 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003674 if (image->matte == MagickFalse)
cristy327d5e92011-08-07 01:16:47 +00003675 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristy3ed852e2009-09-05 21:47:34 +00003676 break;
3677 }
3678 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003679 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003680 break;
3681 }
3682 image->type=type;
3683 image_info=DestroyImageInfo(image_info);
3684 return(status);
3685}
3686
3687/*
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689% %
3690% %
3691% %
3692% 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 %
3693% %
3694% %
3695% %
3696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3697%
3698% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3699% image and returns the previous setting. A virtual pixel is any pixel access
3700% that is outside the boundaries of the image cache.
3701%
3702% The format of the SetImageVirtualPixelMethod() method is:
3703%
3704% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3705% const VirtualPixelMethod virtual_pixel_method)
3706%
3707% A description of each parameter follows:
3708%
3709% o image: the image.
3710%
3711% o virtual_pixel_method: choose the type of virtual pixel.
3712%
3713*/
3714MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3715 const VirtualPixelMethod virtual_pixel_method)
3716{
3717 assert(image != (const Image *) NULL);
3718 assert(image->signature == MagickSignature);
3719 if (image->debug != MagickFalse)
3720 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3721 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3722}
3723
3724/*
3725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726% %
3727% %
3728% %
cristy4285d782011-02-09 20:12:28 +00003729% S m u s h I m a g e s %
3730% %
3731% %
3732% %
3733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3734%
3735% SmushImages() takes all images from the current image pointer to the end
3736% of the image list and smushes them to each other top-to-bottom if the
3737% stack parameter is true, otherwise left-to-right.
3738%
3739% The current gravity setting now effects how the image is justified in the
3740% final image.
3741%
3742% The format of the SmushImages method is:
3743%
cristy4ca38e22011-02-10 02:57:49 +00003744% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003745% ExceptionInfo *exception)
3746%
3747% A description of each parameter follows:
3748%
cristy4ca38e22011-02-10 02:57:49 +00003749% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003750%
3751% o stack: A value other than 0 stacks the images top-to-bottom.
3752%
3753% o offset: minimum distance in pixels between images.
3754%
3755% o exception: return any errors or warnings in this structure.
3756%
3757*/
cristy4ca38e22011-02-10 02:57:49 +00003758
cristy7c6dc152011-02-11 14:10:55 +00003759static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003760 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003761{
cristy4d727152011-02-10 19:57:21 +00003762 CacheView
3763 *left_view,
3764 *right_view;
3765
3766 const Image
3767 *left_image,
3768 *right_image;
3769
cristy4d727152011-02-10 19:57:21 +00003770 RectangleInfo
3771 left_geometry,
3772 right_geometry;
3773
cristy4c08aed2011-07-01 19:47:50 +00003774 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003775 *p;
3776
cristy4d727152011-02-10 19:57:21 +00003777 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003778 i,
cristy4d727152011-02-10 19:57:21 +00003779 y;
3780
cristy7c6dc152011-02-11 14:10:55 +00003781 size_t
3782 gap;
3783
cristy4d727152011-02-10 19:57:21 +00003784 ssize_t
cristy4d727152011-02-10 19:57:21 +00003785 x;
3786
3787 if (images->previous == (Image *) NULL)
3788 return(0);
3789 right_image=images;
3790 SetGeometry(smush_image,&right_geometry);
3791 GravityAdjustGeometry(right_image->columns,right_image->rows,
3792 right_image->gravity,&right_geometry);
3793 left_image=images->previous;
3794 SetGeometry(smush_image,&left_geometry);
3795 GravityAdjustGeometry(left_image->columns,left_image->rows,
3796 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003797 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003798 left_view=AcquireCacheView(left_image);
3799 right_view=AcquireCacheView(right_image);
3800 for (y=0; y < (ssize_t) smush_image->rows; y++)
3801 {
3802 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3803 {
cristydab7e912011-02-11 18:19:24 +00003804 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003805 if ((p == (const Quantum *) NULL) ||
3806 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003807 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003808 break;
3809 }
cristy4ef6f062011-02-10 20:30:22 +00003810 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003811 for (x=0; x < (ssize_t) right_image->columns; x++)
3812 {
cristydab7e912011-02-11 18:19:24 +00003813 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003814 exception);
cristy4c08aed2011-07-01 19:47:50 +00003815 if ((p == (const Quantum *) NULL) ||
3816 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3817 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003818 break;
3819 }
cristy7c6dc152011-02-11 14:10:55 +00003820 if ((x+i) < (ssize_t) gap)
3821 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003822 }
3823 right_view=DestroyCacheView(right_view);
3824 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003825 if (y < (ssize_t) smush_image->rows)
3826 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003827 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003828}
3829
cristy7c6dc152011-02-11 14:10:55 +00003830static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003831 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003832{
cristy4d727152011-02-10 19:57:21 +00003833 CacheView
3834 *bottom_view,
3835 *top_view;
3836
3837 const Image
3838 *bottom_image,
3839 *top_image;
3840
cristy4d727152011-02-10 19:57:21 +00003841 RectangleInfo
3842 bottom_geometry,
3843 top_geometry;
3844
cristy4c08aed2011-07-01 19:47:50 +00003845 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003846 *p;
3847
cristy4d727152011-02-10 19:57:21 +00003848 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003849 i,
cristy4d727152011-02-10 19:57:21 +00003850 x;
3851
cristy7c6dc152011-02-11 14:10:55 +00003852 size_t
3853 gap;
3854
cristy4d727152011-02-10 19:57:21 +00003855 ssize_t
cristy4d727152011-02-10 19:57:21 +00003856 y;
3857
3858 if (images->previous == (Image *) NULL)
3859 return(0);
3860 bottom_image=images;
3861 SetGeometry(smush_image,&bottom_geometry);
3862 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3863 bottom_image->gravity,&bottom_geometry);
3864 top_image=images->previous;
3865 SetGeometry(smush_image,&top_geometry);
3866 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3867 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003868 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003869 top_view=AcquireCacheView(top_image);
3870 bottom_view=AcquireCacheView(bottom_image);
3871 for (x=0; x < (ssize_t) smush_image->columns; x++)
3872 {
3873 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3874 {
cristydab7e912011-02-11 18:19:24 +00003875 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003876 if ((p == (const Quantum *) NULL) ||
3877 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3878 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003879 break;
3880 }
cristy4ef6f062011-02-10 20:30:22 +00003881 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003882 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3883 {
cristydab7e912011-02-11 18:19:24 +00003884 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3885 exception);
cristy4c08aed2011-07-01 19:47:50 +00003886 if ((p == (const Quantum *) NULL) ||
3887 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3888 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003889 break;
3890 }
cristy7c6dc152011-02-11 14:10:55 +00003891 if ((y+i) < (ssize_t) gap)
3892 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003893 }
3894 bottom_view=DestroyCacheView(bottom_view);
3895 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003896 if (x < (ssize_t) smush_image->columns)
3897 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003898 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003899}
3900
3901MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003902 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3903{
3904#define SmushImageTag "Smush/Image"
3905
3906 CacheView
cristybb5dced2011-02-10 02:17:16 +00003907 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003908
cristy4ca38e22011-02-10 02:57:49 +00003909 const Image
3910 *image;
3911
cristy4285d782011-02-09 20:12:28 +00003912 Image
3913 *smush_image;
3914
3915 MagickBooleanType
3916 matte,
3917 proceed,
3918 status;
3919
3920 MagickOffsetType
3921 n;
3922
3923 RectangleInfo
3924 geometry;
3925
3926 register const Image
3927 *next;
3928
3929 size_t
3930 height,
3931 number_images,
3932 width;
3933
3934 ssize_t
3935 x_offset,
cristy4285d782011-02-09 20:12:28 +00003936 y_offset;
3937
3938 /*
cristy7c6dc152011-02-11 14:10:55 +00003939 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003940 */
cristy4ca38e22011-02-10 02:57:49 +00003941 assert(images != (Image *) NULL);
3942 assert(images->signature == MagickSignature);
3943 if (images->debug != MagickFalse)
3944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003945 assert(exception != (ExceptionInfo *) NULL);
3946 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003947 image=images;
cristy4285d782011-02-09 20:12:28 +00003948 matte=image->matte;
3949 number_images=1;
3950 width=image->columns;
3951 height=image->rows;
3952 next=GetNextImageInList(image);
3953 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3954 {
3955 if (next->matte != MagickFalse)
3956 matte=MagickTrue;
3957 number_images++;
3958 if (stack != MagickFalse)
3959 {
3960 if (next->columns > width)
3961 width=next->columns;
3962 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003963 if (next->previous != (Image *) NULL)
3964 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003965 continue;
3966 }
3967 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003968 if (next->previous != (Image *) NULL)
3969 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003970 if (next->rows > height)
3971 height=next->rows;
3972 }
3973 /*
cristy7c6dc152011-02-11 14:10:55 +00003974 Smush images.
cristy4285d782011-02-09 20:12:28 +00003975 */
3976 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3977 if (smush_image == (Image *) NULL)
3978 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003979 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003980 {
cristy4285d782011-02-09 20:12:28 +00003981 smush_image=DestroyImage(smush_image);
3982 return((Image *) NULL);
3983 }
3984 smush_image->matte=matte;
3985 (void) SetImageBackgroundColor(smush_image);
3986 status=MagickTrue;
3987 x_offset=0;
3988 y_offset=0;
3989 smush_view=AcquireCacheView(smush_image);
3990 for (n=0; n < (MagickOffsetType) number_images; n++)
3991 {
3992 SetGeometry(smush_image,&geometry);
3993 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3994 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003995 {
3996 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003997 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003998 }
cristy4285d782011-02-09 20:12:28 +00003999 else
cristy4ca38e22011-02-10 02:57:49 +00004000 {
cristy7c6dc152011-02-11 14:10:55 +00004001 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004002 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004003 }
cristybb5dced2011-02-10 02:17:16 +00004004 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004005 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4006 if (proceed == MagickFalse)
4007 break;
4008 if (stack == MagickFalse)
4009 {
4010 x_offset+=(ssize_t) image->columns;
4011 y_offset=0;
4012 }
4013 else
4014 {
4015 x_offset=0;
4016 y_offset+=(ssize_t) image->rows;
4017 }
4018 image=GetNextImageInList(image);
4019 }
cristy4ef6f062011-02-10 20:30:22 +00004020 if (stack == MagickFalse)
4021 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004022 else
cristy4ef6f062011-02-10 20:30:22 +00004023 smush_image->rows=(size_t) y_offset;
4024 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004025 if (status == MagickFalse)
4026 smush_image=DestroyImage(smush_image);
4027 return(smush_image);
4028}
4029
4030/*
4031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4032% %
4033% %
4034% %
cristy3ed852e2009-09-05 21:47:34 +00004035% S t r i p I m a g e %
4036% %
4037% %
4038% %
4039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4040%
cristy376bda92009-12-22 21:15:23 +00004041% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004042%
4043% The format of the StripImage method is:
4044%
4045% MagickBooleanType StripImage(Image *image)
4046%
4047% A description of each parameter follows:
4048%
4049% o image: the image.
4050%
4051*/
4052MagickExport MagickBooleanType StripImage(Image *image)
4053{
4054 assert(image != (Image *) NULL);
4055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4057 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004058 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004059 (void) DeleteImageProperty(image,"date:create");
4060 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004061 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004062 return(MagickTrue);
4063}
4064
4065/*
4066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4067% %
4068% %
4069% %
4070+ S y n c I m a g e %
4071% %
4072% %
4073% %
4074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4075%
4076% SyncImage() initializes the red, green, and blue intensities of each pixel
4077% as defined by the colormap index.
4078%
4079% The format of the SyncImage method is:
4080%
4081% MagickBooleanType SyncImage(Image *image)
4082%
4083% A description of each parameter follows:
4084%
4085% o image: the image.
4086%
4087*/
4088
cristy4c08aed2011-07-01 19:47:50 +00004089static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004090 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004091{
4092 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004093 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004094 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004095 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004096}
4097
4098MagickExport MagickBooleanType SyncImage(Image *image)
4099{
4100 CacheView
4101 *image_view;
4102
4103 ExceptionInfo
4104 *exception;
4105
cristy3ed852e2009-09-05 21:47:34 +00004106 MagickBooleanType
4107 range_exception,
4108 status;
4109
cristycb6d09b2010-06-19 01:59:36 +00004110 ssize_t
4111 y;
4112
cristy3ed852e2009-09-05 21:47:34 +00004113 assert(image != (Image *) NULL);
4114 if (image->debug != MagickFalse)
4115 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4116 assert(image->signature == MagickSignature);
4117 if (image->storage_class == DirectClass)
4118 return(MagickFalse);
4119 range_exception=MagickFalse;
4120 status=MagickTrue;
4121 exception=(&image->exception);
4122 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004123#if defined(MAGICKCORE_OPENMP_SUPPORT)
4124 #pragma omp parallel for schedule(dynamic,4) shared(status)
4125#endif
cristybb503372010-05-27 20:51:26 +00004126 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004127 {
cristy4c08aed2011-07-01 19:47:50 +00004128 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004129 index;
4130
cristy4c08aed2011-07-01 19:47:50 +00004131 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004132 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004133
cristycb6d09b2010-06-19 01:59:36 +00004134 register ssize_t
4135 x;
4136
cristy48974b92009-12-19 02:36:06 +00004137 if (status == MagickFalse)
4138 continue;
cristy3ed852e2009-09-05 21:47:34 +00004139 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004140 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004141 {
4142 status=MagickFalse;
4143 continue;
4144 }
cristybb503372010-05-27 20:51:26 +00004145 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004146 {
cristy4c08aed2011-07-01 19:47:50 +00004147 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004148 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004149 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00004150 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004151 }
4152 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4153 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004154 }
4155 image_view=DestroyCacheView(image_view);
4156 if (range_exception != MagickFalse)
4157 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4158 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4159 return(status);
4160}
cristy1626d332009-11-10 16:58:17 +00004161
4162/*
4163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4164% %
4165% %
4166% %
4167% S y n c I m a g e S e t t i n g s %
4168% %
4169% %
4170% %
4171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4172%
4173% SyncImageSettings() sync the image info options to the image.
4174%
4175% The format of the SyncImageSettings method is:
4176%
4177% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4178% Image *image)
4179% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4180% Image *image)
4181%
4182% A description of each parameter follows:
4183%
4184% o image_info: the image info.
4185%
4186% o image: the image.
4187%
4188*/
4189
4190MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4191 Image *images)
4192{
4193 Image
4194 *image;
4195
4196 assert(image_info != (const ImageInfo *) NULL);
4197 assert(image_info->signature == MagickSignature);
4198 assert(images != (Image *) NULL);
4199 assert(images->signature == MagickSignature);
4200 if (images->debug != MagickFalse)
4201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4202 image=images;
4203 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4204 (void) SyncImageSettings(image_info,image);
4205 (void) DeleteImageOption(image_info,"page");
4206 return(MagickTrue);
4207}
4208
4209MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4210 Image *image)
4211{
4212 char
4213 property[MaxTextExtent];
4214
4215 const char
cristy9a703812010-07-26 14:50:29 +00004216 *option,
4217 *value;
cristy1626d332009-11-10 16:58:17 +00004218
4219 GeometryInfo
4220 geometry_info;
4221
4222 MagickStatusType
4223 flags;
4224
cristy19eb6412010-04-23 14:42:29 +00004225 ResolutionType
4226 units;
4227
cristy1626d332009-11-10 16:58:17 +00004228 /*
4229 Sync image options.
4230 */
4231 assert(image_info != (const ImageInfo *) NULL);
4232 assert(image_info->signature == MagickSignature);
4233 assert(image != (Image *) NULL);
4234 assert(image->signature == MagickSignature);
4235 if (image->debug != MagickFalse)
4236 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4237 option=GetImageOption(image_info,"background");
4238 if (option != (const char *) NULL)
4239 (void) QueryColorDatabase(option,&image->background_color,
4240 &image->exception);
4241 option=GetImageOption(image_info,"bias");
4242 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004243 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004244 option=GetImageOption(image_info,"black-point-compensation");
4245 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004246 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004247 MagickBooleanOptions,MagickFalse,option);
4248 option=GetImageOption(image_info,"blue-primary");
4249 if (option != (const char *) NULL)
4250 {
4251 flags=ParseGeometry(option,&geometry_info);
4252 image->chromaticity.blue_primary.x=geometry_info.rho;
4253 image->chromaticity.blue_primary.y=geometry_info.sigma;
4254 if ((flags & SigmaValue) == 0)
4255 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4256 }
4257 option=GetImageOption(image_info,"bordercolor");
4258 if (option != (const char *) NULL)
4259 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4260 option=GetImageOption(image_info,"colors");
4261 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004262 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004263 option=GetImageOption(image_info,"compose");
4264 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004265 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004266 MagickFalse,option);
4267 option=GetImageOption(image_info,"compress");
4268 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004269 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004270 MagickCompressOptions,MagickFalse,option);
4271 option=GetImageOption(image_info,"debug");
4272 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004273 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004274 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004275 option=GetImageOption(image_info,"density");
4276 if (option != (const char *) NULL)
4277 {
4278 GeometryInfo
4279 geometry_info;
4280
4281 /*
4282 Set image density.
4283 */
4284 flags=ParseGeometry(option,&geometry_info);
4285 image->x_resolution=geometry_info.rho;
4286 image->y_resolution=geometry_info.sigma;
4287 if ((flags & SigmaValue) == 0)
4288 image->y_resolution=image->x_resolution;
4289 }
cristy1626d332009-11-10 16:58:17 +00004290 option=GetImageOption(image_info,"depth");
4291 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004292 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004293 option=GetImageOption(image_info,"endian");
4294 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004295 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004296 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004297 option=GetImageOption(image_info,"filter");
4298 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004299 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004300 MagickFalse,option);
4301 option=GetImageOption(image_info,"fuzz");
4302 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004303 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004304 option=GetImageOption(image_info,"gravity");
4305 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004306 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004307 MagickFalse,option);
4308 option=GetImageOption(image_info,"green-primary");
4309 if (option != (const char *) NULL)
4310 {
4311 flags=ParseGeometry(option,&geometry_info);
4312 image->chromaticity.green_primary.x=geometry_info.rho;
4313 image->chromaticity.green_primary.y=geometry_info.sigma;
4314 if ((flags & SigmaValue) == 0)
4315 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4316 }
4317 option=GetImageOption(image_info,"intent");
4318 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004319 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004320 MagickIntentOptions,MagickFalse,option);
4321 option=GetImageOption(image_info,"interlace");
4322 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004323 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004324 MagickFalse,option);
4325 option=GetImageOption(image_info,"interpolate");
4326 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004327 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004328 MagickInterpolateOptions,MagickFalse,option);
4329 option=GetImageOption(image_info,"loop");
4330 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004331 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004332 option=GetImageOption(image_info,"mattecolor");
4333 if (option != (const char *) NULL)
4334 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4335 option=GetImageOption(image_info,"orient");
4336 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004337 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004338 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004339 option=GetImageOption(image_info,"page");
4340 if (option != (const char *) NULL)
4341 {
4342 char
4343 *geometry;
4344
4345 geometry=GetPageGeometry(option);
4346 flags=ParseAbsoluteGeometry(geometry,&image->page);
4347 geometry=DestroyString(geometry);
4348 }
cristy1626d332009-11-10 16:58:17 +00004349 option=GetImageOption(image_info,"quality");
4350 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004351 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004352 option=GetImageOption(image_info,"red-primary");
4353 if (option != (const char *) NULL)
4354 {
4355 flags=ParseGeometry(option,&geometry_info);
4356 image->chromaticity.red_primary.x=geometry_info.rho;
4357 image->chromaticity.red_primary.y=geometry_info.sigma;
4358 if ((flags & SigmaValue) == 0)
4359 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4360 }
4361 if (image_info->quality != UndefinedCompressionQuality)
4362 image->quality=image_info->quality;
4363 option=GetImageOption(image_info,"scene");
4364 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004365 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004366 option=GetImageOption(image_info,"taint");
4367 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004368 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004369 MagickFalse,option);
4370 option=GetImageOption(image_info,"tile-offset");
4371 if (option != (const char *) NULL)
4372 {
4373 char
4374 *geometry;
4375
4376 geometry=GetPageGeometry(option);
4377 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4378 geometry=DestroyString(geometry);
4379 }
4380 option=GetImageOption(image_info,"transparent-color");
4381 if (option != (const char *) NULL)
4382 (void) QueryColorDatabase(option,&image->transparent_color,
4383 &image->exception);
4384 option=GetImageOption(image_info,"type");
4385 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004386 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004387 option);
4388 option=GetImageOption(image_info,"units");
4389 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004390 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004391 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004392 else
4393 units = image_info->units;
4394 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004395 {
cristy19eb6412010-04-23 14:42:29 +00004396 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004397 switch (image->units)
4398 {
4399 case PixelsPerInchResolution:
4400 {
cristy19eb6412010-04-23 14:42:29 +00004401 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004402 {
4403 image->x_resolution/=2.54;
4404 image->y_resolution/=2.54;
4405 }
4406 break;
4407 }
4408 case PixelsPerCentimeterResolution:
4409 {
cristy19eb6412010-04-23 14:42:29 +00004410 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004411 {
cristybb503372010-05-27 20:51:26 +00004412 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004413 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004414 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004415 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004416 }
4417 break;
4418 }
4419 default:
4420 break;
4421 }
cristy19eb6412010-04-23 14:42:29 +00004422 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004423 }
4424 option=GetImageOption(image_info,"white-point");
4425 if (option != (const char *) NULL)
4426 {
4427 flags=ParseGeometry(option,&geometry_info);
4428 image->chromaticity.white_point.x=geometry_info.rho;
4429 image->chromaticity.white_point.y=geometry_info.sigma;
4430 if ((flags & SigmaValue) == 0)
4431 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4432 }
4433 ResetImageOptionIterator(image_info);
4434 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4435 {
4436 value=GetImageOption(image_info,option);
4437 if (value != (const char *) NULL)
4438 {
cristyb51dff52011-05-19 16:55:47 +00004439 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004440 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004441 }
4442 option=GetNextImageOption(image_info);
4443 }
4444 return(MagickTrue);
4445}