blob: 377599b55cf541a01e8b114d791c4061161de50c [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*/
43#include "magick/studio.h"
44#include "magick/animate.h"
45#include "magick/artifact.h"
46#include "magick/blob.h"
47#include "magick/blob-private.h"
48#include "magick/cache.h"
49#include "magick/cache-private.h"
50#include "magick/cache-view.h"
51#include "magick/client.h"
52#include "magick/color.h"
53#include "magick/color-private.h"
cristy316d5172009-09-17 19:31:25 +000054#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000055#include "magick/colorspace.h"
56#include "magick/colorspace-private.h"
57#include "magick/composite.h"
58#include "magick/composite-private.h"
59#include "magick/compress.h"
60#include "magick/constitute.h"
61#include "magick/deprecate.h"
62#include "magick/display.h"
63#include "magick/draw.h"
64#include "magick/enhance.h"
65#include "magick/exception.h"
66#include "magick/exception-private.h"
67#include "magick/gem.h"
68#include "magick/geometry.h"
cristyf2e11662009-10-14 01:24:43 +000069#include "magick/histogram.h"
cristy3ed852e2009-09-05 21:47:34 +000070#include "magick/image-private.h"
cristyf2e11662009-10-14 01:24:43 +000071#include "magick/list.h"
cristy3ed852e2009-09-05 21:47:34 +000072#include "magick/magic.h"
73#include "magick/magick.h"
74#include "magick/memory_.h"
75#include "magick/module.h"
76#include "magick/monitor.h"
77#include "magick/monitor-private.h"
78#include "magick/option.h"
79#include "magick/paint.h"
80#include "magick/pixel-private.h"
81#include "magick/profile.h"
82#include "magick/property.h"
83#include "magick/quantize.h"
84#include "magick/random_.h"
85#include "magick/segment.h"
86#include "magick/semaphore.h"
87#include "magick/signature-private.h"
88#include "magick/statistic.h"
89#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000090#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000091#include "magick/thread-private.h"
92#include "magick/threshold.h"
93#include "magick/timer.h"
94#include "magick/utility.h"
95#include "magick/version.h"
96#include "magick/xwindow-private.h"
97
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);
188 image->blob=CloneBlobInfo((BlobInfo *) NULL);
189 image->debug=IsEventLogging();
190 image->reference_count=1;
191 image->semaphore=AllocateSemaphoreInfo();
192 image->signature=MagickSignature;
193 if (image_info == (ImageInfo *) NULL)
194 return(image);
195 /*
196 Transfer image info.
197 */
198 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
199 MagickFalse);
200 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
201 (void) CopyMagickString(image->magick_filename,image_info->filename,
202 MaxTextExtent);
203 (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
204 if (image_info->size != (char *) NULL)
205 {
206 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
207 image->columns=image->extract_info.width;
208 image->rows=image->extract_info.height;
209 image->offset=image->extract_info.x;
210 image->extract_info.x=0;
211 image->extract_info.y=0;
212 }
213 if (image_info->extract != (char *) NULL)
214 {
215 RectangleInfo
216 geometry;
217
218 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
219 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
220 {
221 image->extract_info=geometry;
222 Swap(image->columns,image->extract_info.width);
223 Swap(image->rows,image->extract_info.height);
224 }
225 }
226 image->compression=image_info->compression;
227 image->quality=image_info->quality;
228 image->endian=image_info->endian;
229 image->interlace=image_info->interlace;
230 image->units=image_info->units;
231 if (image_info->density != (char *) NULL)
232 {
233 GeometryInfo
234 geometry_info;
235
236 flags=ParseGeometry(image_info->density,&geometry_info);
237 image->x_resolution=geometry_info.rho;
238 image->y_resolution=geometry_info.sigma;
239 if ((flags & SigmaValue) == 0)
240 image->y_resolution=image->x_resolution;
241 }
242 if (image_info->page != (char *) NULL)
243 {
244 char
245 *geometry;
246
247 image->page=image->extract_info;
248 geometry=GetPageGeometry(image_info->page);
249 (void) ParseAbsoluteGeometry(geometry,&image->page);
250 geometry=DestroyString(geometry);
251 }
252 if (image_info->depth != 0)
253 image->depth=image_info->depth;
254 image->dither=image_info->dither;
255 image->background_color=image_info->background_color;
256 image->border_color=image_info->border_color;
257 image->matte_color=image_info->matte_color;
258 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000259 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000260 image->progress_monitor=image_info->progress_monitor;
261 image->client_data=image_info->client_data;
262 if (image_info->cache != (void *) NULL)
263 ClonePixelCacheMethods(image->cache,image_info->cache);
264 (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
cristy6b9aca12010-02-21 01:50:11 +0000265 (void) SyncImageSettings(image_info,image);
cristye412c892010-07-26 12:31:36 +0000266 option=GetImageOption(image_info,"delay");
267 if (option != (const char *) NULL)
268 {
269 GeometryInfo
270 geometry_info;
271
272 flags=ParseGeometry(option,&geometry_info);
273 if ((flags & GreaterValue) != 0)
274 {
275 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
276 image->delay=(size_t) floor(geometry_info.rho+0.5);
277 }
278 else
279 if ((flags & LessValue) != 0)
280 {
281 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
282 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
283 }
284 else
285 image->delay=(size_t) floor(geometry_info.rho+0.5);
286 if ((flags & SigmaValue) != 0)
287 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
288 }
289 option=GetImageOption(image_info,"dispose");
290 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000291 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
cristye412c892010-07-26 12:31:36 +0000292 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000293 return(image);
294}
295
296/*
297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298% %
299% %
300% %
cristy3ed852e2009-09-05 21:47:34 +0000301% A c q u i r e I m a g e I n f o %
302% %
303% %
304% %
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306%
307% AcquireImageInfo() allocates the ImageInfo structure.
308%
309% The format of the AcquireImageInfo method is:
310%
311% ImageInfo *AcquireImageInfo(void)
312%
313*/
314MagickExport ImageInfo *AcquireImageInfo(void)
315{
316 ImageInfo
317 *image_info;
318
cristy73bd4a52010-10-05 11:24:23 +0000319 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000320 if (image_info == (ImageInfo *) NULL)
321 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
322 GetImageInfo(image_info);
323 return(image_info);
324}
325
326/*
327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328% %
329% %
330% %
331% A c q u i r e N e x t I m a g e %
332% %
333% %
334% %
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336%
337% AcquireNextImage() initializes the next image in a sequence to
338% default values. The next member of image points to the newly allocated
339% image. If there is a memory shortage, next is assigned NULL.
340%
341% The format of the AcquireNextImage method is:
342%
343% void AcquireNextImage(const ImageInfo *image_info,Image *image)
344%
345% A description of each parameter follows:
346%
347% o image_info: Many of the image default values are set from this
348% structure. For example, filename, compression, depth, background color,
349% and others.
350%
351% o image: the image.
352%
353*/
354MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
355{
356 /*
357 Allocate image structure.
358 */
359 assert(image != (Image *) NULL);
360 assert(image->signature == MagickSignature);
361 if (image->debug != MagickFalse)
362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
363 image->next=AcquireImage(image_info);
364 if (GetNextImageInList(image) == (Image *) NULL)
365 return;
366 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
367 MaxTextExtent);
368 if (image_info != (ImageInfo *) NULL)
369 (void) CopyMagickString(GetNextImageInList(image)->filename,
370 image_info->filename,MaxTextExtent);
371 DestroyBlob(GetNextImageInList(image));
372 image->next->blob=ReferenceBlob(image->blob);
373 image->next->endian=image->endian;
374 image->next->scene=image->scene+1;
375 image->next->previous=image;
376}
377
378/*
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380% %
381% %
382% %
383% A p p e n d I m a g e s %
384% %
385% %
386% %
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388%
389% AppendImages() takes all images from the current image pointer to the end
390% of the image list and appends them to each other top-to-bottom if the
391% stack parameter is true, otherwise left-to-right.
392%
393% The current gravity setting now effects how the image is justified in the
394% final image.
395%
396% The format of the AppendImages method is:
397%
cristy4ca38e22011-02-10 02:57:49 +0000398% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000399% ExceptionInfo *exception)
400%
401% A description of each parameter follows:
402%
cristy4ca38e22011-02-10 02:57:49 +0000403% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000404%
405% o stack: A value other than 0 stacks the images top-to-bottom.
406%
407% o exception: return any errors or warnings in this structure.
408%
409*/
cristy4ca38e22011-02-10 02:57:49 +0000410MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000411 const MagickBooleanType stack,ExceptionInfo *exception)
412{
413#define AppendImageTag "Append/Image"
414
415 CacheView
416 *append_view,
417 *image_view;
418
cristy4ca38e22011-02-10 02:57:49 +0000419 const Image
420 *image;
421
cristy3ed852e2009-09-05 21:47:34 +0000422 Image
423 *append_image;
424
cristy3ed852e2009-09-05 21:47:34 +0000425 MagickBooleanType
426 matte,
427 proceed,
428 status;
429
cristybb503372010-05-27 20:51:26 +0000430 MagickOffsetType
431 n;
432
cristy3ed852e2009-09-05 21:47:34 +0000433 RectangleInfo
434 geometry;
435
436 register const Image
437 *next;
438
cristybb503372010-05-27 20:51:26 +0000439 size_t
cristy3ed852e2009-09-05 21:47:34 +0000440 height,
441 number_images,
442 width;
443
cristybb503372010-05-27 20:51:26 +0000444 ssize_t
445 x_offset,
446 y,
447 y_offset;
448
cristy3ed852e2009-09-05 21:47:34 +0000449 /*
cristy7c6dc152011-02-11 14:10:55 +0000450 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000451 */
cristy4ca38e22011-02-10 02:57:49 +0000452 assert(images != (Image *) NULL);
453 assert(images->signature == MagickSignature);
454 if (images->debug != MagickFalse)
455 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000456 assert(exception != (ExceptionInfo *) NULL);
457 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +0000458 image=images;
cristy3ed852e2009-09-05 21:47:34 +0000459 matte=image->matte;
460 number_images=1;
461 width=image->columns;
462 height=image->rows;
463 next=GetNextImageInList(image);
464 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
465 {
466 if (next->matte != MagickFalse)
467 matte=MagickTrue;
468 number_images++;
469 if (stack != MagickFalse)
470 {
471 if (next->columns > width)
472 width=next->columns;
473 height+=next->rows;
474 continue;
475 }
476 width+=next->columns;
477 if (next->rows > height)
478 height=next->rows;
479 }
480 /*
cristy7c6dc152011-02-11 14:10:55 +0000481 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000482 */
483 append_image=CloneImage(image,width,height,MagickTrue,exception);
484 if (append_image == (Image *) NULL)
485 return((Image *) NULL);
486 if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
487 {
488 InheritException(exception,&append_image->exception);
489 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
515 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000516 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000517
518 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000519 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000520
521 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000522 *restrict append_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000523
cristy3ed852e2009-09-05 21:47:34 +0000524 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000525 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000526
cristycb6d09b2010-06-19 01:59:36 +0000527 register ssize_t
528 x;
529
cristy3ed852e2009-09-05 21:47:34 +0000530 if (status == MagickFalse)
531 continue;
532 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
533 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
534 image->columns,1,exception);
535 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
536 {
537 status=MagickFalse;
538 continue;
539 }
540 indexes=GetCacheViewVirtualIndexQueue(image_view);
541 append_indexes=GetCacheViewAuthenticIndexQueue(append_view);
cristybb503372010-05-27 20:51:26 +0000542 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000543 {
cristyce70c172010-01-07 17:15:30 +0000544 SetRedPixelComponent(q,GetRedPixelComponent(p));
545 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
546 SetBluePixelComponent(q,GetBluePixelComponent(p));
547 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +0000548 if (image->matte != MagickFalse)
cristyce70c172010-01-07 17:15:30 +0000549 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristyff775322011-02-24 15:05:25 +0000550 if ((image->colorspace == CMYKColorspace) &&
551 (append_image->colorspace == CMYKColorspace))
cristyc8d25bc2011-04-29 02:19:30 +0000552 SetIndexPixelComponent(append_indexes+x,GetIndexPixelComponent(
553 indexes+x));
cristy3ed852e2009-09-05 21:47:34 +0000554 p++;
555 q++;
556 }
557 sync=SyncCacheViewAuthenticPixels(append_view,exception);
558 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000559 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000560 }
561 image_view=DestroyCacheView(image_view);
562 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
563 if (proceed == MagickFalse)
564 break;
565 if (stack == MagickFalse)
566 {
cristyeaedf062010-05-29 22:36:02 +0000567 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000568 y_offset=0;
569 }
570 else
571 {
572 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000573 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000574 }
575 image=GetNextImageInList(image);
576 }
577 append_view=DestroyCacheView(append_view);
578 if (status == MagickFalse)
579 append_image=DestroyImage(append_image);
580 return(append_image);
581}
582
583/*
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585% %
586% %
587% %
cristy3ed852e2009-09-05 21:47:34 +0000588% C a t c h I m a g e E x c e p t i o n %
589% %
590% %
591% %
592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593%
594% CatchImageException() returns if no exceptions are found in the image
595% sequence, otherwise it determines the most severe exception and reports
596% it as a warning or error depending on the severity.
597%
598% The format of the CatchImageException method is:
599%
600% ExceptionType CatchImageException(Image *image)
601%
602% A description of each parameter follows:
603%
604% o image: An image sequence.
605%
606*/
607MagickExport ExceptionType CatchImageException(Image *image)
608{
609 ExceptionInfo
610 *exception;
611
612 ExceptionType
613 severity;
614
615 assert(image != (const Image *) NULL);
616 assert(image->signature == MagickSignature);
617 if (image->debug != MagickFalse)
618 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
619 exception=AcquireExceptionInfo();
620 GetImageException(image,exception);
621 CatchException(exception);
622 severity=exception->severity;
623 exception=DestroyExceptionInfo(exception);
624 return(severity);
625}
626
627/*
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629% %
630% %
631% %
632% C l i p I m a g e P a t h %
633% %
634% %
635% %
636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637%
638% ClipImagePath() sets the image clip mask based any clipping path information
639% if it exists.
640%
641% The format of the ClipImagePath method is:
642%
643% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
644% const MagickBooleanType inside)
645%
646% A description of each parameter follows:
647%
648% o image: the image.
649%
650% o pathname: name of clipping path resource. If name is preceded by #, use
651% clipping path numbered by name.
652%
653% o inside: if non-zero, later operations take effect inside clipping path.
654% Otherwise later operations take effect outside clipping path.
655%
656*/
657
658MagickExport MagickBooleanType ClipImage(Image *image)
659{
660 return(ClipImagePath(image,"#1",MagickTrue));
661}
662
663MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
664 const MagickBooleanType inside)
665{
666#define ClipImagePathTag "ClipPath/Image"
667
668 char
669 *property;
670
671 const char
672 *value;
673
674 Image
675 *clip_mask;
676
677 ImageInfo
678 *image_info;
679
680 assert(image != (const Image *) NULL);
681 assert(image->signature == MagickSignature);
682 if (image->debug != MagickFalse)
683 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
684 assert(pathname != NULL);
685 property=AcquireString(pathname);
cristyb51dff52011-05-19 16:55:47 +0000686 (void) FormatLocaleString(property,MaxTextExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000687 pathname);
688 value=GetImageProperty(image,property);
689 property=DestroyString(property);
690 if (value == (const char *) NULL)
691 {
692 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
693 image->filename);
694 return(MagickFalse);
695 }
696 image_info=AcquireImageInfo();
697 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
698 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
699 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
700 image_info=DestroyImageInfo(image_info);
701 if (clip_mask == (Image *) NULL)
702 return(MagickFalse);
703 if (clip_mask->storage_class == PseudoClass)
704 {
705 (void) SyncImage(clip_mask);
706 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
707 return(MagickFalse);
708 }
709 if (inside == MagickFalse)
710 (void) NegateImage(clip_mask,MagickFalse);
cristyb51dff52011-05-19 16:55:47 +0000711 (void) FormatLocaleString(clip_mask->magick_filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000712 "8BIM:1999,2998:%s\nPS",pathname);
713 (void) SetImageClipMask(image,clip_mask);
714 clip_mask=DestroyImage(clip_mask);
715 return(MagickTrue);
716}
717
718/*
719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720% %
721% %
722% %
723% C l o n e I m a g e %
724% %
725% %
726% %
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728%
729% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000730%
cristy3ed852e2009-09-05 21:47:34 +0000731% If the specified columns and rows is 0, an exact copy of the image is
732% returned, otherwise the pixel data is undefined and must be initialized
733% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
734% failure, a NULL image is returned and exception describes the reason for the
735% failure.
736%
737% The format of the CloneImage method is:
738%
cristybb503372010-05-27 20:51:26 +0000739% Image *CloneImage(const Image *image,const size_t columns,
740% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000741% ExceptionInfo *exception)
742%
743% A description of each parameter follows:
744%
745% o image: the image.
746%
747% o columns: the number of columns in the cloned image.
748%
749% o rows: the number of rows in the cloned image.
750%
751% o detach: With a value other than 0, the cloned image is detached from
752% its parent I/O stream.
753%
754% o exception: return any errors or warnings in this structure.
755%
756*/
cristybb503372010-05-27 20:51:26 +0000757MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000758 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000759{
760 Image
761 *clone_image;
762
763 MagickRealType
764 scale;
765
766 size_t
767 length;
768
769 /*
770 Clone the image.
771 */
772 assert(image != (const Image *) NULL);
773 assert(image->signature == MagickSignature);
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
776 assert(exception != (ExceptionInfo *) NULL);
777 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000778 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000779 if (clone_image == (Image *) NULL)
780 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
781 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
782 clone_image->signature=MagickSignature;
783 clone_image->storage_class=image->storage_class;
cristy1fe256f2011-04-26 11:36:04 +0000784 clone_image->channels=image->channels;
cristy3ed852e2009-09-05 21:47:34 +0000785 clone_image->colorspace=image->colorspace;
786 clone_image->matte=image->matte;
787 clone_image->columns=image->columns;
788 clone_image->rows=image->rows;
789 clone_image->dither=image->dither;
790 if (image->colormap != (PixelPacket *) NULL)
791 {
792 /*
793 Allocate and copy the image colormap.
794 */
795 clone_image->colors=image->colors;
796 length=(size_t) image->colors;
797 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
798 sizeof(*clone_image->colormap));
799 if (clone_image->colormap == (PixelPacket *) NULL)
800 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
801 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
802 sizeof(*clone_image->colormap));
803 }
804 (void) CloneImageProfiles(clone_image,image);
805 (void) CloneImageProperties(clone_image,image);
806 (void) CloneImageArtifacts(clone_image,image);
807 GetTimerInfo(&clone_image->timer);
808 GetExceptionInfo(&clone_image->exception);
809 InheritException(&clone_image->exception,&image->exception);
810 if (image->ascii85 != (void *) NULL)
811 Ascii85Initialize(clone_image);
812 clone_image->magick_columns=image->magick_columns;
813 clone_image->magick_rows=image->magick_rows;
814 clone_image->type=image->type;
815 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
816 MaxTextExtent);
817 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
818 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
819 clone_image->progress_monitor=image->progress_monitor;
820 clone_image->client_data=image->client_data;
821 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000822 clone_image->next=image->next;
823 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000824 clone_image->list=NewImageList();
825 clone_image->clip_mask=NewImageList();
826 clone_image->mask=NewImageList();
827 if (detach == MagickFalse)
828 clone_image->blob=ReferenceBlob(image->blob);
829 else
cristybee00932011-01-15 20:28:27 +0000830 {
831 clone_image->next=NewImageList();
832 clone_image->previous=NewImageList();
833 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
834 }
cristy73724512010-04-12 14:43:14 +0000835 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000836 clone_image->debug=IsEventLogging();
837 clone_image->semaphore=AllocateSemaphoreInfo();
838 if ((columns == 0) && (rows == 0))
839 {
840 if (image->montage != (char *) NULL)
841 (void) CloneString(&clone_image->montage,image->montage);
842 if (image->directory != (char *) NULL)
843 (void) CloneString(&clone_image->directory,image->directory);
844 if (image->clip_mask != (Image *) NULL)
845 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
846 exception);
847 if (image->mask != (Image *) NULL)
848 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
849 clone_image->cache=ReferencePixelCache(image->cache);
850 return(clone_image);
851 }
cristy1ab35fb2011-04-15 01:25:56 +0000852 if ((columns == image->columns) && (rows == image->rows))
853 {
854 if (image->clip_mask != (Image *) NULL)
855 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
856 exception);
857 if (image->mask != (Image *) NULL)
858 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
859 }
cristy3ed852e2009-09-05 21:47:34 +0000860 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000861 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
862 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
863 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000864 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000865 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
866 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
867 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000868 clone_image->columns=columns;
869 clone_image->rows=rows;
870 clone_image->cache=ClonePixelCache(image->cache);
871 return(clone_image);
872}
873
874/*
875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
876% %
877% %
878% %
879% C l o n e I m a g e I n f o %
880% %
881% %
882% %
883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
884%
885% CloneImageInfo() makes a copy of the given image info structure. If
886% NULL is specified, a new image info structure is created initialized to
887% default values.
888%
889% The format of the CloneImageInfo method is:
890%
891% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
892%
893% A description of each parameter follows:
894%
895% o image_info: the image info.
896%
897*/
898MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
899{
900 ImageInfo
901 *clone_info;
902
903 clone_info=AcquireImageInfo();
904 if (image_info == (ImageInfo *) NULL)
905 return(clone_info);
906 clone_info->compression=image_info->compression;
907 clone_info->temporary=image_info->temporary;
908 clone_info->adjoin=image_info->adjoin;
909 clone_info->antialias=image_info->antialias;
910 clone_info->scene=image_info->scene;
911 clone_info->number_scenes=image_info->number_scenes;
912 clone_info->depth=image_info->depth;
913 if (image_info->size != (char *) NULL)
914 (void) CloneString(&clone_info->size,image_info->size);
915 if (image_info->extract != (char *) NULL)
916 (void) CloneString(&clone_info->extract,image_info->extract);
917 if (image_info->scenes != (char *) NULL)
918 (void) CloneString(&clone_info->scenes,image_info->scenes);
919 if (image_info->page != (char *) NULL)
920 (void) CloneString(&clone_info->page,image_info->page);
921 clone_info->interlace=image_info->interlace;
922 clone_info->endian=image_info->endian;
923 clone_info->units=image_info->units;
924 clone_info->quality=image_info->quality;
925 if (image_info->sampling_factor != (char *) NULL)
926 (void) CloneString(&clone_info->sampling_factor,
927 image_info->sampling_factor);
928 if (image_info->server_name != (char *) NULL)
929 (void) CloneString(&clone_info->server_name,image_info->server_name);
930 if (image_info->font != (char *) NULL)
931 (void) CloneString(&clone_info->font,image_info->font);
932 if (image_info->texture != (char *) NULL)
933 (void) CloneString(&clone_info->texture,image_info->texture);
934 if (image_info->density != (char *) NULL)
935 (void) CloneString(&clone_info->density,image_info->density);
936 clone_info->pointsize=image_info->pointsize;
937 clone_info->fuzz=image_info->fuzz;
938 clone_info->pen=image_info->pen;
939 clone_info->background_color=image_info->background_color;
940 clone_info->border_color=image_info->border_color;
941 clone_info->matte_color=image_info->matte_color;
942 clone_info->transparent_color=image_info->transparent_color;
943 clone_info->dither=image_info->dither;
944 clone_info->monochrome=image_info->monochrome;
945 clone_info->colors=image_info->colors;
946 clone_info->colorspace=image_info->colorspace;
947 clone_info->type=image_info->type;
948 clone_info->orientation=image_info->orientation;
949 clone_info->preview_type=image_info->preview_type;
950 clone_info->group=image_info->group;
951 clone_info->ping=image_info->ping;
952 clone_info->verbose=image_info->verbose;
953 if (image_info->view != (char *) NULL)
954 (void) CloneString(&clone_info->view,image_info->view);
955 if (image_info->authenticate != (char *) NULL)
956 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
957 (void) CloneImageOptions(clone_info,image_info);
958 clone_info->progress_monitor=image_info->progress_monitor;
959 clone_info->client_data=image_info->client_data;
960 clone_info->cache=image_info->cache;
961 if (image_info->cache != (void *) NULL)
962 clone_info->cache=ReferencePixelCache(image_info->cache);
963 if (image_info->profile != (void *) NULL)
964 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
965 image_info->profile);
966 SetImageInfoFile(clone_info,image_info->file);
967 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
968 clone_info->stream=image_info->stream;
969 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
970 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
971 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
972 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
973 (void) CopyMagickString(clone_info->filename,image_info->filename,
974 MaxTextExtent);
975 clone_info->subimage=image_info->scene; /* deprecated */
976 clone_info->subrange=image_info->number_scenes; /* deprecated */
977 clone_info->channel=image_info->channel;
978 clone_info->debug=IsEventLogging();
979 clone_info->signature=image_info->signature;
980 return(clone_info);
981}
982
983/*
984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985% %
986% %
987% %
988% C o m b i n e I m a g e s %
989% %
990% %
991% %
992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993%
994% CombineImages() combines one or more images into a single image. The
995% grayscale value of the pixels of each image in the sequence is assigned in
996% order to the specified channels of the combined image. The typical
997% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
998%
999% The format of the CombineImages method is:
1000%
1001% Image *CombineImages(const Image *image,const ChannelType channel,
1002% ExceptionInfo *exception)
1003%
1004% A description of each parameter follows:
1005%
1006% o image: the image.
1007%
1008% o exception: return any errors or warnings in this structure.
1009%
1010*/
1011MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1012 ExceptionInfo *exception)
1013{
1014#define CombineImageTag "Combine/Image"
1015
1016 CacheView
1017 *combine_view;
1018
1019 const Image
1020 *next;
1021
1022 Image
1023 *combine_image;
1024
cristy3ed852e2009-09-05 21:47:34 +00001025 MagickBooleanType
1026 status;
1027
cristybb503372010-05-27 20:51:26 +00001028 MagickOffsetType
1029 progress;
1030
1031 ssize_t
1032 y;
1033
cristy3ed852e2009-09-05 21:47:34 +00001034 /*
1035 Ensure the image are the same size.
1036 */
1037 assert(image != (const Image *) NULL);
1038 assert(image->signature == MagickSignature);
1039 if (image->debug != MagickFalse)
1040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1041 assert(exception != (ExceptionInfo *) NULL);
1042 assert(exception->signature == MagickSignature);
1043 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1044 {
1045 if ((next->columns != image->columns) || (next->rows != image->rows))
1046 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1047 }
1048 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1049 if (combine_image == (Image *) NULL)
1050 return((Image *) NULL);
1051 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1052 {
1053 InheritException(exception,&combine_image->exception);
1054 combine_image=DestroyImage(combine_image);
1055 return((Image *) NULL);
1056 }
1057 if ((channel & OpacityChannel) != 0)
1058 combine_image->matte=MagickTrue;
1059 (void) SetImageBackgroundColor(combine_image);
1060 /*
1061 Combine images.
1062 */
1063 status=MagickTrue;
1064 progress=0;
1065 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001066 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001067 {
1068 CacheView
1069 *image_view;
1070
1071 const Image
1072 *next;
1073
1074 PixelPacket
1075 *pixels;
1076
1077 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001078 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001079
cristy3ed852e2009-09-05 21:47:34 +00001080 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001081 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001082
cristycb6d09b2010-06-19 01:59:36 +00001083 register ssize_t
1084 x;
1085
cristy3ed852e2009-09-05 21:47:34 +00001086 if (status == MagickFalse)
1087 continue;
1088 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1089 1,exception);
1090 if (pixels == (PixelPacket *) NULL)
1091 {
1092 status=MagickFalse;
1093 continue;
1094 }
1095 next=image;
1096 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
1097 {
1098 image_view=AcquireCacheView(next);
1099 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1100 if (p == (const PixelPacket *) NULL)
1101 continue;
1102 q=pixels;
cristybb503372010-05-27 20:51:26 +00001103 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
cristyce70c172010-01-07 17:15:30 +00001105 SetRedPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001106 p++;
1107 q++;
1108 }
1109 image_view=DestroyCacheView(image_view);
1110 next=GetNextImageInList(next);
1111 }
1112 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
1113 {
1114 image_view=AcquireCacheView(next);
1115 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1116 if (p == (const PixelPacket *) NULL)
1117 continue;
1118 q=pixels;
cristybb503372010-05-27 20:51:26 +00001119 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001120 {
cristyce70c172010-01-07 17:15:30 +00001121 SetGreenPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001122 p++;
1123 q++;
1124 }
1125 image_view=DestroyCacheView(image_view);
1126 next=GetNextImageInList(next);
1127 }
1128 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
1129 {
1130 image_view=AcquireCacheView(next);
1131 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1132 if (p == (const PixelPacket *) NULL)
1133 continue;
1134 q=pixels;
cristybb503372010-05-27 20:51:26 +00001135 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001136 {
cristyce70c172010-01-07 17:15:30 +00001137 SetBluePixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001138 p++;
1139 q++;
1140 }
1141 image_view=DestroyCacheView(image_view);
1142 next=GetNextImageInList(next);
1143 }
1144 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
1145 {
1146 image_view=AcquireCacheView(next);
1147 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1148 if (p == (const PixelPacket *) NULL)
1149 continue;
1150 q=pixels;
cristybb503372010-05-27 20:51:26 +00001151 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001152 {
cristyce70c172010-01-07 17:15:30 +00001153 SetOpacityPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001154 p++;
1155 q++;
1156 }
1157 image_view=DestroyCacheView(image_view);
1158 next=GetNextImageInList(next);
1159 }
1160 if (((channel & IndexChannel) != 0) &&
1161 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1162 {
1163 IndexPacket
1164 *indexes;
1165
1166 image_view=AcquireCacheView(next);
1167 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1168 if (p == (const PixelPacket *) NULL)
1169 continue;
1170 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
cristybb503372010-05-27 20:51:26 +00001171 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001172 {
cristyc8d25bc2011-04-29 02:19:30 +00001173 SetIndexPixelComponent(indexes+x,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001174 p++;
1175 }
1176 image_view=DestroyCacheView(image_view);
1177 next=GetNextImageInList(next);
1178 }
1179 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1180 status=MagickFalse;
1181 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1182 {
1183 MagickBooleanType
1184 proceed;
1185
cristy3ed852e2009-09-05 21:47:34 +00001186 proceed=SetImageProgress(image,CombineImageTag,progress++,
1187 combine_image->rows);
1188 if (proceed == MagickFalse)
1189 status=MagickFalse;
1190 }
1191 }
1192 combine_view=DestroyCacheView(combine_view);
1193 if (status == MagickFalse)
1194 combine_image=DestroyImage(combine_image);
1195 return(combine_image);
1196}
1197
1198/*
1199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200% %
1201% %
1202% %
cristy3ed852e2009-09-05 21:47:34 +00001203% D e s t r o y I m a g e %
1204% %
1205% %
1206% %
1207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208%
1209% DestroyImage() dereferences an image, deallocating memory associated with
1210% the image if the reference count becomes zero.
1211%
1212% The format of the DestroyImage method is:
1213%
1214% Image *DestroyImage(Image *image)
1215%
1216% A description of each parameter follows:
1217%
1218% o image: the image.
1219%
1220*/
1221MagickExport Image *DestroyImage(Image *image)
1222{
1223 MagickBooleanType
1224 destroy;
1225
1226 /*
1227 Dereference image.
1228 */
1229 assert(image != (Image *) NULL);
1230 assert(image->signature == MagickSignature);
1231 if (image->debug != MagickFalse)
1232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1233 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001234 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001235 image->reference_count--;
1236 if (image->reference_count == 0)
1237 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001238 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001239 if (destroy == MagickFalse)
1240 return((Image *) NULL);
1241 /*
1242 Destroy image.
1243 */
1244 DestroyImagePixels(image);
1245 if (image->clip_mask != (Image *) NULL)
1246 image->clip_mask=DestroyImage(image->clip_mask);
1247 if (image->mask != (Image *) NULL)
1248 image->mask=DestroyImage(image->mask);
1249 if (image->montage != (char *) NULL)
1250 image->montage=DestroyString(image->montage);
1251 if (image->directory != (char *) NULL)
1252 image->directory=DestroyString(image->directory);
1253 if (image->colormap != (PixelPacket *) NULL)
1254 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1255 if (image->geometry != (char *) NULL)
1256 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001257 DestroyImageProfiles(image);
1258 DestroyImageProperties(image);
1259 DestroyImageArtifacts(image);
1260 if (image->ascii85 != (Ascii85Info*) NULL)
1261 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1262 DestroyBlob(image);
1263 (void) DestroyExceptionInfo(&image->exception);
1264 if (image->semaphore != (SemaphoreInfo *) NULL)
1265 DestroySemaphoreInfo(&image->semaphore);
1266 image->signature=(~MagickSignature);
1267 image=(Image *) RelinquishMagickMemory(image);
1268 return(image);
1269}
1270
1271/*
1272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1273% %
1274% %
1275% %
1276% D e s t r o y I m a g e I n f o %
1277% %
1278% %
1279% %
1280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281%
1282% DestroyImageInfo() deallocates memory associated with an ImageInfo
1283% structure.
1284%
1285% The format of the DestroyImageInfo method is:
1286%
1287% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1288%
1289% A description of each parameter follows:
1290%
1291% o image_info: the image info.
1292%
1293*/
1294MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1295{
1296 assert(image_info != (ImageInfo *) NULL);
1297 assert(image_info->signature == MagickSignature);
1298 if (image_info->debug != MagickFalse)
1299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1300 image_info->filename);
1301 if (image_info->size != (char *) NULL)
1302 image_info->size=DestroyString(image_info->size);
1303 if (image_info->extract != (char *) NULL)
1304 image_info->extract=DestroyString(image_info->extract);
1305 if (image_info->scenes != (char *) NULL)
1306 image_info->scenes=DestroyString(image_info->scenes);
1307 if (image_info->page != (char *) NULL)
1308 image_info->page=DestroyString(image_info->page);
1309 if (image_info->sampling_factor != (char *) NULL)
1310 image_info->sampling_factor=DestroyString(
1311 image_info->sampling_factor);
1312 if (image_info->server_name != (char *) NULL)
1313 image_info->server_name=DestroyString(
1314 image_info->server_name);
1315 if (image_info->font != (char *) NULL)
1316 image_info->font=DestroyString(image_info->font);
1317 if (image_info->texture != (char *) NULL)
1318 image_info->texture=DestroyString(image_info->texture);
1319 if (image_info->density != (char *) NULL)
1320 image_info->density=DestroyString(image_info->density);
1321 if (image_info->view != (char *) NULL)
1322 image_info->view=DestroyString(image_info->view);
1323 if (image_info->authenticate != (char *) NULL)
1324 image_info->authenticate=DestroyString(
1325 image_info->authenticate);
1326 DestroyImageOptions(image_info);
1327 if (image_info->cache != (void *) NULL)
1328 image_info->cache=DestroyPixelCache(image_info->cache);
1329 if (image_info->profile != (StringInfo *) NULL)
1330 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1331 image_info->profile);
1332 image_info->signature=(~MagickSignature);
1333 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1334 return(image_info);
1335}
1336
1337/*
1338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339% %
1340% %
1341% %
1342+ D i s a s s o c i a t e I m a g e S t r e a m %
1343% %
1344% %
1345% %
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347%
1348% DisassociateImageStream() disassociates the image stream.
1349%
1350% The format of the DisassociateImageStream method is:
1351%
1352% MagickBooleanType DisassociateImageStream(const Image *image)
1353%
1354% A description of each parameter follows:
1355%
1356% o image: the image.
1357%
1358*/
1359MagickExport void DisassociateImageStream(Image *image)
1360{
1361 assert(image != (const Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 if (image->debug != MagickFalse)
1364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1365 (void) DetachBlob(image->blob);
1366}
1367
1368/*
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370% %
1371% %
1372% %
1373% G e t I m a g e A l p h a C h a n n e l %
1374% %
1375% %
1376% %
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378%
1379% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1380% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1381% than CMYKA.
1382%
1383% The format of the GetImageAlphaChannel method is:
1384%
1385% MagickBooleanType GetImageAlphaChannel(const Image *image)
1386%
1387% A description of each parameter follows:
1388%
1389% o image: the image.
1390%
1391*/
1392MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1393{
1394 assert(image != (const Image *) NULL);
1395 if (image->debug != MagickFalse)
1396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1397 assert(image->signature == MagickSignature);
1398 return(image->matte);
1399}
1400
1401/*
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403% %
1404% %
1405% %
1406% G e t I m a g e C l i p M a s k %
1407% %
1408% %
1409% %
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411%
1412% GetImageClipMask() returns the clip path associated with the image.
1413%
1414% The format of the GetImageClipMask method is:
1415%
1416% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1417%
1418% A description of each parameter follows:
1419%
1420% o image: the image.
1421%
1422*/
1423MagickExport Image *GetImageClipMask(const Image *image,
1424 ExceptionInfo *exception)
1425{
1426 assert(image != (const Image *) NULL);
1427 if (image->debug != MagickFalse)
1428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1429 assert(image->signature == MagickSignature);
1430 if (image->clip_mask == (Image *) NULL)
1431 return((Image *) NULL);
1432 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440% G e t I m a g e E x c e p t i o n %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% GetImageException() traverses an image sequence and returns any
1447% error more severe than noted by the exception parameter.
1448%
1449% The format of the GetImageException method is:
1450%
1451% void GetImageException(Image *image,ExceptionInfo *exception)
1452%
1453% A description of each parameter follows:
1454%
1455% o image: Specifies a pointer to a list of one or more images.
1456%
1457% o exception: return the highest severity exception.
1458%
1459*/
1460MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1461{
1462 register Image
1463 *next;
1464
1465 assert(image != (Image *) NULL);
1466 assert(image->signature == MagickSignature);
1467 if (image->debug != MagickFalse)
1468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1469 assert(exception != (ExceptionInfo *) NULL);
1470 assert(exception->signature == MagickSignature);
1471 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1472 {
1473 if (next->exception.severity == UndefinedException)
1474 continue;
1475 if (next->exception.severity > exception->severity)
1476 InheritException(exception,&next->exception);
1477 next->exception.severity=UndefinedException;
1478 }
1479}
1480
1481/*
1482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483% %
1484% %
1485% %
1486% G e t I m a g e I n f o %
1487% %
1488% %
1489% %
1490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1491%
1492% GetImageInfo() initializes image_info to default values.
1493%
1494% The format of the GetImageInfo method is:
1495%
1496% void GetImageInfo(ImageInfo *image_info)
1497%
1498% A description of each parameter follows:
1499%
1500% o image_info: the image info.
1501%
1502*/
1503MagickExport void GetImageInfo(ImageInfo *image_info)
1504{
cristyd9a29192010-10-16 16:49:53 +00001505 const char
1506 *synchronize;
1507
cristy3ed852e2009-09-05 21:47:34 +00001508 ExceptionInfo
1509 *exception;
1510
1511 /*
1512 File and image dimension members.
1513 */
1514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1515 assert(image_info != (ImageInfo *) NULL);
1516 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1517 image_info->adjoin=MagickTrue;
1518 image_info->interlace=NoInterlace;
1519 image_info->channel=DefaultChannels;
1520 image_info->quality=UndefinedCompressionQuality;
1521 image_info->antialias=MagickTrue;
1522 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001523 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1524 if (synchronize != (const char *) NULL)
1525 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001526 exception=AcquireExceptionInfo();
1527 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1528 exception);
1529 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1530 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1531 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1532 exception);
1533 exception=DestroyExceptionInfo(exception);
1534 image_info->debug=IsEventLogging();
1535 image_info->signature=MagickSignature;
1536}
1537
1538/*
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540% %
1541% %
1542% %
cristy15781e52009-12-05 23:05:27 +00001543% G e t I m a g e I n f o F i l e %
1544% %
1545% %
1546% %
1547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548%
1549% GetImageInfoFile() returns the image info file member.
1550%
1551% The format of the GetImageInfoFile method is:
1552%
1553% FILE *GetImageInfoFile(const ImageInfo *image_info)
1554%
1555% A description of each parameter follows:
1556%
1557% o image_info: the image info.
1558%
1559*/
1560MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1561{
1562 return(image_info->file);
1563}
1564
1565/*
1566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567% %
1568% %
1569% %
cristy3ed852e2009-09-05 21:47:34 +00001570% G e t I m a g e M a s k %
1571% %
1572% %
1573% %
1574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575%
1576% GetImageMask() returns the mask associated with the image.
1577%
1578% The format of the GetImageMask method is:
1579%
1580% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1581%
1582% A description of each parameter follows:
1583%
1584% o image: the image.
1585%
1586*/
1587MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1588{
1589 assert(image != (const Image *) NULL);
1590 if (image->debug != MagickFalse)
1591 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1592 assert(image->signature == MagickSignature);
1593 if (image->mask == (Image *) NULL)
1594 return((Image *) NULL);
1595 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1596}
1597
1598/*
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600% %
1601% %
1602% %
cristy0d267172011-04-25 20:13:48 +00001603% G e t I m a g e C h a n n e l s %
1604% %
1605% %
1606% %
1607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608%
cristy6cb60a52011-04-25 20:33:58 +00001609% GetImageChannels() returns the number of pixel channels associated with the
1610% specified image.
cristy0d267172011-04-25 20:13:48 +00001611%
1612% The format of the GetChannels method is:
1613%
1614% size_t GetImageChannels(Image *image)
1615%
1616% A description of each parameter follows:
1617%
1618% o image: the image.
1619%
1620*/
1621MagickExport size_t GetImageChannels(Image *image)
1622{
1623 assert(image != (Image *) NULL);
1624 assert(image->signature == MagickSignature);
1625 if (image->debug != MagickFalse)
1626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1627 return(image->channels);
1628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
cristy3ed852e2009-09-05 21:47:34 +00001635+ G e t I m a g e R e f e r e n c e C o u n t %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% GetImageReferenceCount() returns the image reference count.
1642%
1643% The format of the GetReferenceCount method is:
1644%
cristybb503372010-05-27 20:51:26 +00001645% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001646%
1647% A description of each parameter follows:
1648%
1649% o image: the image.
1650%
1651*/
cristybb503372010-05-27 20:51:26 +00001652MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001653{
cristybb503372010-05-27 20:51:26 +00001654 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001655 reference_count;
1656
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
1659 if (image->debug != MagickFalse)
1660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001661 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001662 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001663 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001664 return(reference_count);
1665}
1666
1667/*
1668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669% %
1670% %
1671% %
cristy3ed852e2009-09-05 21:47:34 +00001672% 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 %
1673% %
1674% %
1675% %
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677%
1678% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1679% image. A virtual pixel is any pixel access that is outside the boundaries
1680% of the image cache.
1681%
1682% The format of the GetImageVirtualPixelMethod() method is:
1683%
1684% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1685%
1686% A description of each parameter follows:
1687%
1688% o image: the image.
1689%
1690*/
1691MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1692{
1693 assert(image != (Image *) NULL);
1694 assert(image->signature == MagickSignature);
1695 if (image->debug != MagickFalse)
1696 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1697 return(GetPixelCacheVirtualMethod(image));
1698}
1699
1700/*
1701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1702% %
1703% %
1704% %
1705% I n t e r p r e t I m a g e F i l e n a m e %
1706% %
1707% %
1708% %
1709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1710%
1711% InterpretImageFilename() interprets embedded characters in an image filename.
1712% The filename length is returned.
1713%
1714% The format of the InterpretImageFilename method is:
1715%
1716% size_t InterpretImageFilename(const ImageInfo *image_info,
1717% Image *image,const char *format,int value,char *filename)
1718%
1719% A description of each parameter follows.
1720%
1721% o image_info: the image info..
1722%
1723% o image: the image.
1724%
1725% o format: A filename describing the format to use to write the numeric
1726% argument. Only the first numeric format identifier is replaced.
1727%
1728% o value: Numeric value to substitute into format filename.
1729%
1730% o filename: return the formatted filename in this character buffer.
1731%
1732*/
1733MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1734 Image *image,const char *format,int value,char *filename)
1735{
1736 char
1737 *q;
1738
1739 int
1740 c;
1741
1742 MagickBooleanType
1743 canonical;
1744
1745 register const char
1746 *p;
1747
1748 canonical=MagickFalse;
1749 (void) CopyMagickString(filename,format,MaxTextExtent);
1750 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1751 {
1752 q=(char *) p+1;
1753 if (*q == '%')
1754 {
1755 p=q+1;
1756 continue;
1757 }
1758 if (*q == '0')
1759 {
cristybb503372010-05-27 20:51:26 +00001760 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001761 value;
1762
cristybb503372010-05-27 20:51:26 +00001763 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001764 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001765 }
1766 switch (*q)
1767 {
1768 case 'd':
1769 case 'o':
1770 case 'x':
1771 {
1772 q++;
1773 c=(*q);
1774 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001775 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001776 (p-format)),p,value);
1777 *q=c;
1778 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1779 canonical=MagickTrue;
1780 if (*(q-1) != '%')
1781 break;
1782 p++;
1783 break;
1784 }
1785 case '[':
1786 {
1787 char
1788 pattern[MaxTextExtent];
1789
1790 const char
1791 *value;
1792
cristy3ed852e2009-09-05 21:47:34 +00001793 register char
1794 *r;
1795
cristybb503372010-05-27 20:51:26 +00001796 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001797 i;
1798
cristycb6d09b2010-06-19 01:59:36 +00001799 ssize_t
1800 depth;
1801
cristy3ed852e2009-09-05 21:47:34 +00001802 /*
1803 Image option.
1804 */
1805 if (strchr(p,']') == (char *) NULL)
1806 break;
1807 depth=1;
1808 r=q+1;
1809 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1810 {
1811 if (*r == '[')
1812 depth++;
1813 if (*r == ']')
1814 depth--;
1815 if (depth <= 0)
1816 break;
1817 pattern[i]=(*r++);
1818 }
1819 pattern[i]='\0';
1820 if (LocaleNCompare(pattern,"filename:",9) != 0)
1821 break;
1822 value=(const char *) NULL;
1823 if ((image_info != (const ImageInfo *) NULL) &&
1824 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001825 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001826 else
1827 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001828 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001829 else
1830 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001831 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001832 if (value == (const char *) NULL)
1833 break;
1834 q--;
1835 c=(*q);
1836 *q='\0';
1837 (void) CopyMagickString(filename+(p-format),value,(size_t)
1838 (MaxTextExtent-(p-format)));
1839 *q=c;
1840 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1841 canonical=MagickTrue;
1842 if (*(q-1) != '%')
1843 break;
1844 p++;
1845 break;
1846 }
1847 default:
1848 break;
1849 }
1850 }
1851 for (q=filename; *q != '\0'; q++)
1852 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001853 {
1854 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1855 canonical=MagickTrue;
1856 }
cristy3ed852e2009-09-05 21:47:34 +00001857 if (canonical == MagickFalse)
1858 (void) CopyMagickString(filename,format,MaxTextExtent);
1859 return(strlen(filename));
1860}
1861
1862/*
1863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864% %
1865% %
1866% %
1867% I s H i g h D y n a m i c R a n g e I m a g e %
1868% %
1869% %
1870% %
1871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1872%
1873% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1874% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1875% 0..65535.
1876%
1877% The format of the IsHighDynamicRangeImage method is:
1878%
1879% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1880% ExceptionInfo *exception)
1881%
1882% A description of each parameter follows:
1883%
1884% o image: the image.
1885%
1886% o exception: return any errors or warnings in this structure.
1887%
1888*/
1889MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1890 ExceptionInfo *exception)
1891{
1892#if !defined(MAGICKCORE_HDRI_SUPPORT)
1893 (void) image;
1894 (void) exception;
1895 return(MagickFalse);
1896#else
1897 CacheView
1898 *image_view;
1899
cristy3ed852e2009-09-05 21:47:34 +00001900 MagickBooleanType
1901 status;
1902
1903 MagickPixelPacket
1904 zero;
1905
cristycb6d09b2010-06-19 01:59:36 +00001906 ssize_t
1907 y;
1908
cristy3ed852e2009-09-05 21:47:34 +00001909 assert(image != (Image *) NULL);
1910 assert(image->signature == MagickSignature);
1911 if (image->debug != MagickFalse)
1912 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1913 status=MagickTrue;
1914 GetMagickPixelPacket(image,&zero);
1915 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001916#if defined(MAGICKCORE_OPENMP_SUPPORT)
1917 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001918#endif
cristybb503372010-05-27 20:51:26 +00001919 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001920 {
1921 MagickPixelPacket
1922 pixel;
1923
1924 register const IndexPacket
1925 *indexes;
1926
1927 register const PixelPacket
1928 *p;
1929
cristybb503372010-05-27 20:51:26 +00001930 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001931 x;
1932
1933 if (status == MagickFalse)
1934 continue;
1935 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1936 if (p == (const PixelPacket *) NULL)
1937 {
1938 status=MagickFalse;
1939 continue;
1940 }
1941 indexes=GetCacheViewVirtualIndexQueue(image_view);
1942 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001943 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001944 {
1945 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1946 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1947 (pixel.red != (QuantumAny) pixel.red))
1948 break;
1949 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1950 (pixel.green != (QuantumAny) pixel.green))
1951 break;
1952 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1953 (pixel.blue != (QuantumAny) pixel.blue))
1954 break;
1955 if (pixel.matte != MagickFalse)
1956 {
1957 if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
1958 (pixel.opacity != (QuantumAny) pixel.opacity))
1959 break;
1960 }
1961 if (pixel.colorspace == CMYKColorspace)
1962 {
1963 if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
1964 (pixel.index != (QuantumAny) pixel.index))
1965 break;
1966 }
1967 p++;
1968 }
cristybb503372010-05-27 20:51:26 +00001969 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001970 status=MagickFalse;
1971 }
1972 image_view=DestroyCacheView(image_view);
1973 return(status != MagickFalse ? MagickFalse : MagickTrue);
1974#endif
1975}
1976
1977/*
1978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979% %
1980% %
1981% %
1982% I s I m a g e O b j e c t %
1983% %
1984% %
1985% %
1986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987%
1988% IsImageObject() returns MagickTrue if the image sequence contains a valid
1989% set of image objects.
1990%
1991% The format of the IsImageObject method is:
1992%
1993% MagickBooleanType IsImageObject(const Image *image)
1994%
1995% A description of each parameter follows:
1996%
1997% o image: the image.
1998%
1999*/
2000MagickExport MagickBooleanType IsImageObject(const Image *image)
2001{
2002 register const Image
2003 *p;
2004
2005 assert(image != (Image *) NULL);
2006 if (image->debug != MagickFalse)
2007 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2008 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2009 if (p->signature != MagickSignature)
2010 return(MagickFalse);
2011 return(MagickTrue);
2012}
2013
2014/*
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% %
2017% %
2018% %
2019% I s T a i n t I m a g e %
2020% %
2021% %
2022% %
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024%
2025% IsTaintImage() returns MagickTrue any pixel in the image has been altered
2026% since it was first constituted.
2027%
2028% The format of the IsTaintImage method is:
2029%
2030% MagickBooleanType IsTaintImage(const Image *image)
2031%
2032% A description of each parameter follows:
2033%
2034% o image: the image.
2035%
2036*/
2037MagickExport MagickBooleanType IsTaintImage(const Image *image)
2038{
2039 char
2040 magick[MaxTextExtent],
2041 filename[MaxTextExtent];
2042
2043 register const Image
2044 *p;
2045
2046 assert(image != (Image *) NULL);
2047 if (image->debug != MagickFalse)
2048 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2049 assert(image->signature == MagickSignature);
2050 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2051 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2052 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2053 {
2054 if (p->taint != MagickFalse)
2055 return(MagickTrue);
2056 if (LocaleCompare(p->magick,magick) != 0)
2057 return(MagickTrue);
2058 if (LocaleCompare(p->filename,filename) != 0)
2059 return(MagickTrue);
2060 }
2061 return(MagickFalse);
2062}
2063
2064/*
2065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066% %
2067% %
2068% %
2069% M o d i f y I m a g e %
2070% %
2071% %
2072% %
2073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2074%
2075% ModifyImage() ensures that there is only a single reference to the image
2076% to be modified, updating the provided image pointer to point to a clone of
2077% the original image if necessary.
2078%
2079% The format of the ModifyImage method is:
2080%
2081% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2082%
2083% A description of each parameter follows:
2084%
2085% o image: the image.
2086%
2087% o exception: return any errors or warnings in this structure.
2088%
2089*/
2090MagickExport MagickBooleanType ModifyImage(Image **image,
2091 ExceptionInfo *exception)
2092{
2093 Image
2094 *clone_image;
2095
2096 assert(image != (Image **) NULL);
2097 assert(*image != (Image *) NULL);
2098 assert((*image)->signature == MagickSignature);
2099 if ((*image)->debug != MagickFalse)
2100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2101 if (GetImageReferenceCount(*image) <= 1)
2102 return(MagickTrue);
2103 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002104 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002105 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002106 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002107 *image=clone_image;
2108 return(MagickTrue);
2109}
2110
2111/*
2112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113% %
2114% %
2115% %
2116% N e w M a g i c k I m a g e %
2117% %
2118% %
2119% %
2120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121%
2122% NewMagickImage() creates a blank image canvas of the specified size and
2123% background color.
2124%
2125% The format of the NewMagickImage method is:
2126%
2127% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002128% const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002129% const MagickPixelPacket *background)
2130%
2131% A description of each parameter follows:
2132%
2133% o image: the image.
2134%
2135% o width: the image width.
2136%
2137% o height: the image height.
2138%
2139% o background: the image color.
2140%
2141*/
2142MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002143 const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002144 const MagickPixelPacket *background)
2145{
2146 CacheView
2147 *image_view;
2148
2149 ExceptionInfo
2150 *exception;
2151
2152 Image
2153 *image;
2154
cristybb503372010-05-27 20:51:26 +00002155 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002156 y;
2157
2158 MagickBooleanType
2159 status;
2160
2161 assert(image_info != (const ImageInfo *) NULL);
2162 if (image_info->debug != MagickFalse)
2163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2164 assert(image_info->signature == MagickSignature);
2165 assert(background != (const MagickPixelPacket *) NULL);
2166 image=AcquireImage(image_info);
2167 image->columns=width;
2168 image->rows=height;
2169 image->colorspace=background->colorspace;
2170 image->matte=background->matte;
2171 image->fuzz=background->fuzz;
2172 image->depth=background->depth;
2173 status=MagickTrue;
2174 exception=(&image->exception);
2175 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002176#if defined(MAGICKCORE_OPENMP_SUPPORT)
2177 #pragma omp parallel for schedule(dynamic,4) shared(status)
2178#endif
cristybb503372010-05-27 20:51:26 +00002179 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002180 {
2181 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002182 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002183
cristy3ed852e2009-09-05 21:47:34 +00002184 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002185 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002186
cristycb6d09b2010-06-19 01:59:36 +00002187 register ssize_t
2188 x;
2189
cristy48974b92009-12-19 02:36:06 +00002190 if (status == MagickFalse)
2191 continue;
cristy3ed852e2009-09-05 21:47:34 +00002192 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2193 if (q == (PixelPacket *) NULL)
2194 {
2195 status=MagickFalse;
2196 continue;
2197 }
2198 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002199 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002200 {
2201 SetPixelPacket(image,background,q,indexes+x);
2202 q++;
2203 }
2204 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2205 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002206 }
2207 image_view=DestroyCacheView(image_view);
2208 if (status == MagickFalse)
2209 image=DestroyImage(image);
2210 return(image);
2211}
2212
2213/*
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215% %
2216% %
2217% %
2218% R e f e r e n c e I m a g e %
2219% %
2220% %
2221% %
2222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223%
2224% ReferenceImage() increments the reference count associated with an image
2225% returning a pointer to the image.
2226%
2227% The format of the ReferenceImage method is:
2228%
2229% Image *ReferenceImage(Image *image)
2230%
2231% A description of each parameter follows:
2232%
2233% o image: the image.
2234%
2235*/
2236MagickExport Image *ReferenceImage(Image *image)
2237{
2238 assert(image != (Image *) NULL);
2239 if (image->debug != MagickFalse)
2240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2241 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002242 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002243 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002244 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002245 return(image);
2246}
2247
2248/*
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250% %
2251% %
2252% %
2253% R e s e t I m a g e P a g e %
2254% %
2255% %
2256% %
2257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2258%
2259% ResetImagePage() resets the image page canvas and position.
2260%
2261% The format of the ResetImagePage method is:
2262%
2263% MagickBooleanType ResetImagePage(Image *image,const char *page)
2264%
2265% A description of each parameter follows:
2266%
2267% o image: the image.
2268%
2269% o page: the relative page specification.
2270%
2271*/
2272MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2273{
2274 MagickStatusType
2275 flags;
2276
2277 RectangleInfo
2278 geometry;
2279
2280 assert(image != (Image *) NULL);
2281 assert(image->signature == MagickSignature);
2282 if (image->debug != MagickFalse)
2283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2284 flags=ParseAbsoluteGeometry(page,&geometry);
2285 if ((flags & WidthValue) != 0)
2286 {
2287 if ((flags & HeightValue) == 0)
2288 geometry.height=geometry.width;
2289 image->page.width=geometry.width;
2290 image->page.height=geometry.height;
2291 }
2292 if ((flags & AspectValue) != 0)
2293 {
2294 if ((flags & XValue) != 0)
2295 image->page.x+=geometry.x;
2296 if ((flags & YValue) != 0)
2297 image->page.y+=geometry.y;
2298 }
2299 else
2300 {
2301 if ((flags & XValue) != 0)
2302 {
2303 image->page.x=geometry.x;
2304 if ((image->page.width == 0) && (geometry.x > 0))
2305 image->page.width=image->columns+geometry.x;
2306 }
2307 if ((flags & YValue) != 0)
2308 {
2309 image->page.y=geometry.y;
2310 if ((image->page.height == 0) && (geometry.y > 0))
2311 image->page.height=image->rows+geometry.y;
2312 }
2313 }
2314 return(MagickTrue);
2315}
2316
2317/*
2318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319% %
2320% %
2321% %
2322% S e p a r a t e I m a g e C h a n n e l %
2323% %
2324% %
2325% %
2326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327%
2328% SeparateImageChannel() separates a channel from the image and returns it as
2329% a grayscale image. A channel is a particular color component of each pixel
2330% in the image.
2331%
2332% The format of the SeparateImageChannel method is:
2333%
2334% MagickBooleanType SeparateImageChannel(Image *image,
2335% const ChannelType channel)
2336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o channel: Identify which channel to extract: RedChannel, GreenChannel,
2342% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2343% YellowChannel, or BlackChannel.
2344%
2345*/
2346MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2347 const ChannelType channel)
2348{
2349#define SeparateImageTag "Separate/Image"
2350
2351 CacheView
2352 *image_view;
2353
2354 ExceptionInfo
2355 *exception;
2356
cristy3ed852e2009-09-05 21:47:34 +00002357 MagickBooleanType
2358 status;
2359
cristybb503372010-05-27 20:51:26 +00002360 MagickOffsetType
2361 progress;
2362
2363 ssize_t
2364 y;
2365
cristy3ed852e2009-09-05 21:47:34 +00002366 assert(image != (Image *) NULL);
2367 assert(image->signature == MagickSignature);
2368 if (image->debug != MagickFalse)
2369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2370 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2371 return(MagickFalse);
2372 /*
2373 Separate image channels.
2374 */
2375 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002376 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002377 image->matte=MagickTrue;
2378 progress=0;
2379 exception=(&image->exception);
2380 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002381#if defined(MAGICKCORE_OPENMP_SUPPORT)
2382 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002383#endif
cristybb503372010-05-27 20:51:26 +00002384 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002385 {
2386 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002387 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002388
cristy3ed852e2009-09-05 21:47:34 +00002389 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002390 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002391
cristycb6d09b2010-06-19 01:59:36 +00002392 register ssize_t
2393 x;
2394
cristy3ed852e2009-09-05 21:47:34 +00002395 if (status == MagickFalse)
2396 continue;
2397 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2398 if (q == (PixelPacket *) NULL)
2399 {
2400 status=MagickFalse;
2401 continue;
2402 }
2403 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2404 switch (channel)
2405 {
2406 case RedChannel:
2407 {
cristybb503372010-05-27 20:51:26 +00002408 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002409 {
cristyc5071682011-04-22 02:06:27 +00002410 SetGreenPixelComponent(q,GetRedPixelComponent(q));
2411 SetBluePixelComponent(q,GetRedPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002412 q++;
2413 }
2414 break;
2415 }
2416 case GreenChannel:
2417 {
cristybb503372010-05-27 20:51:26 +00002418 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002419 {
cristyc5071682011-04-22 02:06:27 +00002420 SetRedPixelComponent(q,GetGreenPixelComponent(q));
2421 SetBluePixelComponent(q,GetGreenPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002422 q++;
2423 }
2424 break;
2425 }
2426 case BlueChannel:
2427 {
cristybb503372010-05-27 20:51:26 +00002428 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002429 {
cristyc5071682011-04-22 02:06:27 +00002430 SetRedPixelComponent(q,GetBluePixelComponent(q));
2431 SetGreenPixelComponent(q,GetBluePixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002432 q++;
2433 }
2434 break;
2435 }
2436 case OpacityChannel:
2437 {
cristybb503372010-05-27 20:51:26 +00002438 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002439 {
cristyc5071682011-04-22 02:06:27 +00002440 SetRedPixelComponent(q,GetOpacityPixelComponent(q));
2441 SetGreenPixelComponent(q,GetOpacityPixelComponent(q));
2442 SetBluePixelComponent(q,GetOpacityPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002443 q++;
2444 }
2445 break;
2446 }
2447 case BlackChannel:
2448 {
2449 if ((image->storage_class != PseudoClass) &&
2450 (image->colorspace != CMYKColorspace))
2451 break;
cristybb503372010-05-27 20:51:26 +00002452 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002453 {
cristyc8d25bc2011-04-29 02:19:30 +00002454 SetRedPixelComponent(q,GetIndexPixelComponent(indexes+x));
2455 SetGreenPixelComponent(q,GetIndexPixelComponent(indexes+x));
2456 SetBluePixelComponent(q,GetIndexPixelComponent(indexes+x));
cristy3ed852e2009-09-05 21:47:34 +00002457 q++;
2458 }
2459 break;
2460 }
2461 case TrueAlphaChannel:
2462 {
cristybb503372010-05-27 20:51:26 +00002463 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002464 {
cristy4e82e512011-04-24 01:33:42 +00002465 SetRedPixelComponent(q,GetAlphaPixelComponent(q));
2466 SetGreenPixelComponent(q,GetAlphaPixelComponent(q));
2467 SetBluePixelComponent(q,GetAlphaPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002468 q++;
2469 }
2470 break;
2471 }
2472 case GrayChannels:
2473 {
cristybb503372010-05-27 20:51:26 +00002474 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002475 {
cristy4e82e512011-04-24 01:33:42 +00002476 SetOpacityPixelComponent(q,(QuantumRange-
cristyc5071682011-04-22 02:06:27 +00002477 PixelIntensityToQuantum(q)));
cristy3ed852e2009-09-05 21:47:34 +00002478 q++;
2479 }
2480 break;
2481 }
2482 default:
2483 break;
2484 }
2485 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2486 status=MagickFalse;
2487 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2488 {
2489 MagickBooleanType
2490 proceed;
2491
cristyb5d5f722009-11-04 03:03:49 +00002492#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002493 #pragma omp critical (MagickCore_SeparateImageChannel)
2494#endif
2495 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2496 if (proceed == MagickFalse)
2497 status=MagickFalse;
2498 }
2499 }
2500 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002501 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002502 image->matte=MagickFalse;
2503 (void) SetImageColorspace(image,RGBColorspace);
2504 return(status);
2505}
2506
2507/*
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509% %
2510% %
2511% %
2512% S e p a r a t e I m a g e s %
2513% %
2514% %
2515% %
2516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2517%
2518% SeparateImages() returns a separate grayscale image for each channel
2519% specified.
2520%
2521% The format of the SeparateImages method is:
2522%
2523% MagickBooleanType SeparateImages(const Image *image,
2524% const ChannelType channel,ExceptionInfo *exception)
2525%
2526% A description of each parameter follows:
2527%
2528% o image: the image.
2529%
2530% o channel: Identify which channels to extract: RedChannel, GreenChannel,
2531% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2532% YellowChannel, or BlackChannel.
2533%
2534% o exception: return any errors or warnings in this structure.
2535%
2536*/
2537MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2538 ExceptionInfo *exception)
2539{
2540 Image
2541 *images,
2542 *separate_image;
2543
2544 assert(image != (Image *) NULL);
2545 assert(image->signature == MagickSignature);
2546 if (image->debug != MagickFalse)
2547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2548 images=NewImageList();
2549 if ((channel & RedChannel) != 0)
2550 {
2551 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2552 (void) SeparateImageChannel(separate_image,RedChannel);
2553 AppendImageToList(&images,separate_image);
2554 }
2555 if ((channel & GreenChannel) != 0)
2556 {
2557 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2558 (void) SeparateImageChannel(separate_image,GreenChannel);
2559 AppendImageToList(&images,separate_image);
2560 }
2561 if ((channel & BlueChannel) != 0)
2562 {
2563 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2564 (void) SeparateImageChannel(separate_image,BlueChannel);
2565 AppendImageToList(&images,separate_image);
2566 }
2567 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
2568 {
2569 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2570 (void) SeparateImageChannel(separate_image,BlackChannel);
2571 AppendImageToList(&images,separate_image);
2572 }
2573 if ((channel & OpacityChannel) != 0)
2574 {
2575 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2576 (void) SeparateImageChannel(separate_image,OpacityChannel);
2577 AppendImageToList(&images,separate_image);
2578 }
2579 return(images);
2580}
2581
2582/*
2583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584% %
2585% %
2586% %
2587% S e t I m a g e A l p h a C h a n n e l %
2588% %
2589% %
2590% %
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592%
2593% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2594% channel.
2595%
2596% The format of the SetImageAlphaChannel method is:
2597%
2598% MagickBooleanType SetImageAlphaChannel(Image *image,
2599% const AlphaChannelType alpha_type)
2600%
2601% A description of each parameter follows:
2602%
2603% o image: the image.
2604%
2605% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2606% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
2607% OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
2608% ShapeAlphaChannel, and TransparentAlphaChannel.
2609%
2610*/
2611MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2612 const AlphaChannelType alpha_type)
2613{
2614 MagickBooleanType
2615 status;
2616
2617 assert(image != (Image *) NULL);
2618 if (image->debug != MagickFalse)
2619 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2620 assert(image->signature == MagickSignature);
2621 status=MagickFalse;
2622 switch (alpha_type)
2623 {
2624 case ActivateAlphaChannel:
2625 {
2626 image->matte=MagickTrue;
2627 break;
2628 }
2629 case BackgroundAlphaChannel:
2630 {
2631 CacheView
2632 *image_view;
2633
2634 ExceptionInfo
2635 *exception;
2636
2637 IndexPacket
2638 index;
2639
cristy3ed852e2009-09-05 21:47:34 +00002640 MagickBooleanType
2641 status;
2642
2643 MagickPixelPacket
2644 background;
2645
2646 PixelPacket
2647 pixel;
2648
cristycb6d09b2010-06-19 01:59:36 +00002649 ssize_t
2650 y;
2651
cristy3ed852e2009-09-05 21:47:34 +00002652 /*
2653 Set transparent pixels to background color.
2654 */
2655 if (image->matte == MagickFalse)
2656 break;
2657 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2658 break;
2659 GetMagickPixelPacket(image,&background);
2660 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2661 NULL,&background);
2662 if (image->colorspace == CMYKColorspace)
2663 ConvertRGBToCMYK(&background);
2664 index=0;
2665 SetPixelPacket(image,&background,&pixel,&index);
2666 status=MagickTrue;
2667 exception=(&image->exception);
2668 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002669 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2670 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002671 #endif
cristybb503372010-05-27 20:51:26 +00002672 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002673 {
2674 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002675 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002676
cristy3ed852e2009-09-05 21:47:34 +00002677 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002678 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002679
cristycb6d09b2010-06-19 01:59:36 +00002680 register ssize_t
2681 x;
2682
cristy3ed852e2009-09-05 21:47:34 +00002683 if (status == MagickFalse)
2684 continue;
2685 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2686 exception);
2687 if (q == (PixelPacket *) NULL)
2688 {
2689 status=MagickFalse;
2690 continue;
2691 }
cristybb503372010-05-27 20:51:26 +00002692 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002693 {
2694 if (q->opacity == TransparentOpacity)
2695 {
cristya2d08742011-04-22 19:59:52 +00002696 SetRedPixelComponent(q,pixel.red);
2697 SetGreenPixelComponent(q,pixel.green);
2698 SetBluePixelComponent(q,pixel.blue);
cristy3ed852e2009-09-05 21:47:34 +00002699 }
2700 q++;
2701 }
2702 if (image->colorspace == CMYKColorspace)
2703 {
2704 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002705 for (x=0; x < (ssize_t) image->columns; x++)
cristyc8d25bc2011-04-29 02:19:30 +00002706 SetIndexPixelComponent(indexes+x,index);
cristy3ed852e2009-09-05 21:47:34 +00002707 }
2708 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2709 status=MagickFalse;
2710 }
2711 image_view=DestroyCacheView(image_view);
2712 return(status);
2713 }
2714 case DeactivateAlphaChannel:
2715 {
2716 image->matte=MagickFalse;
2717 break;
2718 }
2719 case ShapeAlphaChannel:
2720 case CopyAlphaChannel:
2721 {
2722 /*
2723 Special usage case for SeparateImageChannel(): copy grayscale color to
2724 the alpha channel.
2725 */
2726 status=SeparateImageChannel(image,GrayChannels);
2727 image->matte=MagickTrue; /* make sure transparency is now on! */
2728 if (alpha_type == ShapeAlphaChannel)
2729 {
2730 MagickPixelPacket
2731 background;
2732
2733 /*
2734 Reset all color channels to background color.
2735 */
2736 GetMagickPixelPacket(image,&background);
2737 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
2738 NULL,&background);
cristy308b4e62009-09-21 14:40:44 +00002739 (void) LevelColorsImage(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002740 }
2741 break;
2742 }
2743 case ExtractAlphaChannel:
2744 {
2745 status=SeparateImageChannel(image,TrueAlphaChannel);
2746 image->matte=MagickFalse;
2747 break;
2748 }
cristyf64d18b2010-04-30 12:47:03 +00002749 case ResetAlphaChannel: /* deprecated */
cristy3ed852e2009-09-05 21:47:34 +00002750 case OpaqueAlphaChannel:
2751 {
2752 status=SetImageOpacity(image,OpaqueOpacity);
2753 image->matte=MagickTrue;
2754 break;
2755 }
2756 case TransparentAlphaChannel:
2757 {
2758 status=SetImageOpacity(image,TransparentOpacity);
2759 image->matte=MagickTrue;
2760 break;
2761 }
2762 case SetAlphaChannel:
2763 {
2764 if (image->matte == MagickFalse)
2765 {
2766 status=SetImageOpacity(image,OpaqueOpacity);
2767 image->matte=MagickTrue;
2768 }
2769 break;
2770 }
2771 case UndefinedAlphaChannel:
2772 break;
2773 }
2774 return(status);
2775}
2776
2777/*
2778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2779% %
2780% %
2781% %
2782% S e t I m a g e B a c k g r o u n d C o l o r %
2783% %
2784% %
2785% %
2786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2787%
2788% SetImageBackgroundColor() initializes the image pixels to the image
2789% background color. The background color is defined by the background_color
2790% member of the image structure.
2791%
2792% The format of the SetImage method is:
2793%
2794% MagickBooleanType SetImageBackgroundColor(Image *image)
2795%
2796% A description of each parameter follows:
2797%
2798% o image: the image.
2799%
2800*/
2801MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2802{
2803 CacheView
2804 *image_view;
2805
2806 ExceptionInfo
2807 *exception;
2808
2809 IndexPacket
2810 index;
2811
cristy3ed852e2009-09-05 21:47:34 +00002812 MagickBooleanType
2813 status;
2814
2815 MagickPixelPacket
2816 background;
2817
2818 PixelPacket
2819 pixel;
2820
cristycb6d09b2010-06-19 01:59:36 +00002821 ssize_t
2822 y;
2823
cristy3ed852e2009-09-05 21:47:34 +00002824 assert(image != (Image *) NULL);
2825 if (image->debug != MagickFalse)
2826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2827 assert(image->signature == MagickSignature);
2828 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2829 return(MagickFalse);
2830 if (image->background_color.opacity != OpaqueOpacity)
2831 image->matte=MagickTrue;
2832 GetMagickPixelPacket(image,&background);
2833 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2834 NULL,&background);
2835 if (image->colorspace == CMYKColorspace)
2836 ConvertRGBToCMYK(&background);
2837 index=0;
2838 SetPixelPacket(image,&background,&pixel,&index);
2839 /*
2840 Set image background color.
2841 */
2842 status=MagickTrue;
2843 exception=(&image->exception);
2844 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002845 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002846 {
cristy3ed852e2009-09-05 21:47:34 +00002847 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002848 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002849
cristycb6d09b2010-06-19 01:59:36 +00002850 register ssize_t
2851 x;
2852
cristy3ed852e2009-09-05 21:47:34 +00002853 if (status == MagickFalse)
2854 continue;
2855 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2856 if (q == (PixelPacket *) NULL)
2857 {
2858 status=MagickFalse;
2859 continue;
2860 }
cristybb503372010-05-27 20:51:26 +00002861 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002862 *q++=pixel;
2863 if (image->colorspace == CMYKColorspace)
2864 {
cristy29058e62011-02-24 03:12:50 +00002865 register IndexPacket
2866 *restrict indexes;
2867
cristy3ed852e2009-09-05 21:47:34 +00002868 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002869 for (x=0; x < (ssize_t) image->columns; x++)
cristyc8d25bc2011-04-29 02:19:30 +00002870 SetIndexPixelComponent(indexes+x,index);
cristy3ed852e2009-09-05 21:47:34 +00002871 }
2872 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2873 status=MagickFalse;
2874 }
2875 image_view=DestroyCacheView(image_view);
2876 return(status);
2877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
cristy0d267172011-04-25 20:13:48 +00002884% S e t I m a g e C h a n n e l s %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% SetImageChannels() sets the number of pixels channels associated with the
2891% image.
2892%
2893% The format of the SetImageChannels method is:
2894%
2895% MagickBooleanType SetImageChannels(Image *image,const size_t channels)
2896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o channels: The number of pixel channels.
2902%
2903*/
2904MagickExport MagickBooleanType SetImageChannels(Image *image,
2905 const size_t channels)
2906{
2907 image->channels=channels;
2908 return(MagickTrue);
2909}
2910
2911/*
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913% %
2914% %
2915% %
cristya5b77cb2010-05-07 19:34:48 +00002916% S e t I m a g e C o l o r %
2917% %
2918% %
2919% %
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921%
2922% SetImageColor() set the entire image canvas to the specified color.
2923%
2924% The format of the SetImageColor method is:
2925%
2926% MagickBooleanType SetImageColor(Image *image,
2927% const MagickPixelPacket *color)
2928%
2929% A description of each parameter follows:
2930%
2931% o image: the image.
2932%
2933% o background: the image color.
2934%
2935*/
2936MagickExport MagickBooleanType SetImageColor(Image *image,
2937 const MagickPixelPacket *color)
2938{
2939 CacheView
2940 *image_view;
2941
2942 ExceptionInfo
2943 *exception;
2944
cristya5b77cb2010-05-07 19:34:48 +00002945 MagickBooleanType
2946 status;
2947
cristycb6d09b2010-06-19 01:59:36 +00002948 ssize_t
2949 y;
2950
cristya5b77cb2010-05-07 19:34:48 +00002951 assert(image != (Image *) NULL);
2952 if (image->debug != MagickFalse)
2953 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2954 assert(image->signature == MagickSignature);
2955 assert(color != (const MagickPixelPacket *) NULL);
2956 image->colorspace=color->colorspace;
2957 image->matte=color->matte;
2958 image->fuzz=color->fuzz;
2959 image->depth=color->depth;
2960 status=MagickTrue;
2961 exception=(&image->exception);
2962 image_view=AcquireCacheView(image);
2963#if defined(MAGICKCORE_OPENMP_SUPPORT)
2964 #pragma omp parallel for schedule(dynamic,4) shared(status)
2965#endif
cristybb503372010-05-27 20:51:26 +00002966 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002967 {
2968 register IndexPacket
2969 *restrict indexes;
2970
cristya5b77cb2010-05-07 19:34:48 +00002971 register PixelPacket
2972 *restrict q;
2973
cristycb6d09b2010-06-19 01:59:36 +00002974 register ssize_t
2975 x;
2976
cristya5b77cb2010-05-07 19:34:48 +00002977 if (status == MagickFalse)
2978 continue;
2979 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2980 if (q == (PixelPacket *) NULL)
2981 {
2982 status=MagickFalse;
2983 continue;
2984 }
2985 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002986 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002987 {
2988 SetPixelPacket(image,color,q,indexes+x);
2989 q++;
2990 }
2991 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2992 status=MagickFalse;
2993 }
2994 image_view=DestroyCacheView(image_view);
2995 return(status);
2996}
2997
2998/*
2999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000% %
3001% %
3002% %
cristy3ed852e2009-09-05 21:47:34 +00003003% S e t I m a g e S t o r a g e C l a s s %
3004% %
3005% %
3006% %
3007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008%
3009% SetImageStorageClass() sets the image class: DirectClass for true color
3010% images or PseudoClass for colormapped images.
3011%
3012% The format of the SetImageStorageClass method is:
3013%
3014% MagickBooleanType SetImageStorageClass(Image *image,
3015% const ClassType storage_class)
3016%
3017% A description of each parameter follows:
3018%
3019% o image: the image.
3020%
3021% o storage_class: The image class.
3022%
3023*/
3024MagickExport MagickBooleanType SetImageStorageClass(Image *image,
3025 const ClassType storage_class)
3026{
cristy3ed852e2009-09-05 21:47:34 +00003027 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00003028 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003029}
3030
3031/*
3032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3033% %
3034% %
3035% %
3036% S e t I m a g e C l i p M a s k %
3037% %
3038% %
3039% %
3040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041%
3042% SetImageClipMask() associates a clip path with the image. The clip path
3043% must be the same dimensions as the image. Set any pixel component of
3044% the clip path to TransparentOpacity to prevent that corresponding image
3045% pixel component from being updated when SyncAuthenticPixels() is applied.
3046%
3047% The format of the SetImageClipMask method is:
3048%
3049% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
3050%
3051% A description of each parameter follows:
3052%
3053% o image: the image.
3054%
3055% o clip_mask: the image clip path.
3056%
3057*/
3058MagickExport MagickBooleanType SetImageClipMask(Image *image,
3059 const Image *clip_mask)
3060{
3061 assert(image != (Image *) NULL);
3062 if (image->debug != MagickFalse)
3063 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3064 assert(image->signature == MagickSignature);
3065 if (clip_mask != (const Image *) NULL)
3066 if ((clip_mask->columns != image->columns) ||
3067 (clip_mask->rows != image->rows))
3068 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3069 if (image->clip_mask != (Image *) NULL)
3070 image->clip_mask=DestroyImage(image->clip_mask);
3071 image->clip_mask=NewImageList();
3072 if (clip_mask == (Image *) NULL)
3073 return(MagickTrue);
3074 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3075 return(MagickFalse);
3076 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
3077 if (image->clip_mask == (Image *) NULL)
3078 return(MagickFalse);
3079 return(MagickTrue);
3080}
3081
3082/*
3083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3084% %
3085% %
3086% %
3087% S e t I m a g e E x t e n t %
3088% %
3089% %
3090% %
3091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092%
3093% SetImageExtent() sets the image size (i.e. columns & rows).
3094%
3095% The format of the SetImageExtent method is:
3096%
3097% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003098% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003099%
3100% A description of each parameter follows:
3101%
3102% o image: the image.
3103%
3104% o columns: The image width in pixels.
3105%
3106% o rows: The image height in pixels.
3107%
3108*/
3109MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003110 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristy537e2722010-09-21 15:30:59 +00003112 if ((columns == 0) || (rows == 0))
3113 return(MagickFalse);
3114 image->columns=columns;
3115 image->rows=rows;
3116 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003117}
3118
3119/*
3120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121% %
3122% %
3123% %
3124+ S e t I m a g e I n f o %
3125% %
3126% %
3127% %
3128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129%
3130% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3131% It is set to a type of image format based on the prefix or suffix of the
3132% filename. For example, `ps:image' returns PS indicating a Postscript image.
3133% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3134% precendence over the suffix. Use an optional index enclosed in brackets
3135% after a file name to specify a desired scene of a multi-resolution image
3136% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3137% indicates success.
3138%
3139% The format of the SetImageInfo method is:
3140%
3141% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003142% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003143%
3144% A description of each parameter follows:
3145%
cristyd965a422010-03-03 17:47:35 +00003146% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003147%
cristyd965a422010-03-03 17:47:35 +00003148% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003149%
3150% o exception: return any errors or warnings in this structure.
3151%
3152*/
3153MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003154 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003155{
3156 char
3157 extension[MaxTextExtent],
3158 filename[MaxTextExtent],
3159 magic[MaxTextExtent],
3160 *q,
3161 subimage[MaxTextExtent];
3162
3163 const MagicInfo
3164 *magic_info;
3165
3166 const MagickInfo
3167 *magick_info;
3168
3169 ExceptionInfo
3170 *sans_exception;
3171
3172 Image
3173 *image;
3174
3175 MagickBooleanType
3176 status;
3177
3178 register const char
3179 *p;
3180
3181 ssize_t
3182 count;
3183
3184 unsigned char
3185 magick[2*MaxTextExtent];
3186
3187 /*
3188 Look for 'image.format' in filename.
3189 */
3190 assert(image_info != (ImageInfo *) NULL);
3191 assert(image_info->signature == MagickSignature);
3192 if (image_info->debug != MagickFalse)
3193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3194 image_info->filename);
3195 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003196 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
cristyd965a422010-03-03 17:47:35 +00003198 GetPathComponent(image_info->filename,SubimagePath,subimage);
3199 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003200 {
cristyd965a422010-03-03 17:47:35 +00003201 /*
3202 Look for scene specification (e.g. img0001.pcd[4]).
3203 */
3204 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3205 {
3206 if (IsGeometry(subimage) != MagickFalse)
3207 (void) CloneString(&image_info->extract,subimage);
3208 }
3209 else
3210 {
cristybb503372010-05-27 20:51:26 +00003211 size_t
cristyd965a422010-03-03 17:47:35 +00003212 first,
3213 last;
cristy3ed852e2009-09-05 21:47:34 +00003214
cristyd965a422010-03-03 17:47:35 +00003215 (void) CloneString(&image_info->scenes,subimage);
3216 image_info->scene=StringToUnsignedLong(image_info->scenes);
3217 image_info->number_scenes=image_info->scene;
3218 p=image_info->scenes;
3219 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3220 {
3221 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3222 (*p == ','))
3223 p++;
cristybb503372010-05-27 20:51:26 +00003224 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003225 last=first;
3226 while (isspace((int) ((unsigned char) *q)) != 0)
3227 q++;
3228 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003229 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003230 if (first > last)
3231 Swap(first,last);
3232 if (first < image_info->scene)
3233 image_info->scene=first;
3234 if (last > image_info->number_scenes)
3235 image_info->number_scenes=last;
3236 p=q;
3237 }
3238 image_info->number_scenes-=image_info->scene-1;
3239 image_info->subimage=image_info->scene;
3240 image_info->subrange=image_info->number_scenes;
3241 }
cristy3ed852e2009-09-05 21:47:34 +00003242 }
3243 }
3244 *extension='\0';
3245 GetPathComponent(image_info->filename,ExtensionPath,extension);
3246#if defined(MAGICKCORE_ZLIB_DELEGATE)
3247 if (*extension != '\0')
3248 if ((LocaleCompare(extension,"gz") == 0) ||
3249 (LocaleCompare(extension,"Z") == 0) ||
3250 (LocaleCompare(extension,"wmz") == 0))
3251 {
3252 char
3253 path[MaxTextExtent];
3254
3255 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3256 path[strlen(path)-strlen(extension)-1]='\0';
3257 GetPathComponent(path,ExtensionPath,extension);
3258 }
3259#endif
3260#if defined(MAGICKCORE_BZLIB_DELEGATE)
3261 if (*extension != '\0')
3262 if (LocaleCompare(extension,"bz2") == 0)
3263 {
3264 char
3265 path[MaxTextExtent];
3266
3267 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3268 path[strlen(path)-strlen(extension)-1]='\0';
3269 GetPathComponent(path,ExtensionPath,extension);
3270 }
3271#endif
3272 image_info->affirm=MagickFalse;
3273 sans_exception=AcquireExceptionInfo();
3274 if (*extension != '\0')
3275 {
3276 MagickFormatType
3277 format_type;
3278
cristybb503372010-05-27 20:51:26 +00003279 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003280 i;
3281
3282 static const char
3283 *format_type_formats[] =
3284 {
3285 "AUTOTRACE",
3286 "BROWSE",
3287 "DCRAW",
3288 "EDIT",
3289 "EPHEMERAL",
3290 "LAUNCH",
3291 "MPEG:DECODE",
3292 "MPEG:ENCODE",
3293 "PRINT",
3294 "PS:ALPHA",
3295 "PS:CMYK",
3296 "PS:COLOR",
3297 "PS:GRAY",
3298 "PS:MONO",
3299 "SCAN",
3300 "SHOW",
3301 "WIN",
3302 (char *) NULL
3303 };
3304
3305 /*
3306 User specified image format.
3307 */
3308 (void) CopyMagickString(magic,extension,MaxTextExtent);
3309 LocaleUpper(magic);
3310 /*
3311 Look for explicit image formats.
3312 */
3313 format_type=UndefinedFormatType;
3314 i=0;
cristydd9a2532010-02-20 19:26:46 +00003315 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003316 (format_type_formats[i] != (char *) NULL))
3317 {
3318 if ((*magic == *format_type_formats[i]) &&
3319 (LocaleCompare(magic,format_type_formats[i]) == 0))
3320 format_type=ExplicitFormatType;
3321 i++;
3322 }
3323 magick_info=GetMagickInfo(magic,sans_exception);
3324 if ((magick_info != (const MagickInfo *) NULL) &&
3325 (magick_info->format_type != UndefinedFormatType))
3326 format_type=magick_info->format_type;
3327 if (format_type == UndefinedFormatType)
3328 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3329 else
3330 if (format_type == ExplicitFormatType)
3331 {
3332 image_info->affirm=MagickTrue;
3333 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3334 }
3335 if (LocaleCompare(magic,"RGB") == 0)
3336 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3337 }
3338 /*
3339 Look for explicit 'format:image' in filename.
3340 */
3341 *magic='\0';
3342 GetPathComponent(image_info->filename,MagickPath,magic);
3343 if (*magic == '\0')
3344 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3345 else
3346 {
3347 /*
3348 User specified image format.
3349 */
3350 LocaleUpper(magic);
3351 if (IsMagickConflict(magic) == MagickFalse)
3352 {
3353 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3354 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3355 image_info->affirm=MagickTrue;
3356 else
3357 image_info->temporary=MagickTrue;
3358 }
3359 }
3360 magick_info=GetMagickInfo(magic,sans_exception);
3361 sans_exception=DestroyExceptionInfo(sans_exception);
3362 if ((magick_info == (const MagickInfo *) NULL) ||
3363 (GetMagickEndianSupport(magick_info) == MagickFalse))
3364 image_info->endian=UndefinedEndian;
3365 GetPathComponent(image_info->filename,CanonicalPath,filename);
3366 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003367 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003368 {
3369 /*
cristyd965a422010-03-03 17:47:35 +00003370 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003371 */
cristyd965a422010-03-03 17:47:35 +00003372 (void) InterpretImageFilename(image_info,(Image *) NULL,
3373 image_info->filename,(int) image_info->scene,filename);
3374 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3375 (strchr(filename,'%') == (char *) NULL))
3376 image_info->adjoin=MagickFalse;
3377 }
3378 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3379 {
3380 /*
3381 Some image formats do not support multiple frames per file.
3382 */
cristy3ed852e2009-09-05 21:47:34 +00003383 magick_info=GetMagickInfo(magic,exception);
3384 if (magick_info != (const MagickInfo *) NULL)
3385 if (GetMagickAdjoin(magick_info) == MagickFalse)
3386 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003387 }
3388 if (image_info->affirm != MagickFalse)
3389 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003390 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003391 {
3392 /*
cristyd965a422010-03-03 17:47:35 +00003393 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003394 */
cristyd965a422010-03-03 17:47:35 +00003395 image=AcquireImage(image_info);
3396 (void) CopyMagickString(image->filename,image_info->filename,
3397 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003398 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3399 if (status == MagickFalse)
3400 {
3401 image=DestroyImage(image);
3402 return(MagickFalse);
3403 }
cristyd965a422010-03-03 17:47:35 +00003404 if ((IsBlobSeekable(image) == MagickFalse) ||
3405 (IsBlobExempt(image) != MagickFalse))
3406 {
3407 /*
3408 Copy standard input or pipe to temporary file.
3409 */
3410 *filename='\0';
3411 status=ImageToFile(image,filename,exception);
3412 (void) CloseBlob(image);
3413 if (status == MagickFalse)
3414 {
3415 image=DestroyImage(image);
3416 return(MagickFalse);
3417 }
3418 SetImageInfoFile(image_info,(FILE *) NULL);
3419 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3420 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3421 if (status == MagickFalse)
3422 {
3423 image=DestroyImage(image);
3424 return(MagickFalse);
3425 }
3426 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3427 image_info->temporary=MagickTrue;
3428 }
3429 (void) ResetMagickMemory(magick,0,sizeof(magick));
3430 count=ReadBlob(image,2*MaxTextExtent,magick);
3431 (void) CloseBlob(image);
3432 image=DestroyImage(image);
3433 /*
3434 Check magic.xml configuration file.
3435 */
3436 sans_exception=AcquireExceptionInfo();
3437 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3438 if ((magic_info != (const MagicInfo *) NULL) &&
3439 (GetMagicName(magic_info) != (char *) NULL))
3440 {
3441 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3442 MaxTextExtent);
3443 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3444 if ((magick_info == (const MagickInfo *) NULL) ||
3445 (GetMagickEndianSupport(magick_info) == MagickFalse))
3446 image_info->endian=UndefinedEndian;
3447 sans_exception=DestroyExceptionInfo(sans_exception);
3448 return(MagickTrue);
3449 }
cristy3ed852e2009-09-05 21:47:34 +00003450 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3451 if ((magick_info == (const MagickInfo *) NULL) ||
3452 (GetMagickEndianSupport(magick_info) == MagickFalse))
3453 image_info->endian=UndefinedEndian;
3454 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003455 }
cristy3ed852e2009-09-05 21:47:34 +00003456 return(MagickTrue);
3457}
3458
3459/*
3460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3461% %
3462% %
3463% %
3464% S e t I m a g e I n f o B l o b %
3465% %
3466% %
3467% %
3468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3469%
3470% SetImageInfoBlob() sets the image info blob member.
3471%
3472% The format of the SetImageInfoBlob method is:
3473%
3474% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3475% const size_t length)
3476%
3477% A description of each parameter follows:
3478%
3479% o image_info: the image info.
3480%
3481% o blob: the blob.
3482%
3483% o length: the blob length.
3484%
3485*/
3486MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3487 const size_t length)
3488{
3489 assert(image_info != (ImageInfo *) NULL);
3490 assert(image_info->signature == MagickSignature);
3491 if (image_info->debug != MagickFalse)
3492 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3493 image_info->filename);
3494 image_info->blob=(void *) blob;
3495 image_info->length=length;
3496}
3497
3498/*
3499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3500% %
3501% %
3502% %
3503% S e t I m a g e I n f o F i l e %
3504% %
3505% %
3506% %
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508%
3509% SetImageInfoFile() sets the image info file member.
3510%
3511% The format of the SetImageInfoFile method is:
3512%
3513% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3514%
3515% A description of each parameter follows:
3516%
3517% o image_info: the image info.
3518%
3519% o file: the file.
3520%
3521*/
3522MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3523{
3524 assert(image_info != (ImageInfo *) NULL);
3525 assert(image_info->signature == MagickSignature);
3526 if (image_info->debug != MagickFalse)
3527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3528 image_info->filename);
3529 image_info->file=file;
3530}
3531
3532/*
3533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3534% %
3535% %
3536% %
3537% S e t I m a g e M a s k %
3538% %
3539% %
3540% %
3541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3542%
3543% SetImageMask() associates a mask with the image. The mask must be the same
3544% dimensions as the image.
3545%
3546% The format of the SetImageMask method is:
3547%
3548% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3549%
3550% A description of each parameter follows:
3551%
3552% o image: the image.
3553%
3554% o mask: the image mask.
3555%
3556*/
3557MagickExport MagickBooleanType SetImageMask(Image *image,
3558 const Image *mask)
3559{
3560 assert(image != (Image *) NULL);
3561 if (image->debug != MagickFalse)
3562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3563 assert(image->signature == MagickSignature);
3564 if (mask != (const Image *) NULL)
3565 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3566 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3567 if (image->mask != (Image *) NULL)
3568 image->mask=DestroyImage(image->mask);
3569 image->mask=NewImageList();
3570 if (mask == (Image *) NULL)
3571 return(MagickTrue);
3572 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3573 return(MagickFalse);
3574 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3575 if (image->mask == (Image *) NULL)
3576 return(MagickFalse);
3577 return(MagickTrue);
3578}
3579
3580/*
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582% %
3583% %
3584% %
3585% S e t I m a g e O p a c i t y %
3586% %
3587% %
3588% %
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590%
3591% SetImageOpacity() sets the opacity levels of the image.
3592%
3593% The format of the SetImageOpacity method is:
3594%
3595% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3596%
3597% A description of each parameter follows:
3598%
3599% o image: the image.
3600%
3601% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3602% fully transparent.
3603%
3604*/
3605MagickExport MagickBooleanType SetImageOpacity(Image *image,
3606 const Quantum opacity)
3607{
3608 CacheView
3609 *image_view;
3610
3611 ExceptionInfo
3612 *exception;
3613
cristy3ed852e2009-09-05 21:47:34 +00003614 MagickBooleanType
3615 status;
3616
cristycb6d09b2010-06-19 01:59:36 +00003617 ssize_t
3618 y;
3619
cristy3ed852e2009-09-05 21:47:34 +00003620 assert(image != (Image *) NULL);
3621 if (image->debug != MagickFalse)
3622 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3623 assert(image->signature == MagickSignature);
3624 image->matte=opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3625 status=MagickTrue;
3626 exception=(&image->exception);
3627 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003628#if defined(MAGICKCORE_OPENMP_SUPPORT)
3629 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003630#endif
cristybb503372010-05-27 20:51:26 +00003631 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003632 {
cristy3ed852e2009-09-05 21:47:34 +00003633 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003634 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003635
cristycb6d09b2010-06-19 01:59:36 +00003636 register ssize_t
3637 x;
3638
cristy3ed852e2009-09-05 21:47:34 +00003639 if (status == MagickFalse)
3640 continue;
3641 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3642 if (q == (PixelPacket *) NULL)
3643 {
3644 status=MagickFalse;
3645 continue;
3646 }
cristybb503372010-05-27 20:51:26 +00003647 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003648 {
cristy46f08202010-01-10 04:04:21 +00003649 SetOpacityPixelComponent(q,opacity);
cristy3ed852e2009-09-05 21:47:34 +00003650 q++;
3651 }
3652 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3653 status=MagickFalse;
3654 }
3655 image_view=DestroyCacheView(image_view);
3656 return(status);
3657}
3658
3659/*
3660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3661% %
3662% %
3663% %
3664% S e t I m a g e T y p e %
3665% %
3666% %
3667% %
3668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3669%
3670% SetImageType() sets the type of image. Choose from these types:
3671%
3672% Bilevel Grayscale GrayscaleMatte
3673% Palette PaletteMatte TrueColor
3674% TrueColorMatte ColorSeparation ColorSeparationMatte
3675% OptimizeType
3676%
3677% The format of the SetImageType method is:
3678%
3679% MagickBooleanType SetImageType(Image *image,const ImageType type)
3680%
3681% A description of each parameter follows:
3682%
3683% o image: the image.
3684%
3685% o type: Image type.
3686%
3687*/
3688MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3689{
3690 const char
3691 *artifact;
3692
3693 ImageInfo
3694 *image_info;
3695
3696 MagickBooleanType
3697 status;
3698
3699 QuantizeInfo
3700 *quantize_info;
3701
3702 assert(image != (Image *) NULL);
3703 if (image->debug != MagickFalse)
3704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3705 assert(image->signature == MagickSignature);
3706 status=MagickTrue;
3707 image_info=AcquireImageInfo();
3708 image_info->dither=image->dither;
3709 artifact=GetImageArtifact(image,"dither");
3710 if (artifact != (const char *) NULL)
3711 (void) SetImageOption(image_info,"dither",artifact);
3712 switch (type)
3713 {
3714 case BilevelType:
3715 {
3716 if (IsGrayImage(image,&image->exception) == MagickFalse)
3717 status=TransformImageColorspace(image,GRAYColorspace);
3718 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
3719 {
3720 quantize_info=AcquireQuantizeInfo(image_info);
3721 quantize_info->number_colors=2;
3722 quantize_info->colorspace=GRAYColorspace;
3723 status=QuantizeImage(quantize_info,image);
3724 quantize_info=DestroyQuantizeInfo(quantize_info);
3725 }
3726 image->matte=MagickFalse;
3727 break;
3728 }
3729 case GrayscaleType:
3730 {
3731 if (IsGrayImage(image,&image->exception) == MagickFalse)
3732 status=TransformImageColorspace(image,GRAYColorspace);
3733 image->matte=MagickFalse;
3734 break;
3735 }
3736 case GrayscaleMatteType:
3737 {
3738 if (IsGrayImage(image,&image->exception) == MagickFalse)
3739 status=TransformImageColorspace(image,GRAYColorspace);
3740 if (image->matte == MagickFalse)
3741 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3742 break;
3743 }
3744 case PaletteType:
3745 {
3746 if (image->colorspace != RGBColorspace)
3747 status=TransformImageColorspace(image,RGBColorspace);
3748 if ((image->storage_class == DirectClass) || (image->colors > 256))
3749 {
3750 quantize_info=AcquireQuantizeInfo(image_info);
3751 quantize_info->number_colors=256;
3752 status=QuantizeImage(quantize_info,image);
3753 quantize_info=DestroyQuantizeInfo(quantize_info);
3754 }
3755 image->matte=MagickFalse;
3756 break;
3757 }
3758 case PaletteBilevelMatteType:
3759 {
3760 if (image->colorspace != RGBColorspace)
3761 status=TransformImageColorspace(image,RGBColorspace);
3762 if (image->matte == MagickFalse)
3763 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3764 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3765 quantize_info=AcquireQuantizeInfo(image_info);
3766 status=QuantizeImage(quantize_info,image);
3767 quantize_info=DestroyQuantizeInfo(quantize_info);
3768 break;
3769 }
3770 case PaletteMatteType:
3771 {
3772 if (image->colorspace != RGBColorspace)
3773 status=TransformImageColorspace(image,RGBColorspace);
3774 if (image->matte == MagickFalse)
3775 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3776 quantize_info=AcquireQuantizeInfo(image_info);
3777 quantize_info->colorspace=TransparentColorspace;
3778 status=QuantizeImage(quantize_info,image);
3779 quantize_info=DestroyQuantizeInfo(quantize_info);
3780 break;
3781 }
3782 case TrueColorType:
3783 {
3784 if (image->colorspace != RGBColorspace)
3785 status=TransformImageColorspace(image,RGBColorspace);
3786 if (image->storage_class != DirectClass)
3787 status=SetImageStorageClass(image,DirectClass);
3788 image->matte=MagickFalse;
3789 break;
3790 }
3791 case TrueColorMatteType:
3792 {
3793 if (image->colorspace != RGBColorspace)
3794 status=TransformImageColorspace(image,RGBColorspace);
3795 if (image->storage_class != DirectClass)
3796 status=SetImageStorageClass(image,DirectClass);
3797 if (image->matte == MagickFalse)
3798 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3799 break;
3800 }
3801 case ColorSeparationType:
3802 {
3803 if (image->colorspace != CMYKColorspace)
3804 {
3805 if (image->colorspace != RGBColorspace)
3806 status=TransformImageColorspace(image,RGBColorspace);
3807 status=TransformImageColorspace(image,CMYKColorspace);
3808 }
3809 if (image->storage_class != DirectClass)
3810 status=SetImageStorageClass(image,DirectClass);
3811 image->matte=MagickFalse;
3812 break;
3813 }
3814 case ColorSeparationMatteType:
3815 {
3816 if (image->colorspace != CMYKColorspace)
3817 {
3818 if (image->colorspace != RGBColorspace)
3819 status=TransformImageColorspace(image,RGBColorspace);
3820 status=TransformImageColorspace(image,CMYKColorspace);
3821 }
3822 if (image->storage_class != DirectClass)
3823 status=SetImageStorageClass(image,DirectClass);
3824 if (image->matte == MagickFalse)
3825 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3826 break;
3827 }
3828 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003829 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003830 break;
3831 }
3832 image->type=type;
3833 image_info=DestroyImageInfo(image_info);
3834 return(status);
3835}
3836
3837/*
3838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839% %
3840% %
3841% %
3842% 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 %
3843% %
3844% %
3845% %
3846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3847%
3848% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3849% image and returns the previous setting. A virtual pixel is any pixel access
3850% that is outside the boundaries of the image cache.
3851%
3852% The format of the SetImageVirtualPixelMethod() method is:
3853%
3854% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3855% const VirtualPixelMethod virtual_pixel_method)
3856%
3857% A description of each parameter follows:
3858%
3859% o image: the image.
3860%
3861% o virtual_pixel_method: choose the type of virtual pixel.
3862%
3863*/
3864MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3865 const VirtualPixelMethod virtual_pixel_method)
3866{
3867 assert(image != (const Image *) NULL);
3868 assert(image->signature == MagickSignature);
3869 if (image->debug != MagickFalse)
3870 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3871 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3872}
3873
3874/*
3875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3876% %
3877% %
3878% %
cristy4285d782011-02-09 20:12:28 +00003879% S m u s h I m a g e s %
3880% %
3881% %
3882% %
3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3884%
3885% SmushImages() takes all images from the current image pointer to the end
3886% of the image list and smushes them to each other top-to-bottom if the
3887% stack parameter is true, otherwise left-to-right.
3888%
3889% The current gravity setting now effects how the image is justified in the
3890% final image.
3891%
3892% The format of the SmushImages method is:
3893%
cristy4ca38e22011-02-10 02:57:49 +00003894% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003895% ExceptionInfo *exception)
3896%
3897% A description of each parameter follows:
3898%
cristy4ca38e22011-02-10 02:57:49 +00003899% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003900%
3901% o stack: A value other than 0 stacks the images top-to-bottom.
3902%
3903% o offset: minimum distance in pixels between images.
3904%
3905% o exception: return any errors or warnings in this structure.
3906%
3907*/
cristy4ca38e22011-02-10 02:57:49 +00003908
cristy7c6dc152011-02-11 14:10:55 +00003909static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003910 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003911{
cristy4d727152011-02-10 19:57:21 +00003912 CacheView
3913 *left_view,
3914 *right_view;
3915
3916 const Image
3917 *left_image,
3918 *right_image;
3919
cristy4d727152011-02-10 19:57:21 +00003920 RectangleInfo
3921 left_geometry,
3922 right_geometry;
3923
cristydab7e912011-02-11 18:19:24 +00003924 register const PixelPacket
3925 *p;
3926
cristy4d727152011-02-10 19:57:21 +00003927 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003928 i,
cristy4d727152011-02-10 19:57:21 +00003929 y;
3930
cristy7c6dc152011-02-11 14:10:55 +00003931 size_t
3932 gap;
3933
cristy4d727152011-02-10 19:57:21 +00003934 ssize_t
cristy4d727152011-02-10 19:57:21 +00003935 x;
3936
3937 if (images->previous == (Image *) NULL)
3938 return(0);
3939 right_image=images;
3940 SetGeometry(smush_image,&right_geometry);
3941 GravityAdjustGeometry(right_image->columns,right_image->rows,
3942 right_image->gravity,&right_geometry);
3943 left_image=images->previous;
3944 SetGeometry(smush_image,&left_geometry);
3945 GravityAdjustGeometry(left_image->columns,left_image->rows,
3946 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003947 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003948 left_view=AcquireCacheView(left_image);
3949 right_view=AcquireCacheView(right_image);
3950 for (y=0; y < (ssize_t) smush_image->rows; y++)
3951 {
3952 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3953 {
cristydab7e912011-02-11 18:19:24 +00003954 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3955 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003956 (GetOpacityPixelComponent(p) != TransparentOpacity) ||
cristy7c6dc152011-02-11 14:10:55 +00003957 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003958 break;
3959 }
cristy4ef6f062011-02-10 20:30:22 +00003960 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003961 for (x=0; x < (ssize_t) right_image->columns; x++)
3962 {
cristydab7e912011-02-11 18:19:24 +00003963 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003964 exception);
cristydab7e912011-02-11 18:19:24 +00003965 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003966 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003967 break;
3968 }
cristy7c6dc152011-02-11 14:10:55 +00003969 if ((x+i) < (ssize_t) gap)
3970 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003971 }
3972 right_view=DestroyCacheView(right_view);
3973 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003974 if (y < (ssize_t) smush_image->rows)
3975 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003976 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003977}
3978
cristy7c6dc152011-02-11 14:10:55 +00003979static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003980 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003981{
cristy4d727152011-02-10 19:57:21 +00003982 CacheView
3983 *bottom_view,
3984 *top_view;
3985
3986 const Image
3987 *bottom_image,
3988 *top_image;
3989
cristy4d727152011-02-10 19:57:21 +00003990 RectangleInfo
3991 bottom_geometry,
3992 top_geometry;
3993
cristydab7e912011-02-11 18:19:24 +00003994 register const PixelPacket
3995 *p;
3996
cristy4d727152011-02-10 19:57:21 +00003997 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003998 i,
cristy4d727152011-02-10 19:57:21 +00003999 x;
4000
cristy7c6dc152011-02-11 14:10:55 +00004001 size_t
4002 gap;
4003
cristy4d727152011-02-10 19:57:21 +00004004 ssize_t
cristy4d727152011-02-10 19:57:21 +00004005 y;
4006
4007 if (images->previous == (Image *) NULL)
4008 return(0);
4009 bottom_image=images;
4010 SetGeometry(smush_image,&bottom_geometry);
4011 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
4012 bottom_image->gravity,&bottom_geometry);
4013 top_image=images->previous;
4014 SetGeometry(smush_image,&top_geometry);
4015 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
4016 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00004017 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00004018 top_view=AcquireCacheView(top_image);
4019 bottom_view=AcquireCacheView(bottom_image);
4020 for (x=0; x < (ssize_t) smush_image->columns; x++)
4021 {
4022 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
4023 {
cristydab7e912011-02-11 18:19:24 +00004024 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
4025 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004026 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00004027 break;
4028 }
cristy4ef6f062011-02-10 20:30:22 +00004029 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00004030 for (y=0; y < (ssize_t) bottom_image->rows; y++)
4031 {
cristydab7e912011-02-11 18:19:24 +00004032 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
4033 exception);
4034 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004035 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00004036 break;
4037 }
cristy7c6dc152011-02-11 14:10:55 +00004038 if ((y+i) < (ssize_t) gap)
4039 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00004040 }
4041 bottom_view=DestroyCacheView(bottom_view);
4042 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00004043 if (x < (ssize_t) smush_image->columns)
4044 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00004045 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00004046}
4047
4048MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00004049 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
4050{
4051#define SmushImageTag "Smush/Image"
4052
4053 CacheView
cristybb5dced2011-02-10 02:17:16 +00004054 *smush_view;
cristy4285d782011-02-09 20:12:28 +00004055
cristy4ca38e22011-02-10 02:57:49 +00004056 const Image
4057 *image;
4058
cristy4285d782011-02-09 20:12:28 +00004059 Image
4060 *smush_image;
4061
4062 MagickBooleanType
4063 matte,
4064 proceed,
4065 status;
4066
4067 MagickOffsetType
4068 n;
4069
4070 RectangleInfo
4071 geometry;
4072
4073 register const Image
4074 *next;
4075
4076 size_t
4077 height,
4078 number_images,
4079 width;
4080
4081 ssize_t
4082 x_offset,
cristy4285d782011-02-09 20:12:28 +00004083 y_offset;
4084
4085 /*
cristy7c6dc152011-02-11 14:10:55 +00004086 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00004087 */
cristy4ca38e22011-02-10 02:57:49 +00004088 assert(images != (Image *) NULL);
4089 assert(images->signature == MagickSignature);
4090 if (images->debug != MagickFalse)
4091 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00004092 assert(exception != (ExceptionInfo *) NULL);
4093 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00004094 image=images;
cristy4285d782011-02-09 20:12:28 +00004095 matte=image->matte;
4096 number_images=1;
4097 width=image->columns;
4098 height=image->rows;
4099 next=GetNextImageInList(image);
4100 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4101 {
4102 if (next->matte != MagickFalse)
4103 matte=MagickTrue;
4104 number_images++;
4105 if (stack != MagickFalse)
4106 {
4107 if (next->columns > width)
4108 width=next->columns;
4109 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004110 if (next->previous != (Image *) NULL)
4111 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004112 continue;
4113 }
4114 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004115 if (next->previous != (Image *) NULL)
4116 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004117 if (next->rows > height)
4118 height=next->rows;
4119 }
4120 /*
cristy7c6dc152011-02-11 14:10:55 +00004121 Smush images.
cristy4285d782011-02-09 20:12:28 +00004122 */
4123 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4124 if (smush_image == (Image *) NULL)
4125 return((Image *) NULL);
4126 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4127 {
4128 InheritException(exception,&smush_image->exception);
4129 smush_image=DestroyImage(smush_image);
4130 return((Image *) NULL);
4131 }
4132 smush_image->matte=matte;
4133 (void) SetImageBackgroundColor(smush_image);
4134 status=MagickTrue;
4135 x_offset=0;
4136 y_offset=0;
4137 smush_view=AcquireCacheView(smush_image);
4138 for (n=0; n < (MagickOffsetType) number_images; n++)
4139 {
4140 SetGeometry(smush_image,&geometry);
4141 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4142 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004143 {
4144 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004145 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004146 }
cristy4285d782011-02-09 20:12:28 +00004147 else
cristy4ca38e22011-02-10 02:57:49 +00004148 {
cristy7c6dc152011-02-11 14:10:55 +00004149 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004150 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004151 }
cristybb5dced2011-02-10 02:17:16 +00004152 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004153 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4154 if (proceed == MagickFalse)
4155 break;
4156 if (stack == MagickFalse)
4157 {
4158 x_offset+=(ssize_t) image->columns;
4159 y_offset=0;
4160 }
4161 else
4162 {
4163 x_offset=0;
4164 y_offset+=(ssize_t) image->rows;
4165 }
4166 image=GetNextImageInList(image);
4167 }
cristy4ef6f062011-02-10 20:30:22 +00004168 if (stack == MagickFalse)
4169 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004170 else
cristy4ef6f062011-02-10 20:30:22 +00004171 smush_image->rows=(size_t) y_offset;
4172 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004173 if (status == MagickFalse)
4174 smush_image=DestroyImage(smush_image);
4175 return(smush_image);
4176}
4177
4178/*
4179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4180% %
4181% %
4182% %
cristy3ed852e2009-09-05 21:47:34 +00004183% S t r i p I m a g e %
4184% %
4185% %
4186% %
4187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4188%
cristy376bda92009-12-22 21:15:23 +00004189% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004190%
4191% The format of the StripImage method is:
4192%
4193% MagickBooleanType StripImage(Image *image)
4194%
4195% A description of each parameter follows:
4196%
4197% o image: the image.
4198%
4199*/
4200MagickExport MagickBooleanType StripImage(Image *image)
4201{
4202 assert(image != (Image *) NULL);
4203 if (image->debug != MagickFalse)
4204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4205 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004206 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004207 (void) DeleteImageProperty(image,"date:create");
4208 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004209 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004210 return(MagickTrue);
4211}
4212
4213/*
4214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4215% %
4216% %
4217% %
4218+ S y n c I m a g e %
4219% %
4220% %
4221% %
4222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223%
4224% SyncImage() initializes the red, green, and blue intensities of each pixel
4225% as defined by the colormap index.
4226%
4227% The format of the SyncImage method is:
4228%
4229% MagickBooleanType SyncImage(Image *image)
4230%
4231% A description of each parameter follows:
4232%
4233% o image: the image.
4234%
4235*/
4236
4237static inline IndexPacket PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004238 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004239{
4240 if (index < image->colors)
4241 return((IndexPacket) index);
4242 *range_exception=MagickTrue;
4243 return((IndexPacket) 0);
4244}
4245
4246MagickExport MagickBooleanType SyncImage(Image *image)
4247{
4248 CacheView
4249 *image_view;
4250
4251 ExceptionInfo
4252 *exception;
4253
cristy3ed852e2009-09-05 21:47:34 +00004254 MagickBooleanType
4255 range_exception,
4256 status;
4257
cristycb6d09b2010-06-19 01:59:36 +00004258 ssize_t
4259 y;
4260
cristy3ed852e2009-09-05 21:47:34 +00004261 assert(image != (Image *) NULL);
4262 if (image->debug != MagickFalse)
4263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4264 assert(image->signature == MagickSignature);
4265 if (image->storage_class == DirectClass)
4266 return(MagickFalse);
4267 range_exception=MagickFalse;
4268 status=MagickTrue;
4269 exception=(&image->exception);
4270 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004271#if defined(MAGICKCORE_OPENMP_SUPPORT)
4272 #pragma omp parallel for schedule(dynamic,4) shared(status)
4273#endif
cristybb503372010-05-27 20:51:26 +00004274 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004275 {
4276 IndexPacket
4277 index;
4278
4279 PixelPacket
4280 pixel;
4281
4282 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004283 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00004284
cristy3ed852e2009-09-05 21:47:34 +00004285 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004286 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004287
cristycb6d09b2010-06-19 01:59:36 +00004288 register ssize_t
4289 x;
4290
cristy48974b92009-12-19 02:36:06 +00004291 if (status == MagickFalse)
4292 continue;
cristy3ed852e2009-09-05 21:47:34 +00004293 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4294 if (q == (PixelPacket *) NULL)
4295 {
4296 status=MagickFalse;
4297 continue;
4298 }
4299 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00004300 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004301 {
cristyc8d25bc2011-04-29 02:19:30 +00004302 index=PushColormapIndex(image,(size_t) GetIndexPixelComponent(indexes+x),
4303 &range_exception);
cristybb503372010-05-27 20:51:26 +00004304 pixel=image->colormap[(ssize_t) index];
cristya2d08742011-04-22 19:59:52 +00004305 SetRedPixelComponent(q,pixel.red);
4306 SetGreenPixelComponent(q,pixel.green);
4307 SetBluePixelComponent(q,pixel.blue);
cristyd0272592010-04-21 01:01:49 +00004308 if (image->matte != MagickFalse)
cristya2d08742011-04-22 19:59:52 +00004309 SetOpacityPixelComponent(q,pixel.opacity);
cristy3ed852e2009-09-05 21:47:34 +00004310 q++;
4311 }
4312 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4313 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004314 }
4315 image_view=DestroyCacheView(image_view);
4316 if (range_exception != MagickFalse)
4317 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4318 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4319 return(status);
4320}
cristy1626d332009-11-10 16:58:17 +00004321
4322/*
4323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4324% %
4325% %
4326% %
4327% S y n c I m a g e S e t t i n g s %
4328% %
4329% %
4330% %
4331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332%
4333% SyncImageSettings() sync the image info options to the image.
4334%
4335% The format of the SyncImageSettings method is:
4336%
4337% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4338% Image *image)
4339% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4340% Image *image)
4341%
4342% A description of each parameter follows:
4343%
4344% o image_info: the image info.
4345%
4346% o image: the image.
4347%
4348*/
4349
4350MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4351 Image *images)
4352{
4353 Image
4354 *image;
4355
4356 assert(image_info != (const ImageInfo *) NULL);
4357 assert(image_info->signature == MagickSignature);
4358 assert(images != (Image *) NULL);
4359 assert(images->signature == MagickSignature);
4360 if (images->debug != MagickFalse)
4361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4362 image=images;
4363 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4364 (void) SyncImageSettings(image_info,image);
4365 (void) DeleteImageOption(image_info,"page");
4366 return(MagickTrue);
4367}
4368
4369MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4370 Image *image)
4371{
4372 char
4373 property[MaxTextExtent];
4374
4375 const char
cristy9a703812010-07-26 14:50:29 +00004376 *option,
4377 *value;
cristy1626d332009-11-10 16:58:17 +00004378
4379 GeometryInfo
4380 geometry_info;
4381
4382 MagickStatusType
4383 flags;
4384
cristy19eb6412010-04-23 14:42:29 +00004385 ResolutionType
4386 units;
4387
cristy1626d332009-11-10 16:58:17 +00004388 /*
4389 Sync image options.
4390 */
4391 assert(image_info != (const ImageInfo *) NULL);
4392 assert(image_info->signature == MagickSignature);
4393 assert(image != (Image *) NULL);
4394 assert(image->signature == MagickSignature);
4395 if (image->debug != MagickFalse)
4396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4397 option=GetImageOption(image_info,"background");
4398 if (option != (const char *) NULL)
4399 (void) QueryColorDatabase(option,&image->background_color,
4400 &image->exception);
4401 option=GetImageOption(image_info,"bias");
4402 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004403 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004404 option=GetImageOption(image_info,"black-point-compensation");
4405 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004406 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004407 MagickBooleanOptions,MagickFalse,option);
4408 option=GetImageOption(image_info,"blue-primary");
4409 if (option != (const char *) NULL)
4410 {
4411 flags=ParseGeometry(option,&geometry_info);
4412 image->chromaticity.blue_primary.x=geometry_info.rho;
4413 image->chromaticity.blue_primary.y=geometry_info.sigma;
4414 if ((flags & SigmaValue) == 0)
4415 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4416 }
4417 option=GetImageOption(image_info,"bordercolor");
4418 if (option != (const char *) NULL)
4419 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4420 option=GetImageOption(image_info,"colors");
4421 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004422 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004423 option=GetImageOption(image_info,"compose");
4424 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004425 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004426 MagickFalse,option);
4427 option=GetImageOption(image_info,"compress");
4428 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004429 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004430 MagickCompressOptions,MagickFalse,option);
4431 option=GetImageOption(image_info,"debug");
4432 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004433 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004434 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004435 option=GetImageOption(image_info,"density");
4436 if (option != (const char *) NULL)
4437 {
4438 GeometryInfo
4439 geometry_info;
4440
4441 /*
4442 Set image density.
4443 */
4444 flags=ParseGeometry(option,&geometry_info);
4445 image->x_resolution=geometry_info.rho;
4446 image->y_resolution=geometry_info.sigma;
4447 if ((flags & SigmaValue) == 0)
4448 image->y_resolution=image->x_resolution;
4449 }
cristy1626d332009-11-10 16:58:17 +00004450 option=GetImageOption(image_info,"depth");
4451 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004452 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004453 option=GetImageOption(image_info,"endian");
4454 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004455 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004456 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004457 option=GetImageOption(image_info,"filter");
4458 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004459 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004460 MagickFalse,option);
4461 option=GetImageOption(image_info,"fuzz");
4462 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004463 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004464 option=GetImageOption(image_info,"gravity");
4465 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004466 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004467 MagickFalse,option);
4468 option=GetImageOption(image_info,"green-primary");
4469 if (option != (const char *) NULL)
4470 {
4471 flags=ParseGeometry(option,&geometry_info);
4472 image->chromaticity.green_primary.x=geometry_info.rho;
4473 image->chromaticity.green_primary.y=geometry_info.sigma;
4474 if ((flags & SigmaValue) == 0)
4475 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4476 }
4477 option=GetImageOption(image_info,"intent");
4478 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004479 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004480 MagickIntentOptions,MagickFalse,option);
4481 option=GetImageOption(image_info,"interlace");
4482 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004483 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004484 MagickFalse,option);
4485 option=GetImageOption(image_info,"interpolate");
4486 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004487 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004488 MagickInterpolateOptions,MagickFalse,option);
4489 option=GetImageOption(image_info,"loop");
4490 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004491 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004492 option=GetImageOption(image_info,"mattecolor");
4493 if (option != (const char *) NULL)
4494 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4495 option=GetImageOption(image_info,"orient");
4496 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004497 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004498 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004499 option=GetImageOption(image_info,"page");
4500 if (option != (const char *) NULL)
4501 {
4502 char
4503 *geometry;
4504
4505 geometry=GetPageGeometry(option);
4506 flags=ParseAbsoluteGeometry(geometry,&image->page);
4507 geometry=DestroyString(geometry);
4508 }
cristy1626d332009-11-10 16:58:17 +00004509 option=GetImageOption(image_info,"quality");
4510 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004511 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004512 option=GetImageOption(image_info,"red-primary");
4513 if (option != (const char *) NULL)
4514 {
4515 flags=ParseGeometry(option,&geometry_info);
4516 image->chromaticity.red_primary.x=geometry_info.rho;
4517 image->chromaticity.red_primary.y=geometry_info.sigma;
4518 if ((flags & SigmaValue) == 0)
4519 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4520 }
4521 if (image_info->quality != UndefinedCompressionQuality)
4522 image->quality=image_info->quality;
4523 option=GetImageOption(image_info,"scene");
4524 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004525 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004526 option=GetImageOption(image_info,"taint");
4527 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004528 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004529 MagickFalse,option);
4530 option=GetImageOption(image_info,"tile-offset");
4531 if (option != (const char *) NULL)
4532 {
4533 char
4534 *geometry;
4535
4536 geometry=GetPageGeometry(option);
4537 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4538 geometry=DestroyString(geometry);
4539 }
4540 option=GetImageOption(image_info,"transparent-color");
4541 if (option != (const char *) NULL)
4542 (void) QueryColorDatabase(option,&image->transparent_color,
4543 &image->exception);
4544 option=GetImageOption(image_info,"type");
4545 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004546 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004547 option);
4548 option=GetImageOption(image_info,"units");
4549 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004550 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004551 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004552 else
4553 units = image_info->units;
4554 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004555 {
cristy19eb6412010-04-23 14:42:29 +00004556 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004557 switch (image->units)
4558 {
4559 case PixelsPerInchResolution:
4560 {
cristy19eb6412010-04-23 14:42:29 +00004561 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004562 {
4563 image->x_resolution/=2.54;
4564 image->y_resolution/=2.54;
4565 }
4566 break;
4567 }
4568 case PixelsPerCentimeterResolution:
4569 {
cristy19eb6412010-04-23 14:42:29 +00004570 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004571 {
cristybb503372010-05-27 20:51:26 +00004572 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004573 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004574 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004575 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004576 }
4577 break;
4578 }
4579 default:
4580 break;
4581 }
cristy19eb6412010-04-23 14:42:29 +00004582 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004583 }
4584 option=GetImageOption(image_info,"white-point");
4585 if (option != (const char *) NULL)
4586 {
4587 flags=ParseGeometry(option,&geometry_info);
4588 image->chromaticity.white_point.x=geometry_info.rho;
4589 image->chromaticity.white_point.y=geometry_info.sigma;
4590 if ((flags & SigmaValue) == 0)
4591 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4592 }
4593 ResetImageOptionIterator(image_info);
4594 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4595 {
4596 value=GetImageOption(image_info,option);
4597 if (value != (const char *) NULL)
4598 {
cristyb51dff52011-05-19 16:55:47 +00004599 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004600 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004601 }
4602 option=GetNextImageOption(image_info);
4603 }
4604 return(MagickTrue);
4605}