blob: d2bec910f7b6ffeed850bd462c20ab9360498548 [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);
cristy3ed852e2009-09-05 21:47:34 +00002398 (void) SetImageColorspace(image,RGBColorspace);
2399 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,
2500% const AlphaChannelType alpha_type)
2501%
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%
2511*/
2512MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2513 const AlphaChannelType alpha_type)
2514{
2515 MagickBooleanType
2516 status;
2517
2518 assert(image != (Image *) NULL);
2519 if (image->debug != MagickFalse)
2520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2521 assert(image->signature == MagickSignature);
2522 status=MagickFalse;
2523 switch (alpha_type)
2524 {
2525 case ActivateAlphaChannel:
2526 {
2527 image->matte=MagickTrue;
2528 break;
2529 }
2530 case BackgroundAlphaChannel:
2531 {
2532 CacheView
2533 *image_view;
2534
2535 ExceptionInfo
2536 *exception;
2537
cristy3ed852e2009-09-05 21:47:34 +00002538 MagickBooleanType
2539 status;
2540
cristy4c08aed2011-07-01 19:47:50 +00002541 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002542 background;
2543
2544 PixelPacket
2545 pixel;
2546
cristycb6d09b2010-06-19 01:59:36 +00002547 ssize_t
2548 y;
2549
cristy3ed852e2009-09-05 21:47:34 +00002550 /*
2551 Set transparent pixels to background color.
2552 */
2553 if (image->matte == MagickFalse)
2554 break;
cristy47fa6ee2011-08-05 17:35:33 +00002555 exception=(&image->exception);
cristy574cc262011-08-05 01:23:58 +00002556 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002557 break;
cristy4c08aed2011-07-01 19:47:50 +00002558 GetPixelInfo(image,&background);
2559 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002560 if (image->colorspace == CMYKColorspace)
2561 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002562 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002563 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002564 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2566 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002567 #endif
cristybb503372010-05-27 20:51:26 +00002568 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002569 {
cristy4c08aed2011-07-01 19:47:50 +00002570 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002571 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002572
cristycb6d09b2010-06-19 01:59:36 +00002573 register ssize_t
2574 x;
2575
cristy3ed852e2009-09-05 21:47:34 +00002576 if (status == MagickFalse)
2577 continue;
2578 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2579 exception);
cristy4c08aed2011-07-01 19:47:50 +00002580 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002581 {
2582 status=MagickFalse;
2583 continue;
2584 }
cristybb503372010-05-27 20:51:26 +00002585 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002586 {
cristy4c08aed2011-07-01 19:47:50 +00002587 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002588 {
cristy4c08aed2011-07-01 19:47:50 +00002589 SetPixelRed(image,pixel.red,q);
2590 SetPixelGreen(image,pixel.green,q);
2591 SetPixelBlue(image,pixel.blue,q);
2592 if (image->colorspace == CMYKColorspace)
2593 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002594 }
cristyed231572011-07-14 02:18:59 +00002595 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002596 }
cristy3ed852e2009-09-05 21:47:34 +00002597 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2598 status=MagickFalse;
2599 }
2600 image_view=DestroyCacheView(image_view);
2601 return(status);
2602 }
2603 case DeactivateAlphaChannel:
2604 {
2605 image->matte=MagickFalse;
2606 break;
2607 }
2608 case ShapeAlphaChannel:
2609 case CopyAlphaChannel:
2610 {
2611 /*
cristy3139dc22011-07-08 00:11:42 +00002612 Special usage case for SeparateImage(): copy grayscale color to
cristy3ed852e2009-09-05 21:47:34 +00002613 the alpha channel.
2614 */
cristyed231572011-07-14 02:18:59 +00002615 PushPixelChannelMap(image,GrayChannel);
cristy3139dc22011-07-08 00:11:42 +00002616 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002617 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002618 image->matte=MagickTrue; /* make sure transparency is now on! */
2619 if (alpha_type == ShapeAlphaChannel)
2620 {
cristy4c08aed2011-07-01 19:47:50 +00002621 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002622 background;
2623
2624 /*
2625 Reset all color channels to background color.
2626 */
cristy4c08aed2011-07-01 19:47:50 +00002627 GetPixelInfo(image,&background);
2628 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002629 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002630 }
2631 break;
2632 }
2633 case ExtractAlphaChannel:
2634 {
cristyed231572011-07-14 02:18:59 +00002635 PushPixelChannelMap(image,AlphaChannel);
cristy3139dc22011-07-08 00:11:42 +00002636 status=SeparateImage(image);
cristyed231572011-07-14 02:18:59 +00002637 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002638 image->matte=MagickFalse;
2639 break;
2640 }
cristy3ed852e2009-09-05 21:47:34 +00002641 case OpaqueAlphaChannel:
2642 {
cristy4c08aed2011-07-01 19:47:50 +00002643 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002644 image->matte=MagickTrue;
2645 break;
2646 }
2647 case TransparentAlphaChannel:
2648 {
cristy4c08aed2011-07-01 19:47:50 +00002649 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002650 image->matte=MagickTrue;
2651 break;
2652 }
2653 case SetAlphaChannel:
2654 {
2655 if (image->matte == MagickFalse)
2656 {
cristy4c08aed2011-07-01 19:47:50 +00002657 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002658 image->matte=MagickTrue;
2659 }
2660 break;
2661 }
2662 case UndefinedAlphaChannel:
2663 break;
2664 }
2665 return(status);
2666}
2667
2668/*
2669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670% %
2671% %
2672% %
2673% S e t I m a g e B a c k g r o u n d C o l o r %
2674% %
2675% %
2676% %
2677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2678%
2679% SetImageBackgroundColor() initializes the image pixels to the image
2680% background color. The background color is defined by the background_color
2681% member of the image structure.
2682%
2683% The format of the SetImage method is:
2684%
2685% MagickBooleanType SetImageBackgroundColor(Image *image)
2686%
2687% A description of each parameter follows:
2688%
2689% o image: the image.
2690%
2691*/
2692MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2693{
2694 CacheView
2695 *image_view;
2696
2697 ExceptionInfo
2698 *exception;
2699
cristy3ed852e2009-09-05 21:47:34 +00002700 MagickBooleanType
2701 status;
2702
cristy4c08aed2011-07-01 19:47:50 +00002703 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002704 background;
2705
2706 PixelPacket
2707 pixel;
2708
cristycb6d09b2010-06-19 01:59:36 +00002709 ssize_t
2710 y;
2711
cristy3ed852e2009-09-05 21:47:34 +00002712 assert(image != (Image *) NULL);
2713 if (image->debug != MagickFalse)
2714 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2715 assert(image->signature == MagickSignature);
cristy574cc262011-08-05 01:23:58 +00002716 exception=(&image->exception);
2717 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002718 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002719 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002720 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002721 GetPixelInfo(image,&background);
2722 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002723 if (image->colorspace == CMYKColorspace)
2724 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002725 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002726 /*
2727 Set image background color.
2728 */
2729 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002730 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002731 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002732 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002733 {
cristy4c08aed2011-07-01 19:47:50 +00002734 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002735 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002736
cristycb6d09b2010-06-19 01:59:36 +00002737 register ssize_t
2738 x;
2739
cristy3ed852e2009-09-05 21:47:34 +00002740 if (status == MagickFalse)
2741 continue;
2742 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002743 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002744 {
2745 status=MagickFalse;
2746 continue;
2747 }
cristybb503372010-05-27 20:51:26 +00002748 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002749 {
2750 SetPixelPacket(image,&pixel,q);
2751 if (image->colorspace == CMYKColorspace)
2752 SetPixelBlack(image,pixel.black,q);
cristyed231572011-07-14 02:18:59 +00002753 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002754 }
cristy3ed852e2009-09-05 21:47:34 +00002755 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2756 status=MagickFalse;
2757 }
2758 image_view=DestroyCacheView(image_view);
2759 return(status);
2760}
2761
2762/*
2763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2764% %
2765% %
2766% %
cristya5b77cb2010-05-07 19:34:48 +00002767% S e t I m a g e C o l o r %
2768% %
2769% %
2770% %
2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772%
2773% SetImageColor() set the entire image canvas to the specified color.
2774%
2775% The format of the SetImageColor method is:
2776%
cristy08429172011-07-14 17:18:16 +00002777% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002778%
2779% A description of each parameter follows:
2780%
2781% o image: the image.
2782%
2783% o background: the image color.
2784%
2785*/
2786MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002787 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002788{
2789 CacheView
2790 *image_view;
2791
2792 ExceptionInfo
2793 *exception;
2794
cristya5b77cb2010-05-07 19:34:48 +00002795 MagickBooleanType
2796 status;
2797
cristycb6d09b2010-06-19 01:59:36 +00002798 ssize_t
2799 y;
2800
cristya5b77cb2010-05-07 19:34:48 +00002801 assert(image != (Image *) NULL);
2802 if (image->debug != MagickFalse)
2803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2804 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002805 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002806 image->colorspace=color->colorspace;
2807 image->matte=color->matte;
2808 image->fuzz=color->fuzz;
2809 image->depth=color->depth;
2810 status=MagickTrue;
2811 exception=(&image->exception);
2812 image_view=AcquireCacheView(image);
2813#if defined(MAGICKCORE_OPENMP_SUPPORT)
2814 #pragma omp parallel for schedule(dynamic,4) shared(status)
2815#endif
cristybb503372010-05-27 20:51:26 +00002816 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002817 {
cristy4c08aed2011-07-01 19:47:50 +00002818 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002819 *restrict q;
2820
cristycb6d09b2010-06-19 01:59:36 +00002821 register ssize_t
2822 x;
2823
cristya5b77cb2010-05-07 19:34:48 +00002824 if (status == MagickFalse)
2825 continue;
2826 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002827 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002828 {
2829 status=MagickFalse;
2830 continue;
2831 }
cristybb503372010-05-27 20:51:26 +00002832 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002833 {
cristy4c08aed2011-07-01 19:47:50 +00002834 SetPixelPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002835 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002836 }
2837 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2838 status=MagickFalse;
2839 }
2840 image_view=DestroyCacheView(image_view);
2841 return(status);
2842}
2843
2844/*
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846% %
2847% %
2848% %
cristy3ed852e2009-09-05 21:47:34 +00002849% S e t I m a g e S t o r a g e C l a s s %
2850% %
2851% %
2852% %
2853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2854%
2855% SetImageStorageClass() sets the image class: DirectClass for true color
2856% images or PseudoClass for colormapped images.
2857%
2858% The format of the SetImageStorageClass method is:
2859%
2860% MagickBooleanType SetImageStorageClass(Image *image,
2861% const ClassType storage_class)
2862%
2863% A description of each parameter follows:
2864%
2865% o image: the image.
2866%
2867% o storage_class: The image class.
2868%
cristy574cc262011-08-05 01:23:58 +00002869% o exception: return any errors or warnings in this structure.
2870%
cristy3ed852e2009-09-05 21:47:34 +00002871*/
2872MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002873 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002874{
cristy574cc262011-08-05 01:23:58 +00002875 PixelPacket
2876 pixel;
2877
cristy3ed852e2009-09-05 21:47:34 +00002878 image->storage_class=storage_class;
cristy574cc262011-08-05 01:23:58 +00002879 return(GetOneAuthenticPixel(image,0,0,&pixel,exception));
cristy3ed852e2009-09-05 21:47:34 +00002880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
2887% S e t I m a g e C l i p M a s k %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% SetImageClipMask() associates a clip path with the image. The clip path
2894% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002895% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002896% pixel component from being updated when SyncAuthenticPixels() is applied.
2897%
2898% The format of the SetImageClipMask method is:
2899%
2900% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2901%
2902% A description of each parameter follows:
2903%
2904% o image: the image.
2905%
2906% o clip_mask: the image clip path.
2907%
2908*/
2909MagickExport MagickBooleanType SetImageClipMask(Image *image,
2910 const Image *clip_mask)
2911{
2912 assert(image != (Image *) NULL);
2913 if (image->debug != MagickFalse)
2914 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2915 assert(image->signature == MagickSignature);
2916 if (clip_mask != (const Image *) NULL)
2917 if ((clip_mask->columns != image->columns) ||
2918 (clip_mask->rows != image->rows))
2919 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2920 if (image->clip_mask != (Image *) NULL)
2921 image->clip_mask=DestroyImage(image->clip_mask);
2922 image->clip_mask=NewImageList();
2923 if (clip_mask == (Image *) NULL)
2924 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00002925 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002926 return(MagickFalse);
2927 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2928 if (image->clip_mask == (Image *) NULL)
2929 return(MagickFalse);
2930 return(MagickTrue);
2931}
2932
2933/*
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935% %
2936% %
2937% %
2938% S e t I m a g e E x t e n t %
2939% %
2940% %
2941% %
2942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2943%
2944% SetImageExtent() sets the image size (i.e. columns & rows).
2945%
2946% The format of the SetImageExtent method is:
2947%
cristy08429172011-07-14 17:18:16 +00002948% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2949% const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002950%
2951% A description of each parameter follows:
2952%
2953% o image: the image.
2954%
2955% o columns: The image width in pixels.
2956%
2957% o rows: The image height in pixels.
2958%
2959*/
cristy08429172011-07-14 17:18:16 +00002960MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2961 const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002962{
cristy537e2722010-09-21 15:30:59 +00002963 if ((columns == 0) || (rows == 0))
2964 return(MagickFalse);
2965 image->columns=columns;
2966 image->rows=rows;
2967 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002968}
2969
2970/*
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972% %
2973% %
2974% %
2975+ S e t I m a g e I n f o %
2976% %
2977% %
2978% %
2979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980%
2981% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
2982% It is set to a type of image format based on the prefix or suffix of the
2983% filename. For example, `ps:image' returns PS indicating a Postscript image.
2984% JPEG is returned for this filename: `image.jpg'. The filename prefix has
2985% precendence over the suffix. Use an optional index enclosed in brackets
2986% after a file name to specify a desired scene of a multi-resolution image
2987% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2988% indicates success.
2989%
2990% The format of the SetImageInfo method is:
2991%
2992% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002993% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002994%
2995% A description of each parameter follows:
2996%
cristyd965a422010-03-03 17:47:35 +00002997% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002998%
cristyd965a422010-03-03 17:47:35 +00002999% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003000%
3001% o exception: return any errors or warnings in this structure.
3002%
3003*/
3004MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003005 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003006{
3007 char
3008 extension[MaxTextExtent],
3009 filename[MaxTextExtent],
3010 magic[MaxTextExtent],
3011 *q,
3012 subimage[MaxTextExtent];
3013
3014 const MagicInfo
3015 *magic_info;
3016
3017 const MagickInfo
3018 *magick_info;
3019
3020 ExceptionInfo
3021 *sans_exception;
3022
3023 Image
3024 *image;
3025
3026 MagickBooleanType
3027 status;
3028
3029 register const char
3030 *p;
3031
3032 ssize_t
3033 count;
3034
3035 unsigned char
3036 magick[2*MaxTextExtent];
3037
3038 /*
3039 Look for 'image.format' in filename.
3040 */
3041 assert(image_info != (ImageInfo *) NULL);
3042 assert(image_info->signature == MagickSignature);
3043 if (image_info->debug != MagickFalse)
3044 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3045 image_info->filename);
3046 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003047 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003048 {
cristyd965a422010-03-03 17:47:35 +00003049 GetPathComponent(image_info->filename,SubimagePath,subimage);
3050 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003051 {
cristyd965a422010-03-03 17:47:35 +00003052 /*
3053 Look for scene specification (e.g. img0001.pcd[4]).
3054 */
3055 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3056 {
3057 if (IsGeometry(subimage) != MagickFalse)
3058 (void) CloneString(&image_info->extract,subimage);
3059 }
3060 else
3061 {
cristybb503372010-05-27 20:51:26 +00003062 size_t
cristyd965a422010-03-03 17:47:35 +00003063 first,
3064 last;
cristy3ed852e2009-09-05 21:47:34 +00003065
cristyd965a422010-03-03 17:47:35 +00003066 (void) CloneString(&image_info->scenes,subimage);
3067 image_info->scene=StringToUnsignedLong(image_info->scenes);
3068 image_info->number_scenes=image_info->scene;
3069 p=image_info->scenes;
3070 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3071 {
3072 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3073 (*p == ','))
3074 p++;
cristybb503372010-05-27 20:51:26 +00003075 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003076 last=first;
3077 while (isspace((int) ((unsigned char) *q)) != 0)
3078 q++;
3079 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003080 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003081 if (first > last)
3082 Swap(first,last);
3083 if (first < image_info->scene)
3084 image_info->scene=first;
3085 if (last > image_info->number_scenes)
3086 image_info->number_scenes=last;
3087 p=q;
3088 }
3089 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003090 }
cristy3ed852e2009-09-05 21:47:34 +00003091 }
3092 }
3093 *extension='\0';
3094 GetPathComponent(image_info->filename,ExtensionPath,extension);
3095#if defined(MAGICKCORE_ZLIB_DELEGATE)
3096 if (*extension != '\0')
3097 if ((LocaleCompare(extension,"gz") == 0) ||
3098 (LocaleCompare(extension,"Z") == 0) ||
3099 (LocaleCompare(extension,"wmz") == 0))
3100 {
3101 char
3102 path[MaxTextExtent];
3103
3104 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3105 path[strlen(path)-strlen(extension)-1]='\0';
3106 GetPathComponent(path,ExtensionPath,extension);
3107 }
3108#endif
3109#if defined(MAGICKCORE_BZLIB_DELEGATE)
3110 if (*extension != '\0')
3111 if (LocaleCompare(extension,"bz2") == 0)
3112 {
3113 char
3114 path[MaxTextExtent];
3115
3116 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3117 path[strlen(path)-strlen(extension)-1]='\0';
3118 GetPathComponent(path,ExtensionPath,extension);
3119 }
3120#endif
3121 image_info->affirm=MagickFalse;
3122 sans_exception=AcquireExceptionInfo();
3123 if (*extension != '\0')
3124 {
3125 MagickFormatType
3126 format_type;
3127
cristybb503372010-05-27 20:51:26 +00003128 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003129 i;
3130
3131 static const char
3132 *format_type_formats[] =
3133 {
3134 "AUTOTRACE",
3135 "BROWSE",
3136 "DCRAW",
3137 "EDIT",
3138 "EPHEMERAL",
3139 "LAUNCH",
3140 "MPEG:DECODE",
3141 "MPEG:ENCODE",
3142 "PRINT",
3143 "PS:ALPHA",
3144 "PS:CMYK",
3145 "PS:COLOR",
3146 "PS:GRAY",
3147 "PS:MONO",
3148 "SCAN",
3149 "SHOW",
3150 "WIN",
3151 (char *) NULL
3152 };
3153
3154 /*
3155 User specified image format.
3156 */
3157 (void) CopyMagickString(magic,extension,MaxTextExtent);
3158 LocaleUpper(magic);
3159 /*
3160 Look for explicit image formats.
3161 */
3162 format_type=UndefinedFormatType;
3163 i=0;
cristydd9a2532010-02-20 19:26:46 +00003164 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003165 (format_type_formats[i] != (char *) NULL))
3166 {
3167 if ((*magic == *format_type_formats[i]) &&
3168 (LocaleCompare(magic,format_type_formats[i]) == 0))
3169 format_type=ExplicitFormatType;
3170 i++;
3171 }
3172 magick_info=GetMagickInfo(magic,sans_exception);
3173 if ((magick_info != (const MagickInfo *) NULL) &&
3174 (magick_info->format_type != UndefinedFormatType))
3175 format_type=magick_info->format_type;
3176 if (format_type == UndefinedFormatType)
3177 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3178 else
3179 if (format_type == ExplicitFormatType)
3180 {
3181 image_info->affirm=MagickTrue;
3182 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3183 }
3184 if (LocaleCompare(magic,"RGB") == 0)
3185 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3186 }
3187 /*
3188 Look for explicit 'format:image' in filename.
3189 */
3190 *magic='\0';
3191 GetPathComponent(image_info->filename,MagickPath,magic);
3192 if (*magic == '\0')
3193 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3194 else
3195 {
3196 /*
3197 User specified image format.
3198 */
3199 LocaleUpper(magic);
3200 if (IsMagickConflict(magic) == MagickFalse)
3201 {
3202 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3203 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3204 image_info->affirm=MagickTrue;
3205 else
3206 image_info->temporary=MagickTrue;
3207 }
3208 }
3209 magick_info=GetMagickInfo(magic,sans_exception);
3210 sans_exception=DestroyExceptionInfo(sans_exception);
3211 if ((magick_info == (const MagickInfo *) NULL) ||
3212 (GetMagickEndianSupport(magick_info) == MagickFalse))
3213 image_info->endian=UndefinedEndian;
3214 GetPathComponent(image_info->filename,CanonicalPath,filename);
3215 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003216 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003217 {
3218 /*
cristyd965a422010-03-03 17:47:35 +00003219 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003220 */
cristyd965a422010-03-03 17:47:35 +00003221 (void) InterpretImageFilename(image_info,(Image *) NULL,
3222 image_info->filename,(int) image_info->scene,filename);
3223 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3224 (strchr(filename,'%') == (char *) NULL))
3225 image_info->adjoin=MagickFalse;
3226 }
3227 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3228 {
3229 /*
3230 Some image formats do not support multiple frames per file.
3231 */
cristy3ed852e2009-09-05 21:47:34 +00003232 magick_info=GetMagickInfo(magic,exception);
3233 if (magick_info != (const MagickInfo *) NULL)
3234 if (GetMagickAdjoin(magick_info) == MagickFalse)
3235 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003236 }
3237 if (image_info->affirm != MagickFalse)
3238 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003239 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003240 {
3241 /*
cristyd965a422010-03-03 17:47:35 +00003242 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003243 */
cristyd965a422010-03-03 17:47:35 +00003244 image=AcquireImage(image_info);
3245 (void) CopyMagickString(image->filename,image_info->filename,
3246 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003247 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3248 if (status == MagickFalse)
3249 {
3250 image=DestroyImage(image);
3251 return(MagickFalse);
3252 }
cristyd965a422010-03-03 17:47:35 +00003253 if ((IsBlobSeekable(image) == MagickFalse) ||
3254 (IsBlobExempt(image) != MagickFalse))
3255 {
3256 /*
3257 Copy standard input or pipe to temporary file.
3258 */
3259 *filename='\0';
3260 status=ImageToFile(image,filename,exception);
3261 (void) CloseBlob(image);
3262 if (status == MagickFalse)
3263 {
3264 image=DestroyImage(image);
3265 return(MagickFalse);
3266 }
3267 SetImageInfoFile(image_info,(FILE *) NULL);
3268 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3269 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3270 if (status == MagickFalse)
3271 {
3272 image=DestroyImage(image);
3273 return(MagickFalse);
3274 }
3275 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3276 image_info->temporary=MagickTrue;
3277 }
3278 (void) ResetMagickMemory(magick,0,sizeof(magick));
3279 count=ReadBlob(image,2*MaxTextExtent,magick);
3280 (void) CloseBlob(image);
3281 image=DestroyImage(image);
3282 /*
3283 Check magic.xml configuration file.
3284 */
3285 sans_exception=AcquireExceptionInfo();
3286 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3287 if ((magic_info != (const MagicInfo *) NULL) &&
3288 (GetMagicName(magic_info) != (char *) NULL))
3289 {
3290 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3291 MaxTextExtent);
3292 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3293 if ((magick_info == (const MagickInfo *) NULL) ||
3294 (GetMagickEndianSupport(magick_info) == MagickFalse))
3295 image_info->endian=UndefinedEndian;
3296 sans_exception=DestroyExceptionInfo(sans_exception);
3297 return(MagickTrue);
3298 }
cristy3ed852e2009-09-05 21:47:34 +00003299 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3300 if ((magick_info == (const MagickInfo *) NULL) ||
3301 (GetMagickEndianSupport(magick_info) == MagickFalse))
3302 image_info->endian=UndefinedEndian;
3303 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003304 }
cristy3ed852e2009-09-05 21:47:34 +00003305 return(MagickTrue);
3306}
3307
3308/*
3309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3310% %
3311% %
3312% %
3313% S e t I m a g e I n f o B l o b %
3314% %
3315% %
3316% %
3317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3318%
3319% SetImageInfoBlob() sets the image info blob member.
3320%
3321% The format of the SetImageInfoBlob method is:
3322%
3323% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3324% const size_t length)
3325%
3326% A description of each parameter follows:
3327%
3328% o image_info: the image info.
3329%
3330% o blob: the blob.
3331%
3332% o length: the blob length.
3333%
3334*/
3335MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3336 const size_t length)
3337{
3338 assert(image_info != (ImageInfo *) NULL);
3339 assert(image_info->signature == MagickSignature);
3340 if (image_info->debug != MagickFalse)
3341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3342 image_info->filename);
3343 image_info->blob=(void *) blob;
3344 image_info->length=length;
3345}
3346
3347/*
3348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3349% %
3350% %
3351% %
3352% S e t I m a g e I n f o F i l e %
3353% %
3354% %
3355% %
3356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3357%
3358% SetImageInfoFile() sets the image info file member.
3359%
3360% The format of the SetImageInfoFile method is:
3361%
3362% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3363%
3364% A description of each parameter follows:
3365%
3366% o image_info: the image info.
3367%
3368% o file: the file.
3369%
3370*/
3371MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3372{
3373 assert(image_info != (ImageInfo *) NULL);
3374 assert(image_info->signature == MagickSignature);
3375 if (image_info->debug != MagickFalse)
3376 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3377 image_info->filename);
3378 image_info->file=file;
3379}
3380
3381/*
3382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3383% %
3384% %
3385% %
3386% S e t I m a g e M a s k %
3387% %
3388% %
3389% %
3390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391%
3392% SetImageMask() associates a mask with the image. The mask must be the same
3393% dimensions as the image.
3394%
3395% The format of the SetImageMask method is:
3396%
3397% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3398%
3399% A description of each parameter follows:
3400%
3401% o image: the image.
3402%
3403% o mask: the image mask.
3404%
3405*/
3406MagickExport MagickBooleanType SetImageMask(Image *image,
3407 const Image *mask)
3408{
3409 assert(image != (Image *) NULL);
3410 if (image->debug != MagickFalse)
3411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3412 assert(image->signature == MagickSignature);
3413 if (mask != (const Image *) NULL)
3414 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3415 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3416 if (image->mask != (Image *) NULL)
3417 image->mask=DestroyImage(image->mask);
3418 image->mask=NewImageList();
3419 if (mask == (Image *) NULL)
3420 return(MagickTrue);
cristy574cc262011-08-05 01:23:58 +00003421 if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003422 return(MagickFalse);
3423 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3424 if (image->mask == (Image *) NULL)
3425 return(MagickFalse);
3426 return(MagickTrue);
3427}
3428
3429/*
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431% %
3432% %
3433% %
3434% S e t I m a g e O p a c i t y %
3435% %
3436% %
3437% %
3438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439%
3440% SetImageOpacity() sets the opacity levels of the image.
3441%
3442% The format of the SetImageOpacity method is:
3443%
3444% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3445%
3446% A description of each parameter follows:
3447%
3448% o image: the image.
3449%
3450% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3451% fully transparent.
3452%
3453*/
3454MagickExport MagickBooleanType SetImageOpacity(Image *image,
3455 const Quantum opacity)
3456{
3457 CacheView
3458 *image_view;
3459
3460 ExceptionInfo
3461 *exception;
3462
cristy3ed852e2009-09-05 21:47:34 +00003463 MagickBooleanType
3464 status;
3465
cristycb6d09b2010-06-19 01:59:36 +00003466 ssize_t
3467 y;
3468
cristy3ed852e2009-09-05 21:47:34 +00003469 assert(image != (Image *) NULL);
3470 if (image->debug != MagickFalse)
3471 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3472 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003473 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003474 status=MagickTrue;
3475 exception=(&image->exception);
3476 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003477#if defined(MAGICKCORE_OPENMP_SUPPORT)
3478 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003479#endif
cristybb503372010-05-27 20:51:26 +00003480 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003481 {
cristy4c08aed2011-07-01 19:47:50 +00003482 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003483 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003484
cristycb6d09b2010-06-19 01:59:36 +00003485 register ssize_t
3486 x;
3487
cristy3ed852e2009-09-05 21:47:34 +00003488 if (status == MagickFalse)
3489 continue;
3490 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003491 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003492 {
3493 status=MagickFalse;
3494 continue;
3495 }
cristybb503372010-05-27 20:51:26 +00003496 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003497 {
cristy4c08aed2011-07-01 19:47:50 +00003498 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00003499 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003500 }
3501 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3502 status=MagickFalse;
3503 }
3504 image_view=DestroyCacheView(image_view);
3505 return(status);
3506}
3507
3508/*
3509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3510% %
3511% %
3512% %
3513% S e t I m a g e T y p e %
3514% %
3515% %
3516% %
3517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3518%
3519% SetImageType() sets the type of image. Choose from these types:
3520%
3521% Bilevel Grayscale GrayscaleMatte
3522% Palette PaletteMatte TrueColor
3523% TrueColorMatte ColorSeparation ColorSeparationMatte
3524% OptimizeType
3525%
3526% The format of the SetImageType method is:
3527%
3528% MagickBooleanType SetImageType(Image *image,const ImageType type)
3529%
3530% A description of each parameter follows:
3531%
3532% o image: the image.
3533%
3534% o type: Image type.
3535%
3536*/
3537MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3538{
3539 const char
3540 *artifact;
3541
3542 ImageInfo
3543 *image_info;
3544
3545 MagickBooleanType
3546 status;
3547
3548 QuantizeInfo
3549 *quantize_info;
3550
3551 assert(image != (Image *) NULL);
3552 if (image->debug != MagickFalse)
3553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3554 assert(image->signature == MagickSignature);
3555 status=MagickTrue;
3556 image_info=AcquireImageInfo();
3557 image_info->dither=image->dither;
3558 artifact=GetImageArtifact(image,"dither");
3559 if (artifact != (const char *) NULL)
3560 (void) SetImageOption(image_info,"dither",artifact);
3561 switch (type)
3562 {
3563 case BilevelType:
3564 {
cristy4c08aed2011-07-01 19:47:50 +00003565 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003566 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003567 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003568 {
3569 quantize_info=AcquireQuantizeInfo(image_info);
3570 quantize_info->number_colors=2;
3571 quantize_info->colorspace=GRAYColorspace;
3572 status=QuantizeImage(quantize_info,image);
3573 quantize_info=DestroyQuantizeInfo(quantize_info);
3574 }
3575 image->matte=MagickFalse;
3576 break;
3577 }
3578 case GrayscaleType:
3579 {
cristy4c08aed2011-07-01 19:47:50 +00003580 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003581 status=TransformImageColorspace(image,GRAYColorspace);
3582 image->matte=MagickFalse;
3583 break;
3584 }
3585 case GrayscaleMatteType:
3586 {
cristy4c08aed2011-07-01 19:47:50 +00003587 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003588 status=TransformImageColorspace(image,GRAYColorspace);
3589 if (image->matte == MagickFalse)
3590 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3591 break;
3592 }
3593 case PaletteType:
3594 {
cristy510d06a2011-07-06 23:43:54 +00003595 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003596 status=TransformImageColorspace(image,RGBColorspace);
3597 if ((image->storage_class == DirectClass) || (image->colors > 256))
3598 {
3599 quantize_info=AcquireQuantizeInfo(image_info);
3600 quantize_info->number_colors=256;
3601 status=QuantizeImage(quantize_info,image);
3602 quantize_info=DestroyQuantizeInfo(quantize_info);
3603 }
3604 image->matte=MagickFalse;
3605 break;
3606 }
3607 case PaletteBilevelMatteType:
3608 {
cristy510d06a2011-07-06 23:43:54 +00003609 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003610 status=TransformImageColorspace(image,RGBColorspace);
3611 if (image->matte == MagickFalse)
3612 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
cristyed231572011-07-14 02:18:59 +00003613 PushPixelChannelMap(image,AlphaChannel);
cristyf4ad9df2011-07-08 16:49:03 +00003614 (void) BilevelImage(image,(double) QuantumRange/2.0);
cristyed231572011-07-14 02:18:59 +00003615 PopPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00003616 quantize_info=AcquireQuantizeInfo(image_info);
3617 status=QuantizeImage(quantize_info,image);
3618 quantize_info=DestroyQuantizeInfo(quantize_info);
3619 break;
3620 }
3621 case PaletteMatteType:
3622 {
cristy510d06a2011-07-06 23:43:54 +00003623 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003624 status=TransformImageColorspace(image,RGBColorspace);
3625 if (image->matte == MagickFalse)
3626 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3627 quantize_info=AcquireQuantizeInfo(image_info);
3628 quantize_info->colorspace=TransparentColorspace;
3629 status=QuantizeImage(quantize_info,image);
3630 quantize_info=DestroyQuantizeInfo(quantize_info);
3631 break;
3632 }
3633 case TrueColorType:
3634 {
cristy510d06a2011-07-06 23:43:54 +00003635 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003636 status=TransformImageColorspace(image,RGBColorspace);
3637 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003638 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003639 image->matte=MagickFalse;
3640 break;
3641 }
3642 case TrueColorMatteType:
3643 {
cristy510d06a2011-07-06 23:43:54 +00003644 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003645 status=TransformImageColorspace(image,RGBColorspace);
3646 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003647 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003648 if (image->matte == MagickFalse)
3649 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3650 break;
3651 }
3652 case ColorSeparationType:
3653 {
3654 if (image->colorspace != CMYKColorspace)
3655 {
cristy510d06a2011-07-06 23:43:54 +00003656 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003657 status=TransformImageColorspace(image,RGBColorspace);
3658 status=TransformImageColorspace(image,CMYKColorspace);
3659 }
3660 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003661 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003662 image->matte=MagickFalse;
3663 break;
3664 }
3665 case ColorSeparationMatteType:
3666 {
3667 if (image->colorspace != CMYKColorspace)
3668 {
cristy510d06a2011-07-06 23:43:54 +00003669 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003670 status=TransformImageColorspace(image,RGBColorspace);
3671 status=TransformImageColorspace(image,CMYKColorspace);
3672 }
3673 if (image->storage_class != DirectClass)
cristy574cc262011-08-05 01:23:58 +00003674 status=SetImageStorageClass(image,DirectClass,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +00003675 if (image->matte == MagickFalse)
3676 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3677 break;
3678 }
3679 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003680 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003681 break;
3682 }
3683 image->type=type;
3684 image_info=DestroyImageInfo(image_info);
3685 return(status);
3686}
3687
3688/*
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690% %
3691% %
3692% %
3693% S e t I m a g e V i r t u a l P i x e l M e t h o d %
3694% %
3695% %
3696% %
3697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3698%
3699% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3700% image and returns the previous setting. A virtual pixel is any pixel access
3701% that is outside the boundaries of the image cache.
3702%
3703% The format of the SetImageVirtualPixelMethod() method is:
3704%
3705% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3706% const VirtualPixelMethod virtual_pixel_method)
3707%
3708% A description of each parameter follows:
3709%
3710% o image: the image.
3711%
3712% o virtual_pixel_method: choose the type of virtual pixel.
3713%
3714*/
3715MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3716 const VirtualPixelMethod virtual_pixel_method)
3717{
3718 assert(image != (const Image *) NULL);
3719 assert(image->signature == MagickSignature);
3720 if (image->debug != MagickFalse)
3721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3722 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3723}
3724
3725/*
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727% %
3728% %
3729% %
cristy4285d782011-02-09 20:12:28 +00003730% S m u s h I m a g e s %
3731% %
3732% %
3733% %
3734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735%
3736% SmushImages() takes all images from the current image pointer to the end
3737% of the image list and smushes them to each other top-to-bottom if the
3738% stack parameter is true, otherwise left-to-right.
3739%
3740% The current gravity setting now effects how the image is justified in the
3741% final image.
3742%
3743% The format of the SmushImages method is:
3744%
cristy4ca38e22011-02-10 02:57:49 +00003745% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003746% ExceptionInfo *exception)
3747%
3748% A description of each parameter follows:
3749%
cristy4ca38e22011-02-10 02:57:49 +00003750% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003751%
3752% o stack: A value other than 0 stacks the images top-to-bottom.
3753%
3754% o offset: minimum distance in pixels between images.
3755%
3756% o exception: return any errors or warnings in this structure.
3757%
3758*/
cristy4ca38e22011-02-10 02:57:49 +00003759
cristy7c6dc152011-02-11 14:10:55 +00003760static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003761 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003762{
cristy4d727152011-02-10 19:57:21 +00003763 CacheView
3764 *left_view,
3765 *right_view;
3766
3767 const Image
3768 *left_image,
3769 *right_image;
3770
cristy4d727152011-02-10 19:57:21 +00003771 RectangleInfo
3772 left_geometry,
3773 right_geometry;
3774
cristy4c08aed2011-07-01 19:47:50 +00003775 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003776 *p;
3777
cristy4d727152011-02-10 19:57:21 +00003778 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003779 i,
cristy4d727152011-02-10 19:57:21 +00003780 y;
3781
cristy7c6dc152011-02-11 14:10:55 +00003782 size_t
3783 gap;
3784
cristy4d727152011-02-10 19:57:21 +00003785 ssize_t
cristy4d727152011-02-10 19:57:21 +00003786 x;
3787
3788 if (images->previous == (Image *) NULL)
3789 return(0);
3790 right_image=images;
3791 SetGeometry(smush_image,&right_geometry);
3792 GravityAdjustGeometry(right_image->columns,right_image->rows,
3793 right_image->gravity,&right_geometry);
3794 left_image=images->previous;
3795 SetGeometry(smush_image,&left_geometry);
3796 GravityAdjustGeometry(left_image->columns,left_image->rows,
3797 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003798 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003799 left_view=AcquireCacheView(left_image);
3800 right_view=AcquireCacheView(right_image);
3801 for (y=0; y < (ssize_t) smush_image->rows; y++)
3802 {
3803 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3804 {
cristydab7e912011-02-11 18:19:24 +00003805 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003806 if ((p == (const Quantum *) NULL) ||
3807 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003808 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003809 break;
3810 }
cristy4ef6f062011-02-10 20:30:22 +00003811 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003812 for (x=0; x < (ssize_t) right_image->columns; x++)
3813 {
cristydab7e912011-02-11 18:19:24 +00003814 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003815 exception);
cristy4c08aed2011-07-01 19:47:50 +00003816 if ((p == (const Quantum *) NULL) ||
3817 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3818 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003819 break;
3820 }
cristy7c6dc152011-02-11 14:10:55 +00003821 if ((x+i) < (ssize_t) gap)
3822 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003823 }
3824 right_view=DestroyCacheView(right_view);
3825 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003826 if (y < (ssize_t) smush_image->rows)
3827 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003828 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003829}
3830
cristy7c6dc152011-02-11 14:10:55 +00003831static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003832 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003833{
cristy4d727152011-02-10 19:57:21 +00003834 CacheView
3835 *bottom_view,
3836 *top_view;
3837
3838 const Image
3839 *bottom_image,
3840 *top_image;
3841
cristy4d727152011-02-10 19:57:21 +00003842 RectangleInfo
3843 bottom_geometry,
3844 top_geometry;
3845
cristy4c08aed2011-07-01 19:47:50 +00003846 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003847 *p;
3848
cristy4d727152011-02-10 19:57:21 +00003849 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003850 i,
cristy4d727152011-02-10 19:57:21 +00003851 x;
3852
cristy7c6dc152011-02-11 14:10:55 +00003853 size_t
3854 gap;
3855
cristy4d727152011-02-10 19:57:21 +00003856 ssize_t
cristy4d727152011-02-10 19:57:21 +00003857 y;
3858
3859 if (images->previous == (Image *) NULL)
3860 return(0);
3861 bottom_image=images;
3862 SetGeometry(smush_image,&bottom_geometry);
3863 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3864 bottom_image->gravity,&bottom_geometry);
3865 top_image=images->previous;
3866 SetGeometry(smush_image,&top_geometry);
3867 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3868 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003869 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003870 top_view=AcquireCacheView(top_image);
3871 bottom_view=AcquireCacheView(bottom_image);
3872 for (x=0; x < (ssize_t) smush_image->columns; x++)
3873 {
3874 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3875 {
cristydab7e912011-02-11 18:19:24 +00003876 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003877 if ((p == (const Quantum *) NULL) ||
3878 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3879 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003880 break;
3881 }
cristy4ef6f062011-02-10 20:30:22 +00003882 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003883 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3884 {
cristydab7e912011-02-11 18:19:24 +00003885 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3886 exception);
cristy4c08aed2011-07-01 19:47:50 +00003887 if ((p == (const Quantum *) NULL) ||
3888 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3889 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003890 break;
3891 }
cristy7c6dc152011-02-11 14:10:55 +00003892 if ((y+i) < (ssize_t) gap)
3893 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003894 }
3895 bottom_view=DestroyCacheView(bottom_view);
3896 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003897 if (x < (ssize_t) smush_image->columns)
3898 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003899 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003900}
3901
3902MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003903 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3904{
3905#define SmushImageTag "Smush/Image"
3906
3907 CacheView
cristybb5dced2011-02-10 02:17:16 +00003908 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003909
cristy4ca38e22011-02-10 02:57:49 +00003910 const Image
3911 *image;
3912
cristy4285d782011-02-09 20:12:28 +00003913 Image
3914 *smush_image;
3915
3916 MagickBooleanType
3917 matte,
3918 proceed,
3919 status;
3920
3921 MagickOffsetType
3922 n;
3923
3924 RectangleInfo
3925 geometry;
3926
3927 register const Image
3928 *next;
3929
3930 size_t
3931 height,
3932 number_images,
3933 width;
3934
3935 ssize_t
3936 x_offset,
cristy4285d782011-02-09 20:12:28 +00003937 y_offset;
3938
3939 /*
cristy7c6dc152011-02-11 14:10:55 +00003940 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003941 */
cristy4ca38e22011-02-10 02:57:49 +00003942 assert(images != (Image *) NULL);
3943 assert(images->signature == MagickSignature);
3944 if (images->debug != MagickFalse)
3945 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003946 assert(exception != (ExceptionInfo *) NULL);
3947 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003948 image=images;
cristy4285d782011-02-09 20:12:28 +00003949 matte=image->matte;
3950 number_images=1;
3951 width=image->columns;
3952 height=image->rows;
3953 next=GetNextImageInList(image);
3954 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3955 {
3956 if (next->matte != MagickFalse)
3957 matte=MagickTrue;
3958 number_images++;
3959 if (stack != MagickFalse)
3960 {
3961 if (next->columns > width)
3962 width=next->columns;
3963 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003964 if (next->previous != (Image *) NULL)
3965 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003966 continue;
3967 }
3968 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003969 if (next->previous != (Image *) NULL)
3970 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003971 if (next->rows > height)
3972 height=next->rows;
3973 }
3974 /*
cristy7c6dc152011-02-11 14:10:55 +00003975 Smush images.
cristy4285d782011-02-09 20:12:28 +00003976 */
3977 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3978 if (smush_image == (Image *) NULL)
3979 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003980 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003981 {
cristy4285d782011-02-09 20:12:28 +00003982 smush_image=DestroyImage(smush_image);
3983 return((Image *) NULL);
3984 }
3985 smush_image->matte=matte;
3986 (void) SetImageBackgroundColor(smush_image);
3987 status=MagickTrue;
3988 x_offset=0;
3989 y_offset=0;
3990 smush_view=AcquireCacheView(smush_image);
3991 for (n=0; n < (MagickOffsetType) number_images; n++)
3992 {
3993 SetGeometry(smush_image,&geometry);
3994 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3995 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003996 {
3997 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003998 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003999 }
cristy4285d782011-02-09 20:12:28 +00004000 else
cristy4ca38e22011-02-10 02:57:49 +00004001 {
cristy7c6dc152011-02-11 14:10:55 +00004002 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004003 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004004 }
cristybb5dced2011-02-10 02:17:16 +00004005 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004006 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4007 if (proceed == MagickFalse)
4008 break;
4009 if (stack == MagickFalse)
4010 {
4011 x_offset+=(ssize_t) image->columns;
4012 y_offset=0;
4013 }
4014 else
4015 {
4016 x_offset=0;
4017 y_offset+=(ssize_t) image->rows;
4018 }
4019 image=GetNextImageInList(image);
4020 }
cristy4ef6f062011-02-10 20:30:22 +00004021 if (stack == MagickFalse)
4022 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004023 else
cristy4ef6f062011-02-10 20:30:22 +00004024 smush_image->rows=(size_t) y_offset;
4025 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004026 if (status == MagickFalse)
4027 smush_image=DestroyImage(smush_image);
4028 return(smush_image);
4029}
4030
4031/*
4032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4033% %
4034% %
4035% %
cristy3ed852e2009-09-05 21:47:34 +00004036% S t r i p I m a g e %
4037% %
4038% %
4039% %
4040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4041%
cristy376bda92009-12-22 21:15:23 +00004042% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004043%
4044% The format of the StripImage method is:
4045%
4046% MagickBooleanType StripImage(Image *image)
4047%
4048% A description of each parameter follows:
4049%
4050% o image: the image.
4051%
4052*/
4053MagickExport MagickBooleanType StripImage(Image *image)
4054{
4055 assert(image != (Image *) NULL);
4056 if (image->debug != MagickFalse)
4057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4058 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004059 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004060 (void) DeleteImageProperty(image,"date:create");
4061 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004062 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004063 return(MagickTrue);
4064}
4065
4066/*
4067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4068% %
4069% %
4070% %
4071+ S y n c I m a g e %
4072% %
4073% %
4074% %
4075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4076%
4077% SyncImage() initializes the red, green, and blue intensities of each pixel
4078% as defined by the colormap index.
4079%
4080% The format of the SyncImage method is:
4081%
4082% MagickBooleanType SyncImage(Image *image)
4083%
4084% A description of each parameter follows:
4085%
4086% o image: the image.
4087%
4088*/
4089
cristy4c08aed2011-07-01 19:47:50 +00004090static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004091 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004092{
4093 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004094 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004095 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004096 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004097}
4098
4099MagickExport MagickBooleanType SyncImage(Image *image)
4100{
4101 CacheView
4102 *image_view;
4103
4104 ExceptionInfo
4105 *exception;
4106
cristy3ed852e2009-09-05 21:47:34 +00004107 MagickBooleanType
4108 range_exception,
4109 status;
4110
cristycb6d09b2010-06-19 01:59:36 +00004111 ssize_t
4112 y;
4113
cristy3ed852e2009-09-05 21:47:34 +00004114 assert(image != (Image *) NULL);
4115 if (image->debug != MagickFalse)
4116 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4117 assert(image->signature == MagickSignature);
4118 if (image->storage_class == DirectClass)
4119 return(MagickFalse);
4120 range_exception=MagickFalse;
4121 status=MagickTrue;
4122 exception=(&image->exception);
4123 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004124#if defined(MAGICKCORE_OPENMP_SUPPORT)
4125 #pragma omp parallel for schedule(dynamic,4) shared(status)
4126#endif
cristybb503372010-05-27 20:51:26 +00004127 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004128 {
cristy4c08aed2011-07-01 19:47:50 +00004129 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004130 index;
4131
cristy4c08aed2011-07-01 19:47:50 +00004132 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004133 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004134
cristycb6d09b2010-06-19 01:59:36 +00004135 register ssize_t
4136 x;
4137
cristy48974b92009-12-19 02:36:06 +00004138 if (status == MagickFalse)
4139 continue;
cristy3ed852e2009-09-05 21:47:34 +00004140 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004141 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004142 {
4143 status=MagickFalse;
4144 continue;
4145 }
cristybb503372010-05-27 20:51:26 +00004146 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004147 {
cristy4c08aed2011-07-01 19:47:50 +00004148 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004149 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004150 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00004151 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004152 }
4153 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4154 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004155 }
4156 image_view=DestroyCacheView(image_view);
4157 if (range_exception != MagickFalse)
4158 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4159 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4160 return(status);
4161}
cristy1626d332009-11-10 16:58:17 +00004162
4163/*
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165% %
4166% %
4167% %
4168% S y n c I m a g e S e t t i n g s %
4169% %
4170% %
4171% %
4172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173%
4174% SyncImageSettings() sync the image info options to the image.
4175%
4176% The format of the SyncImageSettings method is:
4177%
4178% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4179% Image *image)
4180% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4181% Image *image)
4182%
4183% A description of each parameter follows:
4184%
4185% o image_info: the image info.
4186%
4187% o image: the image.
4188%
4189*/
4190
4191MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4192 Image *images)
4193{
4194 Image
4195 *image;
4196
4197 assert(image_info != (const ImageInfo *) NULL);
4198 assert(image_info->signature == MagickSignature);
4199 assert(images != (Image *) NULL);
4200 assert(images->signature == MagickSignature);
4201 if (images->debug != MagickFalse)
4202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4203 image=images;
4204 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4205 (void) SyncImageSettings(image_info,image);
4206 (void) DeleteImageOption(image_info,"page");
4207 return(MagickTrue);
4208}
4209
4210MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4211 Image *image)
4212{
4213 char
4214 property[MaxTextExtent];
4215
4216 const char
cristy9a703812010-07-26 14:50:29 +00004217 *option,
4218 *value;
cristy1626d332009-11-10 16:58:17 +00004219
4220 GeometryInfo
4221 geometry_info;
4222
4223 MagickStatusType
4224 flags;
4225
cristy19eb6412010-04-23 14:42:29 +00004226 ResolutionType
4227 units;
4228
cristy1626d332009-11-10 16:58:17 +00004229 /*
4230 Sync image options.
4231 */
4232 assert(image_info != (const ImageInfo *) NULL);
4233 assert(image_info->signature == MagickSignature);
4234 assert(image != (Image *) NULL);
4235 assert(image->signature == MagickSignature);
4236 if (image->debug != MagickFalse)
4237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4238 option=GetImageOption(image_info,"background");
4239 if (option != (const char *) NULL)
4240 (void) QueryColorDatabase(option,&image->background_color,
4241 &image->exception);
4242 option=GetImageOption(image_info,"bias");
4243 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004244 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004245 option=GetImageOption(image_info,"black-point-compensation");
4246 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004247 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004248 MagickBooleanOptions,MagickFalse,option);
4249 option=GetImageOption(image_info,"blue-primary");
4250 if (option != (const char *) NULL)
4251 {
4252 flags=ParseGeometry(option,&geometry_info);
4253 image->chromaticity.blue_primary.x=geometry_info.rho;
4254 image->chromaticity.blue_primary.y=geometry_info.sigma;
4255 if ((flags & SigmaValue) == 0)
4256 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4257 }
4258 option=GetImageOption(image_info,"bordercolor");
4259 if (option != (const char *) NULL)
4260 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4261 option=GetImageOption(image_info,"colors");
4262 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004263 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004264 option=GetImageOption(image_info,"compose");
4265 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004266 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004267 MagickFalse,option);
4268 option=GetImageOption(image_info,"compress");
4269 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004270 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004271 MagickCompressOptions,MagickFalse,option);
4272 option=GetImageOption(image_info,"debug");
4273 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004274 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004275 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004276 option=GetImageOption(image_info,"density");
4277 if (option != (const char *) NULL)
4278 {
4279 GeometryInfo
4280 geometry_info;
4281
4282 /*
4283 Set image density.
4284 */
4285 flags=ParseGeometry(option,&geometry_info);
4286 image->x_resolution=geometry_info.rho;
4287 image->y_resolution=geometry_info.sigma;
4288 if ((flags & SigmaValue) == 0)
4289 image->y_resolution=image->x_resolution;
4290 }
cristy1626d332009-11-10 16:58:17 +00004291 option=GetImageOption(image_info,"depth");
4292 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004293 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004294 option=GetImageOption(image_info,"endian");
4295 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004296 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004297 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004298 option=GetImageOption(image_info,"filter");
4299 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004300 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004301 MagickFalse,option);
4302 option=GetImageOption(image_info,"fuzz");
4303 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004304 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004305 option=GetImageOption(image_info,"gravity");
4306 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004307 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004308 MagickFalse,option);
4309 option=GetImageOption(image_info,"green-primary");
4310 if (option != (const char *) NULL)
4311 {
4312 flags=ParseGeometry(option,&geometry_info);
4313 image->chromaticity.green_primary.x=geometry_info.rho;
4314 image->chromaticity.green_primary.y=geometry_info.sigma;
4315 if ((flags & SigmaValue) == 0)
4316 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4317 }
4318 option=GetImageOption(image_info,"intent");
4319 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004320 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004321 MagickIntentOptions,MagickFalse,option);
4322 option=GetImageOption(image_info,"interlace");
4323 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004324 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004325 MagickFalse,option);
4326 option=GetImageOption(image_info,"interpolate");
4327 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004328 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004329 MagickInterpolateOptions,MagickFalse,option);
4330 option=GetImageOption(image_info,"loop");
4331 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004332 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004333 option=GetImageOption(image_info,"mattecolor");
4334 if (option != (const char *) NULL)
4335 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4336 option=GetImageOption(image_info,"orient");
4337 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004338 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004339 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004340 option=GetImageOption(image_info,"page");
4341 if (option != (const char *) NULL)
4342 {
4343 char
4344 *geometry;
4345
4346 geometry=GetPageGeometry(option);
4347 flags=ParseAbsoluteGeometry(geometry,&image->page);
4348 geometry=DestroyString(geometry);
4349 }
cristy1626d332009-11-10 16:58:17 +00004350 option=GetImageOption(image_info,"quality");
4351 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004352 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004353 option=GetImageOption(image_info,"red-primary");
4354 if (option != (const char *) NULL)
4355 {
4356 flags=ParseGeometry(option,&geometry_info);
4357 image->chromaticity.red_primary.x=geometry_info.rho;
4358 image->chromaticity.red_primary.y=geometry_info.sigma;
4359 if ((flags & SigmaValue) == 0)
4360 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4361 }
4362 if (image_info->quality != UndefinedCompressionQuality)
4363 image->quality=image_info->quality;
4364 option=GetImageOption(image_info,"scene");
4365 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004366 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004367 option=GetImageOption(image_info,"taint");
4368 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004369 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004370 MagickFalse,option);
4371 option=GetImageOption(image_info,"tile-offset");
4372 if (option != (const char *) NULL)
4373 {
4374 char
4375 *geometry;
4376
4377 geometry=GetPageGeometry(option);
4378 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4379 geometry=DestroyString(geometry);
4380 }
4381 option=GetImageOption(image_info,"transparent-color");
4382 if (option != (const char *) NULL)
4383 (void) QueryColorDatabase(option,&image->transparent_color,
4384 &image->exception);
4385 option=GetImageOption(image_info,"type");
4386 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004387 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004388 option);
4389 option=GetImageOption(image_info,"units");
4390 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004391 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004392 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004393 else
4394 units = image_info->units;
4395 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004396 {
cristy19eb6412010-04-23 14:42:29 +00004397 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004398 switch (image->units)
4399 {
4400 case PixelsPerInchResolution:
4401 {
cristy19eb6412010-04-23 14:42:29 +00004402 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004403 {
4404 image->x_resolution/=2.54;
4405 image->y_resolution/=2.54;
4406 }
4407 break;
4408 }
4409 case PixelsPerCentimeterResolution:
4410 {
cristy19eb6412010-04-23 14:42:29 +00004411 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004412 {
cristybb503372010-05-27 20:51:26 +00004413 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004414 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004415 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004416 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004417 }
4418 break;
4419 }
4420 default:
4421 break;
4422 }
cristy19eb6412010-04-23 14:42:29 +00004423 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004424 }
4425 option=GetImageOption(image_info,"white-point");
4426 if (option != (const char *) NULL)
4427 {
4428 flags=ParseGeometry(option,&geometry_info);
4429 image->chromaticity.white_point.x=geometry_info.rho;
4430 image->chromaticity.white_point.y=geometry_info.sigma;
4431 if ((flags & SigmaValue) == 0)
4432 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4433 }
4434 ResetImageOptionIterator(image_info);
4435 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4436 {
4437 value=GetImageOption(image_info,option);
4438 if (value != (const char *) NULL)
4439 {
cristyb51dff52011-05-19 16:55:47 +00004440 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004441 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004442 }
4443 option=GetNextImageOption(image_info);
4444 }
4445 return(MagickTrue);
4446}