blob: 0dc6252240de0e6d7c53420ba256f32f017db2ac [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))
cristy3ed852e2009-09-05 21:47:34 +0000552 append_indexes[x]=indexes[x];
553 p++;
554 q++;
555 }
556 sync=SyncCacheViewAuthenticPixels(append_view,exception);
557 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000558 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000559 }
560 image_view=DestroyCacheView(image_view);
561 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
562 if (proceed == MagickFalse)
563 break;
564 if (stack == MagickFalse)
565 {
cristyeaedf062010-05-29 22:36:02 +0000566 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000567 y_offset=0;
568 }
569 else
570 {
571 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000572 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000573 }
574 image=GetNextImageInList(image);
575 }
576 append_view=DestroyCacheView(append_view);
577 if (status == MagickFalse)
578 append_image=DestroyImage(append_image);
579 return(append_image);
580}
581
582/*
583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584% %
585% %
586% %
cristy3ed852e2009-09-05 21:47:34 +0000587% C a t c h I m a g e E x c e p t i o n %
588% %
589% %
590% %
591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592%
593% CatchImageException() returns if no exceptions are found in the image
594% sequence, otherwise it determines the most severe exception and reports
595% it as a warning or error depending on the severity.
596%
597% The format of the CatchImageException method is:
598%
599% ExceptionType CatchImageException(Image *image)
600%
601% A description of each parameter follows:
602%
603% o image: An image sequence.
604%
605*/
606MagickExport ExceptionType CatchImageException(Image *image)
607{
608 ExceptionInfo
609 *exception;
610
611 ExceptionType
612 severity;
613
614 assert(image != (const Image *) NULL);
615 assert(image->signature == MagickSignature);
616 if (image->debug != MagickFalse)
617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
618 exception=AcquireExceptionInfo();
619 GetImageException(image,exception);
620 CatchException(exception);
621 severity=exception->severity;
622 exception=DestroyExceptionInfo(exception);
623 return(severity);
624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
631% C l i p I m a g e P a t h %
632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636%
637% ClipImagePath() sets the image clip mask based any clipping path information
638% if it exists.
639%
640% The format of the ClipImagePath method is:
641%
642% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
643% const MagickBooleanType inside)
644%
645% A description of each parameter follows:
646%
647% o image: the image.
648%
649% o pathname: name of clipping path resource. If name is preceded by #, use
650% clipping path numbered by name.
651%
652% o inside: if non-zero, later operations take effect inside clipping path.
653% Otherwise later operations take effect outside clipping path.
654%
655*/
656
657MagickExport MagickBooleanType ClipImage(Image *image)
658{
659 return(ClipImagePath(image,"#1",MagickTrue));
660}
661
662MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
663 const MagickBooleanType inside)
664{
665#define ClipImagePathTag "ClipPath/Image"
666
667 char
668 *property;
669
670 const char
671 *value;
672
673 Image
674 *clip_mask;
675
676 ImageInfo
677 *image_info;
678
679 assert(image != (const Image *) NULL);
680 assert(image->signature == MagickSignature);
681 if (image->debug != MagickFalse)
682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
683 assert(pathname != NULL);
684 property=AcquireString(pathname);
685 (void) FormatMagickString(property,MaxTextExtent,"8BIM:1999,2998:%s",
686 pathname);
687 value=GetImageProperty(image,property);
688 property=DestroyString(property);
689 if (value == (const char *) NULL)
690 {
691 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
692 image->filename);
693 return(MagickFalse);
694 }
695 image_info=AcquireImageInfo();
696 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
697 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
698 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
699 image_info=DestroyImageInfo(image_info);
700 if (clip_mask == (Image *) NULL)
701 return(MagickFalse);
702 if (clip_mask->storage_class == PseudoClass)
703 {
704 (void) SyncImage(clip_mask);
705 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
706 return(MagickFalse);
707 }
708 if (inside == MagickFalse)
709 (void) NegateImage(clip_mask,MagickFalse);
710 (void) FormatMagickString(clip_mask->magick_filename,MaxTextExtent,
711 "8BIM:1999,2998:%s\nPS",pathname);
712 (void) SetImageClipMask(image,clip_mask);
713 clip_mask=DestroyImage(clip_mask);
714 return(MagickTrue);
715}
716
717/*
718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719% %
720% %
721% %
722% C l o n e I m a g e %
723% %
724% %
725% %
726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727%
728% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000729%
cristy3ed852e2009-09-05 21:47:34 +0000730% If the specified columns and rows is 0, an exact copy of the image is
731% returned, otherwise the pixel data is undefined and must be initialized
732% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
733% failure, a NULL image is returned and exception describes the reason for the
734% failure.
735%
736% The format of the CloneImage method is:
737%
cristybb503372010-05-27 20:51:26 +0000738% Image *CloneImage(const Image *image,const size_t columns,
739% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000740% ExceptionInfo *exception)
741%
742% A description of each parameter follows:
743%
744% o image: the image.
745%
746% o columns: the number of columns in the cloned image.
747%
748% o rows: the number of rows in the cloned image.
749%
750% o detach: With a value other than 0, the cloned image is detached from
751% its parent I/O stream.
752%
753% o exception: return any errors or warnings in this structure.
754%
755*/
cristybb503372010-05-27 20:51:26 +0000756MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000757 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000758{
759 Image
760 *clone_image;
761
762 MagickRealType
763 scale;
764
765 size_t
766 length;
767
768 /*
769 Clone the image.
770 */
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(exception != (ExceptionInfo *) NULL);
776 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000777 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000778 if (clone_image == (Image *) NULL)
779 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
780 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
781 clone_image->signature=MagickSignature;
782 clone_image->storage_class=image->storage_class;
783 clone_image->colorspace=image->colorspace;
784 clone_image->matte=image->matte;
785 clone_image->columns=image->columns;
786 clone_image->rows=image->rows;
787 clone_image->dither=image->dither;
788 if (image->colormap != (PixelPacket *) NULL)
789 {
790 /*
791 Allocate and copy the image colormap.
792 */
793 clone_image->colors=image->colors;
794 length=(size_t) image->colors;
795 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
796 sizeof(*clone_image->colormap));
797 if (clone_image->colormap == (PixelPacket *) NULL)
798 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
799 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
800 sizeof(*clone_image->colormap));
801 }
802 (void) CloneImageProfiles(clone_image,image);
803 (void) CloneImageProperties(clone_image,image);
804 (void) CloneImageArtifacts(clone_image,image);
805 GetTimerInfo(&clone_image->timer);
806 GetExceptionInfo(&clone_image->exception);
807 InheritException(&clone_image->exception,&image->exception);
808 if (image->ascii85 != (void *) NULL)
809 Ascii85Initialize(clone_image);
810 clone_image->magick_columns=image->magick_columns;
811 clone_image->magick_rows=image->magick_rows;
812 clone_image->type=image->type;
813 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
814 MaxTextExtent);
815 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
816 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
817 clone_image->progress_monitor=image->progress_monitor;
818 clone_image->client_data=image->client_data;
819 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000820 clone_image->next=image->next;
821 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000822 clone_image->list=NewImageList();
823 clone_image->clip_mask=NewImageList();
824 clone_image->mask=NewImageList();
825 if (detach == MagickFalse)
826 clone_image->blob=ReferenceBlob(image->blob);
827 else
cristybee00932011-01-15 20:28:27 +0000828 {
829 clone_image->next=NewImageList();
830 clone_image->previous=NewImageList();
831 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
832 }
cristy73724512010-04-12 14:43:14 +0000833 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000834 clone_image->debug=IsEventLogging();
835 clone_image->semaphore=AllocateSemaphoreInfo();
836 if ((columns == 0) && (rows == 0))
837 {
838 if (image->montage != (char *) NULL)
839 (void) CloneString(&clone_image->montage,image->montage);
840 if (image->directory != (char *) NULL)
841 (void) CloneString(&clone_image->directory,image->directory);
842 if (image->clip_mask != (Image *) NULL)
843 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
844 exception);
845 if (image->mask != (Image *) NULL)
846 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
847 clone_image->cache=ReferencePixelCache(image->cache);
848 return(clone_image);
849 }
cristy1ab35fb2011-04-15 01:25:56 +0000850 if ((columns == image->columns) && (rows == image->rows))
851 {
852 if (image->clip_mask != (Image *) NULL)
853 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
854 exception);
855 if (image->mask != (Image *) NULL)
856 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
857 }
cristy3ed852e2009-09-05 21:47:34 +0000858 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000859 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
860 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
861 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000862 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000863 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
864 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
865 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000866 clone_image->columns=columns;
867 clone_image->rows=rows;
868 clone_image->cache=ClonePixelCache(image->cache);
869 return(clone_image);
870}
871
872/*
873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
874% %
875% %
876% %
877% C l o n e I m a g e I n f o %
878% %
879% %
880% %
881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882%
883% CloneImageInfo() makes a copy of the given image info structure. If
884% NULL is specified, a new image info structure is created initialized to
885% default values.
886%
887% The format of the CloneImageInfo method is:
888%
889% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
890%
891% A description of each parameter follows:
892%
893% o image_info: the image info.
894%
895*/
896MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
897{
898 ImageInfo
899 *clone_info;
900
901 clone_info=AcquireImageInfo();
902 if (image_info == (ImageInfo *) NULL)
903 return(clone_info);
904 clone_info->compression=image_info->compression;
905 clone_info->temporary=image_info->temporary;
906 clone_info->adjoin=image_info->adjoin;
907 clone_info->antialias=image_info->antialias;
908 clone_info->scene=image_info->scene;
909 clone_info->number_scenes=image_info->number_scenes;
910 clone_info->depth=image_info->depth;
911 if (image_info->size != (char *) NULL)
912 (void) CloneString(&clone_info->size,image_info->size);
913 if (image_info->extract != (char *) NULL)
914 (void) CloneString(&clone_info->extract,image_info->extract);
915 if (image_info->scenes != (char *) NULL)
916 (void) CloneString(&clone_info->scenes,image_info->scenes);
917 if (image_info->page != (char *) NULL)
918 (void) CloneString(&clone_info->page,image_info->page);
919 clone_info->interlace=image_info->interlace;
920 clone_info->endian=image_info->endian;
921 clone_info->units=image_info->units;
922 clone_info->quality=image_info->quality;
923 if (image_info->sampling_factor != (char *) NULL)
924 (void) CloneString(&clone_info->sampling_factor,
925 image_info->sampling_factor);
926 if (image_info->server_name != (char *) NULL)
927 (void) CloneString(&clone_info->server_name,image_info->server_name);
928 if (image_info->font != (char *) NULL)
929 (void) CloneString(&clone_info->font,image_info->font);
930 if (image_info->texture != (char *) NULL)
931 (void) CloneString(&clone_info->texture,image_info->texture);
932 if (image_info->density != (char *) NULL)
933 (void) CloneString(&clone_info->density,image_info->density);
934 clone_info->pointsize=image_info->pointsize;
935 clone_info->fuzz=image_info->fuzz;
936 clone_info->pen=image_info->pen;
937 clone_info->background_color=image_info->background_color;
938 clone_info->border_color=image_info->border_color;
939 clone_info->matte_color=image_info->matte_color;
940 clone_info->transparent_color=image_info->transparent_color;
941 clone_info->dither=image_info->dither;
942 clone_info->monochrome=image_info->monochrome;
943 clone_info->colors=image_info->colors;
944 clone_info->colorspace=image_info->colorspace;
945 clone_info->type=image_info->type;
946 clone_info->orientation=image_info->orientation;
947 clone_info->preview_type=image_info->preview_type;
948 clone_info->group=image_info->group;
949 clone_info->ping=image_info->ping;
950 clone_info->verbose=image_info->verbose;
951 if (image_info->view != (char *) NULL)
952 (void) CloneString(&clone_info->view,image_info->view);
953 if (image_info->authenticate != (char *) NULL)
954 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
955 (void) CloneImageOptions(clone_info,image_info);
956 clone_info->progress_monitor=image_info->progress_monitor;
957 clone_info->client_data=image_info->client_data;
958 clone_info->cache=image_info->cache;
959 if (image_info->cache != (void *) NULL)
960 clone_info->cache=ReferencePixelCache(image_info->cache);
961 if (image_info->profile != (void *) NULL)
962 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
963 image_info->profile);
964 SetImageInfoFile(clone_info,image_info->file);
965 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
966 clone_info->stream=image_info->stream;
967 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
968 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
969 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
970 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
971 (void) CopyMagickString(clone_info->filename,image_info->filename,
972 MaxTextExtent);
973 clone_info->subimage=image_info->scene; /* deprecated */
974 clone_info->subrange=image_info->number_scenes; /* deprecated */
975 clone_info->channel=image_info->channel;
976 clone_info->debug=IsEventLogging();
977 clone_info->signature=image_info->signature;
978 return(clone_info);
979}
980
981/*
982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983% %
984% %
985% %
986% C o m b i n e I m a g e s %
987% %
988% %
989% %
990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991%
992% CombineImages() combines one or more images into a single image. The
993% grayscale value of the pixels of each image in the sequence is assigned in
994% order to the specified channels of the combined image. The typical
995% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
996%
997% The format of the CombineImages method is:
998%
999% Image *CombineImages(const Image *image,const ChannelType channel,
1000% ExceptionInfo *exception)
1001%
1002% A description of each parameter follows:
1003%
1004% o image: the image.
1005%
1006% o exception: return any errors or warnings in this structure.
1007%
1008*/
1009MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1010 ExceptionInfo *exception)
1011{
1012#define CombineImageTag "Combine/Image"
1013
1014 CacheView
1015 *combine_view;
1016
1017 const Image
1018 *next;
1019
1020 Image
1021 *combine_image;
1022
cristy3ed852e2009-09-05 21:47:34 +00001023 MagickBooleanType
1024 status;
1025
cristybb503372010-05-27 20:51:26 +00001026 MagickOffsetType
1027 progress;
1028
1029 ssize_t
1030 y;
1031
cristy3ed852e2009-09-05 21:47:34 +00001032 /*
1033 Ensure the image are the same size.
1034 */
1035 assert(image != (const Image *) NULL);
1036 assert(image->signature == MagickSignature);
1037 if (image->debug != MagickFalse)
1038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1039 assert(exception != (ExceptionInfo *) NULL);
1040 assert(exception->signature == MagickSignature);
1041 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1042 {
1043 if ((next->columns != image->columns) || (next->rows != image->rows))
1044 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1045 }
1046 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1047 if (combine_image == (Image *) NULL)
1048 return((Image *) NULL);
1049 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1050 {
1051 InheritException(exception,&combine_image->exception);
1052 combine_image=DestroyImage(combine_image);
1053 return((Image *) NULL);
1054 }
1055 if ((channel & OpacityChannel) != 0)
1056 combine_image->matte=MagickTrue;
1057 (void) SetImageBackgroundColor(combine_image);
1058 /*
1059 Combine images.
1060 */
1061 status=MagickTrue;
1062 progress=0;
1063 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001064 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001065 {
1066 CacheView
1067 *image_view;
1068
1069 const Image
1070 *next;
1071
1072 PixelPacket
1073 *pixels;
1074
1075 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001076 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001077
cristy3ed852e2009-09-05 21:47:34 +00001078 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001079 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001080
cristycb6d09b2010-06-19 01:59:36 +00001081 register ssize_t
1082 x;
1083
cristy3ed852e2009-09-05 21:47:34 +00001084 if (status == MagickFalse)
1085 continue;
1086 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1087 1,exception);
1088 if (pixels == (PixelPacket *) NULL)
1089 {
1090 status=MagickFalse;
1091 continue;
1092 }
1093 next=image;
1094 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
1095 {
1096 image_view=AcquireCacheView(next);
1097 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1098 if (p == (const PixelPacket *) NULL)
1099 continue;
1100 q=pixels;
cristybb503372010-05-27 20:51:26 +00001101 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001102 {
cristyce70c172010-01-07 17:15:30 +00001103 SetRedPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001104 p++;
1105 q++;
1106 }
1107 image_view=DestroyCacheView(image_view);
1108 next=GetNextImageInList(next);
1109 }
1110 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
1111 {
1112 image_view=AcquireCacheView(next);
1113 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1114 if (p == (const PixelPacket *) NULL)
1115 continue;
1116 q=pixels;
cristybb503372010-05-27 20:51:26 +00001117 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001118 {
cristyce70c172010-01-07 17:15:30 +00001119 SetGreenPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001120 p++;
1121 q++;
1122 }
1123 image_view=DestroyCacheView(image_view);
1124 next=GetNextImageInList(next);
1125 }
1126 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
1127 {
1128 image_view=AcquireCacheView(next);
1129 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1130 if (p == (const PixelPacket *) NULL)
1131 continue;
1132 q=pixels;
cristybb503372010-05-27 20:51:26 +00001133 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
cristyce70c172010-01-07 17:15:30 +00001135 SetBluePixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001136 p++;
1137 q++;
1138 }
1139 image_view=DestroyCacheView(image_view);
1140 next=GetNextImageInList(next);
1141 }
1142 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
1143 {
1144 image_view=AcquireCacheView(next);
1145 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1146 if (p == (const PixelPacket *) NULL)
1147 continue;
1148 q=pixels;
cristybb503372010-05-27 20:51:26 +00001149 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001150 {
cristyce70c172010-01-07 17:15:30 +00001151 SetOpacityPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001152 p++;
1153 q++;
1154 }
1155 image_view=DestroyCacheView(image_view);
1156 next=GetNextImageInList(next);
1157 }
1158 if (((channel & IndexChannel) != 0) &&
1159 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1160 {
1161 IndexPacket
1162 *indexes;
1163
1164 image_view=AcquireCacheView(next);
1165 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1166 if (p == (const PixelPacket *) NULL)
1167 continue;
1168 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
cristybb503372010-05-27 20:51:26 +00001169 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001170 {
1171 indexes[x]=PixelIntensityToQuantum(p);
1172 p++;
1173 }
1174 image_view=DestroyCacheView(image_view);
1175 next=GetNextImageInList(next);
1176 }
1177 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1178 status=MagickFalse;
1179 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1180 {
1181 MagickBooleanType
1182 proceed;
1183
cristy3ed852e2009-09-05 21:47:34 +00001184 proceed=SetImageProgress(image,CombineImageTag,progress++,
1185 combine_image->rows);
1186 if (proceed == MagickFalse)
1187 status=MagickFalse;
1188 }
1189 }
1190 combine_view=DestroyCacheView(combine_view);
1191 if (status == MagickFalse)
1192 combine_image=DestroyImage(combine_image);
1193 return(combine_image);
1194}
1195
1196/*
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198% %
1199% %
1200% %
cristy3ed852e2009-09-05 21:47:34 +00001201% D e s t r o y I m a g e %
1202% %
1203% %
1204% %
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206%
1207% DestroyImage() dereferences an image, deallocating memory associated with
1208% the image if the reference count becomes zero.
1209%
1210% The format of the DestroyImage method is:
1211%
1212% Image *DestroyImage(Image *image)
1213%
1214% A description of each parameter follows:
1215%
1216% o image: the image.
1217%
1218*/
1219MagickExport Image *DestroyImage(Image *image)
1220{
1221 MagickBooleanType
1222 destroy;
1223
1224 /*
1225 Dereference image.
1226 */
1227 assert(image != (Image *) NULL);
1228 assert(image->signature == MagickSignature);
1229 if (image->debug != MagickFalse)
1230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1231 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001232 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001233 image->reference_count--;
1234 if (image->reference_count == 0)
1235 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001236 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001237 if (destroy == MagickFalse)
1238 return((Image *) NULL);
1239 /*
1240 Destroy image.
1241 */
1242 DestroyImagePixels(image);
1243 if (image->clip_mask != (Image *) NULL)
1244 image->clip_mask=DestroyImage(image->clip_mask);
1245 if (image->mask != (Image *) NULL)
1246 image->mask=DestroyImage(image->mask);
1247 if (image->montage != (char *) NULL)
1248 image->montage=DestroyString(image->montage);
1249 if (image->directory != (char *) NULL)
1250 image->directory=DestroyString(image->directory);
1251 if (image->colormap != (PixelPacket *) NULL)
1252 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1253 if (image->geometry != (char *) NULL)
1254 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001255 DestroyImageProfiles(image);
1256 DestroyImageProperties(image);
1257 DestroyImageArtifacts(image);
1258 if (image->ascii85 != (Ascii85Info*) NULL)
1259 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1260 DestroyBlob(image);
1261 (void) DestroyExceptionInfo(&image->exception);
1262 if (image->semaphore != (SemaphoreInfo *) NULL)
1263 DestroySemaphoreInfo(&image->semaphore);
1264 image->signature=(~MagickSignature);
1265 image=(Image *) RelinquishMagickMemory(image);
1266 return(image);
1267}
1268
1269/*
1270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271% %
1272% %
1273% %
1274% D e s t r o y I m a g e I n f o %
1275% %
1276% %
1277% %
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279%
1280% DestroyImageInfo() deallocates memory associated with an ImageInfo
1281% structure.
1282%
1283% The format of the DestroyImageInfo method is:
1284%
1285% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1286%
1287% A description of each parameter follows:
1288%
1289% o image_info: the image info.
1290%
1291*/
1292MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1293{
1294 assert(image_info != (ImageInfo *) NULL);
1295 assert(image_info->signature == MagickSignature);
1296 if (image_info->debug != MagickFalse)
1297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1298 image_info->filename);
1299 if (image_info->size != (char *) NULL)
1300 image_info->size=DestroyString(image_info->size);
1301 if (image_info->extract != (char *) NULL)
1302 image_info->extract=DestroyString(image_info->extract);
1303 if (image_info->scenes != (char *) NULL)
1304 image_info->scenes=DestroyString(image_info->scenes);
1305 if (image_info->page != (char *) NULL)
1306 image_info->page=DestroyString(image_info->page);
1307 if (image_info->sampling_factor != (char *) NULL)
1308 image_info->sampling_factor=DestroyString(
1309 image_info->sampling_factor);
1310 if (image_info->server_name != (char *) NULL)
1311 image_info->server_name=DestroyString(
1312 image_info->server_name);
1313 if (image_info->font != (char *) NULL)
1314 image_info->font=DestroyString(image_info->font);
1315 if (image_info->texture != (char *) NULL)
1316 image_info->texture=DestroyString(image_info->texture);
1317 if (image_info->density != (char *) NULL)
1318 image_info->density=DestroyString(image_info->density);
1319 if (image_info->view != (char *) NULL)
1320 image_info->view=DestroyString(image_info->view);
1321 if (image_info->authenticate != (char *) NULL)
1322 image_info->authenticate=DestroyString(
1323 image_info->authenticate);
1324 DestroyImageOptions(image_info);
1325 if (image_info->cache != (void *) NULL)
1326 image_info->cache=DestroyPixelCache(image_info->cache);
1327 if (image_info->profile != (StringInfo *) NULL)
1328 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1329 image_info->profile);
1330 image_info->signature=(~MagickSignature);
1331 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1332 return(image_info);
1333}
1334
1335/*
1336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337% %
1338% %
1339% %
1340+ D i s a s s o c i a t e I m a g e S t r e a m %
1341% %
1342% %
1343% %
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345%
1346% DisassociateImageStream() disassociates the image stream.
1347%
1348% The format of the DisassociateImageStream method is:
1349%
1350% MagickBooleanType DisassociateImageStream(const Image *image)
1351%
1352% A description of each parameter follows:
1353%
1354% o image: the image.
1355%
1356*/
1357MagickExport void DisassociateImageStream(Image *image)
1358{
1359 assert(image != (const Image *) NULL);
1360 assert(image->signature == MagickSignature);
1361 if (image->debug != MagickFalse)
1362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1363 (void) DetachBlob(image->blob);
1364}
1365
1366/*
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368% %
1369% %
1370% %
1371% G e t I m a g e A l p h a C h a n n e l %
1372% %
1373% %
1374% %
1375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376%
1377% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1378% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1379% than CMYKA.
1380%
1381% The format of the GetImageAlphaChannel method is:
1382%
1383% MagickBooleanType GetImageAlphaChannel(const Image *image)
1384%
1385% A description of each parameter follows:
1386%
1387% o image: the image.
1388%
1389*/
1390MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1391{
1392 assert(image != (const Image *) NULL);
1393 if (image->debug != MagickFalse)
1394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1395 assert(image->signature == MagickSignature);
1396 return(image->matte);
1397}
1398
1399/*
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401% %
1402% %
1403% %
1404% G e t I m a g e C l i p M a s k %
1405% %
1406% %
1407% %
1408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409%
1410% GetImageClipMask() returns the clip path associated with the image.
1411%
1412% The format of the GetImageClipMask method is:
1413%
1414% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1415%
1416% A description of each parameter follows:
1417%
1418% o image: the image.
1419%
1420*/
1421MagickExport Image *GetImageClipMask(const Image *image,
1422 ExceptionInfo *exception)
1423{
1424 assert(image != (const Image *) NULL);
1425 if (image->debug != MagickFalse)
1426 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1427 assert(image->signature == MagickSignature);
1428 if (image->clip_mask == (Image *) NULL)
1429 return((Image *) NULL);
1430 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1431}
1432
1433/*
1434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435% %
1436% %
1437% %
1438% G e t I m a g e E x c e p t i o n %
1439% %
1440% %
1441% %
1442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443%
1444% GetImageException() traverses an image sequence and returns any
1445% error more severe than noted by the exception parameter.
1446%
1447% The format of the GetImageException method is:
1448%
1449% void GetImageException(Image *image,ExceptionInfo *exception)
1450%
1451% A description of each parameter follows:
1452%
1453% o image: Specifies a pointer to a list of one or more images.
1454%
1455% o exception: return the highest severity exception.
1456%
1457*/
1458MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1459{
1460 register Image
1461 *next;
1462
1463 assert(image != (Image *) NULL);
1464 assert(image->signature == MagickSignature);
1465 if (image->debug != MagickFalse)
1466 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1467 assert(exception != (ExceptionInfo *) NULL);
1468 assert(exception->signature == MagickSignature);
1469 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1470 {
1471 if (next->exception.severity == UndefinedException)
1472 continue;
1473 if (next->exception.severity > exception->severity)
1474 InheritException(exception,&next->exception);
1475 next->exception.severity=UndefinedException;
1476 }
1477}
1478
1479/*
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481% %
1482% %
1483% %
1484% G e t I m a g e I n f o %
1485% %
1486% %
1487% %
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489%
1490% GetImageInfo() initializes image_info to default values.
1491%
1492% The format of the GetImageInfo method is:
1493%
1494% void GetImageInfo(ImageInfo *image_info)
1495%
1496% A description of each parameter follows:
1497%
1498% o image_info: the image info.
1499%
1500*/
1501MagickExport void GetImageInfo(ImageInfo *image_info)
1502{
cristyd9a29192010-10-16 16:49:53 +00001503 const char
1504 *synchronize;
1505
cristy3ed852e2009-09-05 21:47:34 +00001506 ExceptionInfo
1507 *exception;
1508
1509 /*
1510 File and image dimension members.
1511 */
1512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1513 assert(image_info != (ImageInfo *) NULL);
1514 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1515 image_info->adjoin=MagickTrue;
1516 image_info->interlace=NoInterlace;
1517 image_info->channel=DefaultChannels;
1518 image_info->quality=UndefinedCompressionQuality;
1519 image_info->antialias=MagickTrue;
1520 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001521 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1522 if (synchronize != (const char *) NULL)
1523 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001524 exception=AcquireExceptionInfo();
1525 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1526 exception);
1527 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1528 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1529 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1530 exception);
1531 exception=DestroyExceptionInfo(exception);
1532 image_info->debug=IsEventLogging();
1533 image_info->signature=MagickSignature;
1534}
1535
1536/*
1537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538% %
1539% %
1540% %
cristy15781e52009-12-05 23:05:27 +00001541% G e t I m a g e I n f o F i l e %
1542% %
1543% %
1544% %
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546%
1547% GetImageInfoFile() returns the image info file member.
1548%
1549% The format of the GetImageInfoFile method is:
1550%
1551% FILE *GetImageInfoFile(const ImageInfo *image_info)
1552%
1553% A description of each parameter follows:
1554%
1555% o image_info: the image info.
1556%
1557*/
1558MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1559{
1560 return(image_info->file);
1561}
1562
1563/*
1564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565% %
1566% %
1567% %
cristy3ed852e2009-09-05 21:47:34 +00001568% G e t I m a g e M a s k %
1569% %
1570% %
1571% %
1572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573%
1574% GetImageMask() returns the mask associated with the image.
1575%
1576% The format of the GetImageMask method is:
1577%
1578% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1579%
1580% A description of each parameter follows:
1581%
1582% o image: the image.
1583%
1584*/
1585MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1586{
1587 assert(image != (const Image *) NULL);
1588 if (image->debug != MagickFalse)
1589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1590 assert(image->signature == MagickSignature);
1591 if (image->mask == (Image *) NULL)
1592 return((Image *) NULL);
1593 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1594}
1595
1596/*
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598% %
1599% %
1600% %
cristy0d267172011-04-25 20:13:48 +00001601% G e t I m a g e C h a n n e l s %
1602% %
1603% %
1604% %
1605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606%
cristy6cb60a52011-04-25 20:33:58 +00001607% GetImageChannels() returns the number of pixel channels associated with the
1608% specified image.
cristy0d267172011-04-25 20:13:48 +00001609%
1610% The format of the GetChannels method is:
1611%
1612% size_t GetImageChannels(Image *image)
1613%
1614% A description of each parameter follows:
1615%
1616% o image: the image.
1617%
1618*/
1619MagickExport size_t GetImageChannels(Image *image)
1620{
1621 assert(image != (Image *) NULL);
1622 assert(image->signature == MagickSignature);
1623 if (image->debug != MagickFalse)
1624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1625 return(image->channels);
1626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
cristy3ed852e2009-09-05 21:47:34 +00001633+ G e t I m a g e R e f e r e n c e C o u n t %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetImageReferenceCount() returns the image reference count.
1640%
1641% The format of the GetReferenceCount method is:
1642%
cristybb503372010-05-27 20:51:26 +00001643% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001644%
1645% A description of each parameter follows:
1646%
1647% o image: the image.
1648%
1649*/
cristybb503372010-05-27 20:51:26 +00001650MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001651{
cristybb503372010-05-27 20:51:26 +00001652 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001653 reference_count;
1654
1655 assert(image != (Image *) NULL);
1656 assert(image->signature == MagickSignature);
1657 if (image->debug != MagickFalse)
1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001659 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001660 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001661 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001662 return(reference_count);
1663}
1664
1665/*
1666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667% %
1668% %
1669% %
cristy3ed852e2009-09-05 21:47:34 +00001670% 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 %
1671% %
1672% %
1673% %
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675%
1676% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1677% image. A virtual pixel is any pixel access that is outside the boundaries
1678% of the image cache.
1679%
1680% The format of the GetImageVirtualPixelMethod() method is:
1681%
1682% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1683%
1684% A description of each parameter follows:
1685%
1686% o image: the image.
1687%
1688*/
1689MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1690{
1691 assert(image != (Image *) NULL);
1692 assert(image->signature == MagickSignature);
1693 if (image->debug != MagickFalse)
1694 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1695 return(GetPixelCacheVirtualMethod(image));
1696}
1697
1698/*
1699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1700% %
1701% %
1702% %
1703% I n t e r p r e t I m a g e F i l e n a m e %
1704% %
1705% %
1706% %
1707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708%
1709% InterpretImageFilename() interprets embedded characters in an image filename.
1710% The filename length is returned.
1711%
1712% The format of the InterpretImageFilename method is:
1713%
1714% size_t InterpretImageFilename(const ImageInfo *image_info,
1715% Image *image,const char *format,int value,char *filename)
1716%
1717% A description of each parameter follows.
1718%
1719% o image_info: the image info..
1720%
1721% o image: the image.
1722%
1723% o format: A filename describing the format to use to write the numeric
1724% argument. Only the first numeric format identifier is replaced.
1725%
1726% o value: Numeric value to substitute into format filename.
1727%
1728% o filename: return the formatted filename in this character buffer.
1729%
1730*/
1731MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1732 Image *image,const char *format,int value,char *filename)
1733{
1734 char
1735 *q;
1736
1737 int
1738 c;
1739
1740 MagickBooleanType
1741 canonical;
1742
1743 register const char
1744 *p;
1745
1746 canonical=MagickFalse;
1747 (void) CopyMagickString(filename,format,MaxTextExtent);
1748 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1749 {
1750 q=(char *) p+1;
1751 if (*q == '%')
1752 {
1753 p=q+1;
1754 continue;
1755 }
1756 if (*q == '0')
1757 {
cristybb503372010-05-27 20:51:26 +00001758 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001759 value;
1760
cristybb503372010-05-27 20:51:26 +00001761 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001762 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001763 }
1764 switch (*q)
1765 {
1766 case 'd':
1767 case 'o':
1768 case 'x':
1769 {
1770 q++;
1771 c=(*q);
1772 *q='\0';
1773 (void) FormatMagickString(filename+(p-format),(size_t) (MaxTextExtent-
1774 (p-format)),p,value);
1775 *q=c;
1776 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1777 canonical=MagickTrue;
1778 if (*(q-1) != '%')
1779 break;
1780 p++;
1781 break;
1782 }
1783 case '[':
1784 {
1785 char
1786 pattern[MaxTextExtent];
1787
1788 const char
1789 *value;
1790
cristy3ed852e2009-09-05 21:47:34 +00001791 register char
1792 *r;
1793
cristybb503372010-05-27 20:51:26 +00001794 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001795 i;
1796
cristycb6d09b2010-06-19 01:59:36 +00001797 ssize_t
1798 depth;
1799
cristy3ed852e2009-09-05 21:47:34 +00001800 /*
1801 Image option.
1802 */
1803 if (strchr(p,']') == (char *) NULL)
1804 break;
1805 depth=1;
1806 r=q+1;
1807 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1808 {
1809 if (*r == '[')
1810 depth++;
1811 if (*r == ']')
1812 depth--;
1813 if (depth <= 0)
1814 break;
1815 pattern[i]=(*r++);
1816 }
1817 pattern[i]='\0';
1818 if (LocaleNCompare(pattern,"filename:",9) != 0)
1819 break;
1820 value=(const char *) NULL;
1821 if ((image_info != (const ImageInfo *) NULL) &&
1822 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001823 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001824 else
1825 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001826 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001827 else
1828 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001829 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001830 if (value == (const char *) NULL)
1831 break;
1832 q--;
1833 c=(*q);
1834 *q='\0';
1835 (void) CopyMagickString(filename+(p-format),value,(size_t)
1836 (MaxTextExtent-(p-format)));
1837 *q=c;
1838 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1839 canonical=MagickTrue;
1840 if (*(q-1) != '%')
1841 break;
1842 p++;
1843 break;
1844 }
1845 default:
1846 break;
1847 }
1848 }
1849 for (q=filename; *q != '\0'; q++)
1850 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001851 {
1852 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1853 canonical=MagickTrue;
1854 }
cristy3ed852e2009-09-05 21:47:34 +00001855 if (canonical == MagickFalse)
1856 (void) CopyMagickString(filename,format,MaxTextExtent);
1857 return(strlen(filename));
1858}
1859
1860/*
1861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862% %
1863% %
1864% %
1865% I s H i g h D y n a m i c R a n g e I m a g e %
1866% %
1867% %
1868% %
1869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1870%
1871% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1872% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1873% 0..65535.
1874%
1875% The format of the IsHighDynamicRangeImage method is:
1876%
1877% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1878% ExceptionInfo *exception)
1879%
1880% A description of each parameter follows:
1881%
1882% o image: the image.
1883%
1884% o exception: return any errors or warnings in this structure.
1885%
1886*/
1887MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1888 ExceptionInfo *exception)
1889{
1890#if !defined(MAGICKCORE_HDRI_SUPPORT)
1891 (void) image;
1892 (void) exception;
1893 return(MagickFalse);
1894#else
1895 CacheView
1896 *image_view;
1897
cristy3ed852e2009-09-05 21:47:34 +00001898 MagickBooleanType
1899 status;
1900
1901 MagickPixelPacket
1902 zero;
1903
cristycb6d09b2010-06-19 01:59:36 +00001904 ssize_t
1905 y;
1906
cristy3ed852e2009-09-05 21:47:34 +00001907 assert(image != (Image *) NULL);
1908 assert(image->signature == MagickSignature);
1909 if (image->debug != MagickFalse)
1910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1911 status=MagickTrue;
1912 GetMagickPixelPacket(image,&zero);
1913 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001914#if defined(MAGICKCORE_OPENMP_SUPPORT)
1915 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001916#endif
cristybb503372010-05-27 20:51:26 +00001917 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001918 {
1919 MagickPixelPacket
1920 pixel;
1921
1922 register const IndexPacket
1923 *indexes;
1924
1925 register const PixelPacket
1926 *p;
1927
cristybb503372010-05-27 20:51:26 +00001928 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001929 x;
1930
1931 if (status == MagickFalse)
1932 continue;
1933 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1934 if (p == (const PixelPacket *) NULL)
1935 {
1936 status=MagickFalse;
1937 continue;
1938 }
1939 indexes=GetCacheViewVirtualIndexQueue(image_view);
1940 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001941 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001942 {
1943 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1944 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1945 (pixel.red != (QuantumAny) pixel.red))
1946 break;
1947 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1948 (pixel.green != (QuantumAny) pixel.green))
1949 break;
1950 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1951 (pixel.blue != (QuantumAny) pixel.blue))
1952 break;
1953 if (pixel.matte != MagickFalse)
1954 {
1955 if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
1956 (pixel.opacity != (QuantumAny) pixel.opacity))
1957 break;
1958 }
1959 if (pixel.colorspace == CMYKColorspace)
1960 {
1961 if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
1962 (pixel.index != (QuantumAny) pixel.index))
1963 break;
1964 }
1965 p++;
1966 }
cristybb503372010-05-27 20:51:26 +00001967 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001968 status=MagickFalse;
1969 }
1970 image_view=DestroyCacheView(image_view);
1971 return(status != MagickFalse ? MagickFalse : MagickTrue);
1972#endif
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980% I s I m a g e O b j e c t %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% IsImageObject() returns MagickTrue if the image sequence contains a valid
1987% set of image objects.
1988%
1989% The format of the IsImageObject method is:
1990%
1991% MagickBooleanType IsImageObject(const Image *image)
1992%
1993% A description of each parameter follows:
1994%
1995% o image: the image.
1996%
1997*/
1998MagickExport MagickBooleanType IsImageObject(const Image *image)
1999{
2000 register const Image
2001 *p;
2002
2003 assert(image != (Image *) NULL);
2004 if (image->debug != MagickFalse)
2005 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2006 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2007 if (p->signature != MagickSignature)
2008 return(MagickFalse);
2009 return(MagickTrue);
2010}
2011
2012/*
2013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014% %
2015% %
2016% %
2017% I s T a i n t I m a g e %
2018% %
2019% %
2020% %
2021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022%
2023% IsTaintImage() returns MagickTrue any pixel in the image has been altered
2024% since it was first constituted.
2025%
2026% The format of the IsTaintImage method is:
2027%
2028% MagickBooleanType IsTaintImage(const Image *image)
2029%
2030% A description of each parameter follows:
2031%
2032% o image: the image.
2033%
2034*/
2035MagickExport MagickBooleanType IsTaintImage(const Image *image)
2036{
2037 char
2038 magick[MaxTextExtent],
2039 filename[MaxTextExtent];
2040
2041 register const Image
2042 *p;
2043
2044 assert(image != (Image *) NULL);
2045 if (image->debug != MagickFalse)
2046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2047 assert(image->signature == MagickSignature);
2048 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2049 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2050 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2051 {
2052 if (p->taint != MagickFalse)
2053 return(MagickTrue);
2054 if (LocaleCompare(p->magick,magick) != 0)
2055 return(MagickTrue);
2056 if (LocaleCompare(p->filename,filename) != 0)
2057 return(MagickTrue);
2058 }
2059 return(MagickFalse);
2060}
2061
2062/*
2063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2064% %
2065% %
2066% %
2067% M o d i f y I m a g e %
2068% %
2069% %
2070% %
2071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072%
2073% ModifyImage() ensures that there is only a single reference to the image
2074% to be modified, updating the provided image pointer to point to a clone of
2075% the original image if necessary.
2076%
2077% The format of the ModifyImage method is:
2078%
2079% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2080%
2081% A description of each parameter follows:
2082%
2083% o image: the image.
2084%
2085% o exception: return any errors or warnings in this structure.
2086%
2087*/
2088MagickExport MagickBooleanType ModifyImage(Image **image,
2089 ExceptionInfo *exception)
2090{
2091 Image
2092 *clone_image;
2093
2094 assert(image != (Image **) NULL);
2095 assert(*image != (Image *) NULL);
2096 assert((*image)->signature == MagickSignature);
2097 if ((*image)->debug != MagickFalse)
2098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2099 if (GetImageReferenceCount(*image) <= 1)
2100 return(MagickTrue);
2101 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002102 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002103 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002104 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002105 *image=clone_image;
2106 return(MagickTrue);
2107}
2108
2109/*
2110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111% %
2112% %
2113% %
2114% N e w M a g i c k I m a g e %
2115% %
2116% %
2117% %
2118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119%
2120% NewMagickImage() creates a blank image canvas of the specified size and
2121% background color.
2122%
2123% The format of the NewMagickImage method is:
2124%
2125% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002126% const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002127% const MagickPixelPacket *background)
2128%
2129% A description of each parameter follows:
2130%
2131% o image: the image.
2132%
2133% o width: the image width.
2134%
2135% o height: the image height.
2136%
2137% o background: the image color.
2138%
2139*/
2140MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002141 const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002142 const MagickPixelPacket *background)
2143{
2144 CacheView
2145 *image_view;
2146
2147 ExceptionInfo
2148 *exception;
2149
2150 Image
2151 *image;
2152
cristybb503372010-05-27 20:51:26 +00002153 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002154 y;
2155
2156 MagickBooleanType
2157 status;
2158
2159 assert(image_info != (const ImageInfo *) NULL);
2160 if (image_info->debug != MagickFalse)
2161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2162 assert(image_info->signature == MagickSignature);
2163 assert(background != (const MagickPixelPacket *) NULL);
2164 image=AcquireImage(image_info);
2165 image->columns=width;
2166 image->rows=height;
2167 image->colorspace=background->colorspace;
2168 image->matte=background->matte;
2169 image->fuzz=background->fuzz;
2170 image->depth=background->depth;
2171 status=MagickTrue;
2172 exception=(&image->exception);
2173 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002174#if defined(MAGICKCORE_OPENMP_SUPPORT)
2175 #pragma omp parallel for schedule(dynamic,4) shared(status)
2176#endif
cristybb503372010-05-27 20:51:26 +00002177 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002178 {
2179 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002180 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002181
cristy3ed852e2009-09-05 21:47:34 +00002182 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002183 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002184
cristycb6d09b2010-06-19 01:59:36 +00002185 register ssize_t
2186 x;
2187
cristy48974b92009-12-19 02:36:06 +00002188 if (status == MagickFalse)
2189 continue;
cristy3ed852e2009-09-05 21:47:34 +00002190 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2191 if (q == (PixelPacket *) NULL)
2192 {
2193 status=MagickFalse;
2194 continue;
2195 }
2196 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002197 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002198 {
2199 SetPixelPacket(image,background,q,indexes+x);
2200 q++;
2201 }
2202 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2203 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002204 }
2205 image_view=DestroyCacheView(image_view);
2206 if (status == MagickFalse)
2207 image=DestroyImage(image);
2208 return(image);
2209}
2210
2211/*
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213% %
2214% %
2215% %
2216% R e f e r e n c e I m a g e %
2217% %
2218% %
2219% %
2220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221%
2222% ReferenceImage() increments the reference count associated with an image
2223% returning a pointer to the image.
2224%
2225% The format of the ReferenceImage method is:
2226%
2227% Image *ReferenceImage(Image *image)
2228%
2229% A description of each parameter follows:
2230%
2231% o image: the image.
2232%
2233*/
2234MagickExport Image *ReferenceImage(Image *image)
2235{
2236 assert(image != (Image *) NULL);
2237 if (image->debug != MagickFalse)
2238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2239 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002240 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002241 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002242 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002243 return(image);
2244}
2245
2246/*
2247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248% %
2249% %
2250% %
2251% R e s e t I m a g e P a g e %
2252% %
2253% %
2254% %
2255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2256%
2257% ResetImagePage() resets the image page canvas and position.
2258%
2259% The format of the ResetImagePage method is:
2260%
2261% MagickBooleanType ResetImagePage(Image *image,const char *page)
2262%
2263% A description of each parameter follows:
2264%
2265% o image: the image.
2266%
2267% o page: the relative page specification.
2268%
2269*/
2270MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2271{
2272 MagickStatusType
2273 flags;
2274
2275 RectangleInfo
2276 geometry;
2277
2278 assert(image != (Image *) NULL);
2279 assert(image->signature == MagickSignature);
2280 if (image->debug != MagickFalse)
2281 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2282 flags=ParseAbsoluteGeometry(page,&geometry);
2283 if ((flags & WidthValue) != 0)
2284 {
2285 if ((flags & HeightValue) == 0)
2286 geometry.height=geometry.width;
2287 image->page.width=geometry.width;
2288 image->page.height=geometry.height;
2289 }
2290 if ((flags & AspectValue) != 0)
2291 {
2292 if ((flags & XValue) != 0)
2293 image->page.x+=geometry.x;
2294 if ((flags & YValue) != 0)
2295 image->page.y+=geometry.y;
2296 }
2297 else
2298 {
2299 if ((flags & XValue) != 0)
2300 {
2301 image->page.x=geometry.x;
2302 if ((image->page.width == 0) && (geometry.x > 0))
2303 image->page.width=image->columns+geometry.x;
2304 }
2305 if ((flags & YValue) != 0)
2306 {
2307 image->page.y=geometry.y;
2308 if ((image->page.height == 0) && (geometry.y > 0))
2309 image->page.height=image->rows+geometry.y;
2310 }
2311 }
2312 return(MagickTrue);
2313}
2314
2315/*
2316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317% %
2318% %
2319% %
2320% S e p a r a t e I m a g e C h a n n e l %
2321% %
2322% %
2323% %
2324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325%
2326% SeparateImageChannel() separates a channel from the image and returns it as
2327% a grayscale image. A channel is a particular color component of each pixel
2328% in the image.
2329%
2330% The format of the SeparateImageChannel method is:
2331%
2332% MagickBooleanType SeparateImageChannel(Image *image,
2333% const ChannelType channel)
2334%
2335% A description of each parameter follows:
2336%
2337% o image: the image.
2338%
2339% o channel: Identify which channel to extract: RedChannel, GreenChannel,
2340% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2341% YellowChannel, or BlackChannel.
2342%
2343*/
2344MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2345 const ChannelType channel)
2346{
2347#define SeparateImageTag "Separate/Image"
2348
2349 CacheView
2350 *image_view;
2351
2352 ExceptionInfo
2353 *exception;
2354
cristy3ed852e2009-09-05 21:47:34 +00002355 MagickBooleanType
2356 status;
2357
cristybb503372010-05-27 20:51:26 +00002358 MagickOffsetType
2359 progress;
2360
2361 ssize_t
2362 y;
2363
cristy3ed852e2009-09-05 21:47:34 +00002364 assert(image != (Image *) NULL);
2365 assert(image->signature == MagickSignature);
2366 if (image->debug != MagickFalse)
2367 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2368 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2369 return(MagickFalse);
2370 /*
2371 Separate image channels.
2372 */
2373 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002374 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002375 image->matte=MagickTrue;
2376 progress=0;
2377 exception=(&image->exception);
2378 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002379#if defined(MAGICKCORE_OPENMP_SUPPORT)
2380 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002381#endif
cristybb503372010-05-27 20:51:26 +00002382 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002383 {
2384 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002385 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002386
cristy3ed852e2009-09-05 21:47:34 +00002387 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002388 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002389
cristycb6d09b2010-06-19 01:59:36 +00002390 register ssize_t
2391 x;
2392
cristy3ed852e2009-09-05 21:47:34 +00002393 if (status == MagickFalse)
2394 continue;
2395 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2396 if (q == (PixelPacket *) NULL)
2397 {
2398 status=MagickFalse;
2399 continue;
2400 }
2401 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2402 switch (channel)
2403 {
2404 case RedChannel:
2405 {
cristybb503372010-05-27 20:51:26 +00002406 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002407 {
cristyc5071682011-04-22 02:06:27 +00002408 SetGreenPixelComponent(q,GetRedPixelComponent(q));
2409 SetBluePixelComponent(q,GetRedPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002410 q++;
2411 }
2412 break;
2413 }
2414 case GreenChannel:
2415 {
cristybb503372010-05-27 20:51:26 +00002416 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002417 {
cristyc5071682011-04-22 02:06:27 +00002418 SetRedPixelComponent(q,GetGreenPixelComponent(q));
2419 SetBluePixelComponent(q,GetGreenPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002420 q++;
2421 }
2422 break;
2423 }
2424 case BlueChannel:
2425 {
cristybb503372010-05-27 20:51:26 +00002426 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002427 {
cristyc5071682011-04-22 02:06:27 +00002428 SetRedPixelComponent(q,GetBluePixelComponent(q));
2429 SetGreenPixelComponent(q,GetBluePixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002430 q++;
2431 }
2432 break;
2433 }
2434 case OpacityChannel:
2435 {
cristybb503372010-05-27 20:51:26 +00002436 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002437 {
cristyc5071682011-04-22 02:06:27 +00002438 SetRedPixelComponent(q,GetOpacityPixelComponent(q));
2439 SetGreenPixelComponent(q,GetOpacityPixelComponent(q));
2440 SetBluePixelComponent(q,GetOpacityPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002441 q++;
2442 }
2443 break;
2444 }
2445 case BlackChannel:
2446 {
2447 if ((image->storage_class != PseudoClass) &&
2448 (image->colorspace != CMYKColorspace))
2449 break;
cristybb503372010-05-27 20:51:26 +00002450 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002451 {
cristyc5071682011-04-22 02:06:27 +00002452 SetRedPixelComponent(q,indexes[x]);
2453 SetGreenPixelComponent(q,indexes[x]);
2454 SetBluePixelComponent(q,indexes[x]);
cristy3ed852e2009-09-05 21:47:34 +00002455 q++;
2456 }
2457 break;
2458 }
2459 case TrueAlphaChannel:
2460 {
cristybb503372010-05-27 20:51:26 +00002461 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002462 {
cristy4e82e512011-04-24 01:33:42 +00002463 SetRedPixelComponent(q,GetAlphaPixelComponent(q));
2464 SetGreenPixelComponent(q,GetAlphaPixelComponent(q));
2465 SetBluePixelComponent(q,GetAlphaPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002466 q++;
2467 }
2468 break;
2469 }
2470 case GrayChannels:
2471 {
cristybb503372010-05-27 20:51:26 +00002472 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002473 {
cristy4e82e512011-04-24 01:33:42 +00002474 SetOpacityPixelComponent(q,(QuantumRange-
cristyc5071682011-04-22 02:06:27 +00002475 PixelIntensityToQuantum(q)));
cristy3ed852e2009-09-05 21:47:34 +00002476 q++;
2477 }
2478 break;
2479 }
2480 default:
2481 break;
2482 }
2483 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2484 status=MagickFalse;
2485 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2486 {
2487 MagickBooleanType
2488 proceed;
2489
cristyb5d5f722009-11-04 03:03:49 +00002490#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002491 #pragma omp critical (MagickCore_SeparateImageChannel)
2492#endif
2493 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2494 if (proceed == MagickFalse)
2495 status=MagickFalse;
2496 }
2497 }
2498 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002499 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002500 image->matte=MagickFalse;
2501 (void) SetImageColorspace(image,RGBColorspace);
2502 return(status);
2503}
2504
2505/*
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507% %
2508% %
2509% %
2510% S e p a r a t e I m a g e s %
2511% %
2512% %
2513% %
2514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2515%
2516% SeparateImages() returns a separate grayscale image for each channel
2517% specified.
2518%
2519% The format of the SeparateImages method is:
2520%
2521% MagickBooleanType SeparateImages(const Image *image,
2522% const ChannelType channel,ExceptionInfo *exception)
2523%
2524% A description of each parameter follows:
2525%
2526% o image: the image.
2527%
2528% o channel: Identify which channels to extract: RedChannel, GreenChannel,
2529% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2530% YellowChannel, or BlackChannel.
2531%
2532% o exception: return any errors or warnings in this structure.
2533%
2534*/
2535MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2536 ExceptionInfo *exception)
2537{
2538 Image
2539 *images,
2540 *separate_image;
2541
2542 assert(image != (Image *) NULL);
2543 assert(image->signature == MagickSignature);
2544 if (image->debug != MagickFalse)
2545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2546 images=NewImageList();
2547 if ((channel & RedChannel) != 0)
2548 {
2549 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2550 (void) SeparateImageChannel(separate_image,RedChannel);
2551 AppendImageToList(&images,separate_image);
2552 }
2553 if ((channel & GreenChannel) != 0)
2554 {
2555 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2556 (void) SeparateImageChannel(separate_image,GreenChannel);
2557 AppendImageToList(&images,separate_image);
2558 }
2559 if ((channel & BlueChannel) != 0)
2560 {
2561 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2562 (void) SeparateImageChannel(separate_image,BlueChannel);
2563 AppendImageToList(&images,separate_image);
2564 }
2565 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
2566 {
2567 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2568 (void) SeparateImageChannel(separate_image,BlackChannel);
2569 AppendImageToList(&images,separate_image);
2570 }
2571 if ((channel & OpacityChannel) != 0)
2572 {
2573 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2574 (void) SeparateImageChannel(separate_image,OpacityChannel);
2575 AppendImageToList(&images,separate_image);
2576 }
2577 return(images);
2578}
2579
2580/*
2581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582% %
2583% %
2584% %
2585% S e t I m a g e A l p h a C h a n n e l %
2586% %
2587% %
2588% %
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590%
2591% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2592% channel.
2593%
2594% The format of the SetImageAlphaChannel method is:
2595%
2596% MagickBooleanType SetImageAlphaChannel(Image *image,
2597% const AlphaChannelType alpha_type)
2598%
2599% A description of each parameter follows:
2600%
2601% o image: the image.
2602%
2603% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2604% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
2605% OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
2606% ShapeAlphaChannel, and TransparentAlphaChannel.
2607%
2608*/
2609MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2610 const AlphaChannelType alpha_type)
2611{
2612 MagickBooleanType
2613 status;
2614
2615 assert(image != (Image *) NULL);
2616 if (image->debug != MagickFalse)
2617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2618 assert(image->signature == MagickSignature);
2619 status=MagickFalse;
2620 switch (alpha_type)
2621 {
2622 case ActivateAlphaChannel:
2623 {
2624 image->matte=MagickTrue;
2625 break;
2626 }
2627 case BackgroundAlphaChannel:
2628 {
2629 CacheView
2630 *image_view;
2631
2632 ExceptionInfo
2633 *exception;
2634
2635 IndexPacket
2636 index;
2637
cristy3ed852e2009-09-05 21:47:34 +00002638 MagickBooleanType
2639 status;
2640
2641 MagickPixelPacket
2642 background;
2643
2644 PixelPacket
2645 pixel;
2646
cristycb6d09b2010-06-19 01:59:36 +00002647 ssize_t
2648 y;
2649
cristy3ed852e2009-09-05 21:47:34 +00002650 /*
2651 Set transparent pixels to background color.
2652 */
2653 if (image->matte == MagickFalse)
2654 break;
2655 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2656 break;
2657 GetMagickPixelPacket(image,&background);
2658 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2659 NULL,&background);
2660 if (image->colorspace == CMYKColorspace)
2661 ConvertRGBToCMYK(&background);
2662 index=0;
2663 SetPixelPacket(image,&background,&pixel,&index);
2664 status=MagickTrue;
2665 exception=(&image->exception);
2666 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002667 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2668 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002669 #endif
cristybb503372010-05-27 20:51:26 +00002670 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002671 {
2672 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002673 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002674
cristy3ed852e2009-09-05 21:47:34 +00002675 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002676 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002677
cristycb6d09b2010-06-19 01:59:36 +00002678 register ssize_t
2679 x;
2680
cristy3ed852e2009-09-05 21:47:34 +00002681 if (status == MagickFalse)
2682 continue;
2683 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2684 exception);
2685 if (q == (PixelPacket *) NULL)
2686 {
2687 status=MagickFalse;
2688 continue;
2689 }
cristybb503372010-05-27 20:51:26 +00002690 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002691 {
2692 if (q->opacity == TransparentOpacity)
2693 {
cristya2d08742011-04-22 19:59:52 +00002694 SetRedPixelComponent(q,pixel.red);
2695 SetGreenPixelComponent(q,pixel.green);
2696 SetBluePixelComponent(q,pixel.blue);
cristy3ed852e2009-09-05 21:47:34 +00002697 }
2698 q++;
2699 }
2700 if (image->colorspace == CMYKColorspace)
2701 {
2702 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002703 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002704 indexes[x]=index;
2705 }
2706 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2707 status=MagickFalse;
2708 }
2709 image_view=DestroyCacheView(image_view);
2710 return(status);
2711 }
2712 case DeactivateAlphaChannel:
2713 {
2714 image->matte=MagickFalse;
2715 break;
2716 }
2717 case ShapeAlphaChannel:
2718 case CopyAlphaChannel:
2719 {
2720 /*
2721 Special usage case for SeparateImageChannel(): copy grayscale color to
2722 the alpha channel.
2723 */
2724 status=SeparateImageChannel(image,GrayChannels);
2725 image->matte=MagickTrue; /* make sure transparency is now on! */
2726 if (alpha_type == ShapeAlphaChannel)
2727 {
2728 MagickPixelPacket
2729 background;
2730
2731 /*
2732 Reset all color channels to background color.
2733 */
2734 GetMagickPixelPacket(image,&background);
2735 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
2736 NULL,&background);
cristy308b4e62009-09-21 14:40:44 +00002737 (void) LevelColorsImage(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002738 }
2739 break;
2740 }
2741 case ExtractAlphaChannel:
2742 {
2743 status=SeparateImageChannel(image,TrueAlphaChannel);
2744 image->matte=MagickFalse;
2745 break;
2746 }
cristyf64d18b2010-04-30 12:47:03 +00002747 case ResetAlphaChannel: /* deprecated */
cristy3ed852e2009-09-05 21:47:34 +00002748 case OpaqueAlphaChannel:
2749 {
2750 status=SetImageOpacity(image,OpaqueOpacity);
2751 image->matte=MagickTrue;
2752 break;
2753 }
2754 case TransparentAlphaChannel:
2755 {
2756 status=SetImageOpacity(image,TransparentOpacity);
2757 image->matte=MagickTrue;
2758 break;
2759 }
2760 case SetAlphaChannel:
2761 {
2762 if (image->matte == MagickFalse)
2763 {
2764 status=SetImageOpacity(image,OpaqueOpacity);
2765 image->matte=MagickTrue;
2766 }
2767 break;
2768 }
2769 case UndefinedAlphaChannel:
2770 break;
2771 }
2772 return(status);
2773}
2774
2775/*
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777% %
2778% %
2779% %
2780% S e t I m a g e B a c k g r o u n d C o l o r %
2781% %
2782% %
2783% %
2784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785%
2786% SetImageBackgroundColor() initializes the image pixels to the image
2787% background color. The background color is defined by the background_color
2788% member of the image structure.
2789%
2790% The format of the SetImage method is:
2791%
2792% MagickBooleanType SetImageBackgroundColor(Image *image)
2793%
2794% A description of each parameter follows:
2795%
2796% o image: the image.
2797%
2798*/
2799MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2800{
2801 CacheView
2802 *image_view;
2803
2804 ExceptionInfo
2805 *exception;
2806
2807 IndexPacket
2808 index;
2809
cristy3ed852e2009-09-05 21:47:34 +00002810 MagickBooleanType
2811 status;
2812
2813 MagickPixelPacket
2814 background;
2815
2816 PixelPacket
2817 pixel;
2818
cristycb6d09b2010-06-19 01:59:36 +00002819 ssize_t
2820 y;
2821
cristy3ed852e2009-09-05 21:47:34 +00002822 assert(image != (Image *) NULL);
2823 if (image->debug != MagickFalse)
2824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2825 assert(image->signature == MagickSignature);
2826 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2827 return(MagickFalse);
2828 if (image->background_color.opacity != OpaqueOpacity)
2829 image->matte=MagickTrue;
2830 GetMagickPixelPacket(image,&background);
2831 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2832 NULL,&background);
2833 if (image->colorspace == CMYKColorspace)
2834 ConvertRGBToCMYK(&background);
2835 index=0;
2836 SetPixelPacket(image,&background,&pixel,&index);
2837 /*
2838 Set image background color.
2839 */
2840 status=MagickTrue;
2841 exception=(&image->exception);
2842 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002843 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002844 {
cristy3ed852e2009-09-05 21:47:34 +00002845 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002846 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002847
cristycb6d09b2010-06-19 01:59:36 +00002848 register ssize_t
2849 x;
2850
cristy3ed852e2009-09-05 21:47:34 +00002851 if (status == MagickFalse)
2852 continue;
2853 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2854 if (q == (PixelPacket *) NULL)
2855 {
2856 status=MagickFalse;
2857 continue;
2858 }
cristybb503372010-05-27 20:51:26 +00002859 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002860 *q++=pixel;
2861 if (image->colorspace == CMYKColorspace)
2862 {
cristy29058e62011-02-24 03:12:50 +00002863 register IndexPacket
2864 *restrict indexes;
2865
cristy3ed852e2009-09-05 21:47:34 +00002866 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002867 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002868 indexes[x]=index;
2869 }
2870 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2871 status=MagickFalse;
2872 }
2873 image_view=DestroyCacheView(image_view);
2874 return(status);
2875}
2876
2877/*
2878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2879% %
2880% %
2881% %
cristy0d267172011-04-25 20:13:48 +00002882% S e t I m a g e C h a n n e l s %
2883% %
2884% %
2885% %
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887%
2888% SetImageChannels() sets the number of pixels channels associated with the
2889% image.
2890%
2891% The format of the SetImageChannels method is:
2892%
2893% MagickBooleanType SetImageChannels(Image *image,const size_t channels)
2894%
2895% A description of each parameter follows:
2896%
2897% o image: the image.
2898%
2899% o channels: The number of pixel channels.
2900%
2901*/
2902MagickExport MagickBooleanType SetImageChannels(Image *image,
2903 const size_t channels)
2904{
2905 image->channels=channels;
2906 return(MagickTrue);
2907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
cristya5b77cb2010-05-07 19:34:48 +00002914% S e t I m a g e C o l o r %
2915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
2920% SetImageColor() set the entire image canvas to the specified color.
2921%
2922% The format of the SetImageColor method is:
2923%
2924% MagickBooleanType SetImageColor(Image *image,
2925% const MagickPixelPacket *color)
2926%
2927% A description of each parameter follows:
2928%
2929% o image: the image.
2930%
2931% o background: the image color.
2932%
2933*/
2934MagickExport MagickBooleanType SetImageColor(Image *image,
2935 const MagickPixelPacket *color)
2936{
2937 CacheView
2938 *image_view;
2939
2940 ExceptionInfo
2941 *exception;
2942
cristya5b77cb2010-05-07 19:34:48 +00002943 MagickBooleanType
2944 status;
2945
cristycb6d09b2010-06-19 01:59:36 +00002946 ssize_t
2947 y;
2948
cristya5b77cb2010-05-07 19:34:48 +00002949 assert(image != (Image *) NULL);
2950 if (image->debug != MagickFalse)
2951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2952 assert(image->signature == MagickSignature);
2953 assert(color != (const MagickPixelPacket *) NULL);
2954 image->colorspace=color->colorspace;
2955 image->matte=color->matte;
2956 image->fuzz=color->fuzz;
2957 image->depth=color->depth;
2958 status=MagickTrue;
2959 exception=(&image->exception);
2960 image_view=AcquireCacheView(image);
2961#if defined(MAGICKCORE_OPENMP_SUPPORT)
2962 #pragma omp parallel for schedule(dynamic,4) shared(status)
2963#endif
cristybb503372010-05-27 20:51:26 +00002964 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002965 {
2966 register IndexPacket
2967 *restrict indexes;
2968
cristya5b77cb2010-05-07 19:34:48 +00002969 register PixelPacket
2970 *restrict q;
2971
cristycb6d09b2010-06-19 01:59:36 +00002972 register ssize_t
2973 x;
2974
cristya5b77cb2010-05-07 19:34:48 +00002975 if (status == MagickFalse)
2976 continue;
2977 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2978 if (q == (PixelPacket *) NULL)
2979 {
2980 status=MagickFalse;
2981 continue;
2982 }
2983 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002984 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002985 {
2986 SetPixelPacket(image,color,q,indexes+x);
2987 q++;
2988 }
2989 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2990 status=MagickFalse;
2991 }
2992 image_view=DestroyCacheView(image_view);
2993 return(status);
2994}
2995
2996/*
2997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2998% %
2999% %
3000% %
cristy3ed852e2009-09-05 21:47:34 +00003001% S e t I m a g e S t o r a g e C l a s s %
3002% %
3003% %
3004% %
3005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006%
3007% SetImageStorageClass() sets the image class: DirectClass for true color
3008% images or PseudoClass for colormapped images.
3009%
3010% The format of the SetImageStorageClass method is:
3011%
3012% MagickBooleanType SetImageStorageClass(Image *image,
3013% const ClassType storage_class)
3014%
3015% A description of each parameter follows:
3016%
3017% o image: the image.
3018%
3019% o storage_class: The image class.
3020%
3021*/
3022MagickExport MagickBooleanType SetImageStorageClass(Image *image,
3023 const ClassType storage_class)
3024{
cristy3ed852e2009-09-05 21:47:34 +00003025 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00003026 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003027}
3028
3029/*
3030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3031% %
3032% %
3033% %
3034% S e t I m a g e C l i p M a s k %
3035% %
3036% %
3037% %
3038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039%
3040% SetImageClipMask() associates a clip path with the image. The clip path
3041% must be the same dimensions as the image. Set any pixel component of
3042% the clip path to TransparentOpacity to prevent that corresponding image
3043% pixel component from being updated when SyncAuthenticPixels() is applied.
3044%
3045% The format of the SetImageClipMask method is:
3046%
3047% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
3048%
3049% A description of each parameter follows:
3050%
3051% o image: the image.
3052%
3053% o clip_mask: the image clip path.
3054%
3055*/
3056MagickExport MagickBooleanType SetImageClipMask(Image *image,
3057 const Image *clip_mask)
3058{
3059 assert(image != (Image *) NULL);
3060 if (image->debug != MagickFalse)
3061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3062 assert(image->signature == MagickSignature);
3063 if (clip_mask != (const Image *) NULL)
3064 if ((clip_mask->columns != image->columns) ||
3065 (clip_mask->rows != image->rows))
3066 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3067 if (image->clip_mask != (Image *) NULL)
3068 image->clip_mask=DestroyImage(image->clip_mask);
3069 image->clip_mask=NewImageList();
3070 if (clip_mask == (Image *) NULL)
3071 return(MagickTrue);
3072 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3073 return(MagickFalse);
3074 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
3075 if (image->clip_mask == (Image *) NULL)
3076 return(MagickFalse);
3077 return(MagickTrue);
3078}
3079
3080/*
3081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082% %
3083% %
3084% %
3085% S e t I m a g e E x t e n t %
3086% %
3087% %
3088% %
3089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3090%
3091% SetImageExtent() sets the image size (i.e. columns & rows).
3092%
3093% The format of the SetImageExtent method is:
3094%
3095% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003096% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003097%
3098% A description of each parameter follows:
3099%
3100% o image: the image.
3101%
3102% o columns: The image width in pixels.
3103%
3104% o rows: The image height in pixels.
3105%
3106*/
3107MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003108 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003109{
cristy537e2722010-09-21 15:30:59 +00003110 if ((columns == 0) || (rows == 0))
3111 return(MagickFalse);
3112 image->columns=columns;
3113 image->rows=rows;
3114 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003115}
3116
3117/*
3118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119% %
3120% %
3121% %
3122+ S e t I m a g e I n f o %
3123% %
3124% %
3125% %
3126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3127%
3128% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3129% It is set to a type of image format based on the prefix or suffix of the
3130% filename. For example, `ps:image' returns PS indicating a Postscript image.
3131% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3132% precendence over the suffix. Use an optional index enclosed in brackets
3133% after a file name to specify a desired scene of a multi-resolution image
3134% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3135% indicates success.
3136%
3137% The format of the SetImageInfo method is:
3138%
3139% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003140% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003141%
3142% A description of each parameter follows:
3143%
cristyd965a422010-03-03 17:47:35 +00003144% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003145%
cristyd965a422010-03-03 17:47:35 +00003146% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003147%
3148% o exception: return any errors or warnings in this structure.
3149%
3150*/
3151MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003152 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003153{
3154 char
3155 extension[MaxTextExtent],
3156 filename[MaxTextExtent],
3157 magic[MaxTextExtent],
3158 *q,
3159 subimage[MaxTextExtent];
3160
3161 const MagicInfo
3162 *magic_info;
3163
3164 const MagickInfo
3165 *magick_info;
3166
3167 ExceptionInfo
3168 *sans_exception;
3169
3170 Image
3171 *image;
3172
3173 MagickBooleanType
3174 status;
3175
3176 register const char
3177 *p;
3178
3179 ssize_t
3180 count;
3181
3182 unsigned char
3183 magick[2*MaxTextExtent];
3184
3185 /*
3186 Look for 'image.format' in filename.
3187 */
3188 assert(image_info != (ImageInfo *) NULL);
3189 assert(image_info->signature == MagickSignature);
3190 if (image_info->debug != MagickFalse)
3191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3192 image_info->filename);
3193 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003194 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003195 {
cristyd965a422010-03-03 17:47:35 +00003196 GetPathComponent(image_info->filename,SubimagePath,subimage);
3197 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003198 {
cristyd965a422010-03-03 17:47:35 +00003199 /*
3200 Look for scene specification (e.g. img0001.pcd[4]).
3201 */
3202 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3203 {
3204 if (IsGeometry(subimage) != MagickFalse)
3205 (void) CloneString(&image_info->extract,subimage);
3206 }
3207 else
3208 {
cristybb503372010-05-27 20:51:26 +00003209 size_t
cristyd965a422010-03-03 17:47:35 +00003210 first,
3211 last;
cristy3ed852e2009-09-05 21:47:34 +00003212
cristyd965a422010-03-03 17:47:35 +00003213 (void) CloneString(&image_info->scenes,subimage);
3214 image_info->scene=StringToUnsignedLong(image_info->scenes);
3215 image_info->number_scenes=image_info->scene;
3216 p=image_info->scenes;
3217 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3218 {
3219 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3220 (*p == ','))
3221 p++;
cristybb503372010-05-27 20:51:26 +00003222 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003223 last=first;
3224 while (isspace((int) ((unsigned char) *q)) != 0)
3225 q++;
3226 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003227 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003228 if (first > last)
3229 Swap(first,last);
3230 if (first < image_info->scene)
3231 image_info->scene=first;
3232 if (last > image_info->number_scenes)
3233 image_info->number_scenes=last;
3234 p=q;
3235 }
3236 image_info->number_scenes-=image_info->scene-1;
3237 image_info->subimage=image_info->scene;
3238 image_info->subrange=image_info->number_scenes;
3239 }
cristy3ed852e2009-09-05 21:47:34 +00003240 }
3241 }
3242 *extension='\0';
3243 GetPathComponent(image_info->filename,ExtensionPath,extension);
3244#if defined(MAGICKCORE_ZLIB_DELEGATE)
3245 if (*extension != '\0')
3246 if ((LocaleCompare(extension,"gz") == 0) ||
3247 (LocaleCompare(extension,"Z") == 0) ||
3248 (LocaleCompare(extension,"wmz") == 0))
3249 {
3250 char
3251 path[MaxTextExtent];
3252
3253 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3254 path[strlen(path)-strlen(extension)-1]='\0';
3255 GetPathComponent(path,ExtensionPath,extension);
3256 }
3257#endif
3258#if defined(MAGICKCORE_BZLIB_DELEGATE)
3259 if (*extension != '\0')
3260 if (LocaleCompare(extension,"bz2") == 0)
3261 {
3262 char
3263 path[MaxTextExtent];
3264
3265 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3266 path[strlen(path)-strlen(extension)-1]='\0';
3267 GetPathComponent(path,ExtensionPath,extension);
3268 }
3269#endif
3270 image_info->affirm=MagickFalse;
3271 sans_exception=AcquireExceptionInfo();
3272 if (*extension != '\0')
3273 {
3274 MagickFormatType
3275 format_type;
3276
cristybb503372010-05-27 20:51:26 +00003277 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003278 i;
3279
3280 static const char
3281 *format_type_formats[] =
3282 {
3283 "AUTOTRACE",
3284 "BROWSE",
3285 "DCRAW",
3286 "EDIT",
3287 "EPHEMERAL",
3288 "LAUNCH",
3289 "MPEG:DECODE",
3290 "MPEG:ENCODE",
3291 "PRINT",
3292 "PS:ALPHA",
3293 "PS:CMYK",
3294 "PS:COLOR",
3295 "PS:GRAY",
3296 "PS:MONO",
3297 "SCAN",
3298 "SHOW",
3299 "WIN",
3300 (char *) NULL
3301 };
3302
3303 /*
3304 User specified image format.
3305 */
3306 (void) CopyMagickString(magic,extension,MaxTextExtent);
3307 LocaleUpper(magic);
3308 /*
3309 Look for explicit image formats.
3310 */
3311 format_type=UndefinedFormatType;
3312 i=0;
cristydd9a2532010-02-20 19:26:46 +00003313 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003314 (format_type_formats[i] != (char *) NULL))
3315 {
3316 if ((*magic == *format_type_formats[i]) &&
3317 (LocaleCompare(magic,format_type_formats[i]) == 0))
3318 format_type=ExplicitFormatType;
3319 i++;
3320 }
3321 magick_info=GetMagickInfo(magic,sans_exception);
3322 if ((magick_info != (const MagickInfo *) NULL) &&
3323 (magick_info->format_type != UndefinedFormatType))
3324 format_type=magick_info->format_type;
3325 if (format_type == UndefinedFormatType)
3326 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3327 else
3328 if (format_type == ExplicitFormatType)
3329 {
3330 image_info->affirm=MagickTrue;
3331 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3332 }
3333 if (LocaleCompare(magic,"RGB") == 0)
3334 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3335 }
3336 /*
3337 Look for explicit 'format:image' in filename.
3338 */
3339 *magic='\0';
3340 GetPathComponent(image_info->filename,MagickPath,magic);
3341 if (*magic == '\0')
3342 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3343 else
3344 {
3345 /*
3346 User specified image format.
3347 */
3348 LocaleUpper(magic);
3349 if (IsMagickConflict(magic) == MagickFalse)
3350 {
3351 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3352 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3353 image_info->affirm=MagickTrue;
3354 else
3355 image_info->temporary=MagickTrue;
3356 }
3357 }
3358 magick_info=GetMagickInfo(magic,sans_exception);
3359 sans_exception=DestroyExceptionInfo(sans_exception);
3360 if ((magick_info == (const MagickInfo *) NULL) ||
3361 (GetMagickEndianSupport(magick_info) == MagickFalse))
3362 image_info->endian=UndefinedEndian;
3363 GetPathComponent(image_info->filename,CanonicalPath,filename);
3364 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003365 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003366 {
3367 /*
cristyd965a422010-03-03 17:47:35 +00003368 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003369 */
cristyd965a422010-03-03 17:47:35 +00003370 (void) InterpretImageFilename(image_info,(Image *) NULL,
3371 image_info->filename,(int) image_info->scene,filename);
3372 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3373 (strchr(filename,'%') == (char *) NULL))
3374 image_info->adjoin=MagickFalse;
3375 }
3376 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3377 {
3378 /*
3379 Some image formats do not support multiple frames per file.
3380 */
cristy3ed852e2009-09-05 21:47:34 +00003381 magick_info=GetMagickInfo(magic,exception);
3382 if (magick_info != (const MagickInfo *) NULL)
3383 if (GetMagickAdjoin(magick_info) == MagickFalse)
3384 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003385 }
3386 if (image_info->affirm != MagickFalse)
3387 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003388 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003389 {
3390 /*
cristyd965a422010-03-03 17:47:35 +00003391 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003392 */
cristyd965a422010-03-03 17:47:35 +00003393 image=AcquireImage(image_info);
3394 (void) CopyMagickString(image->filename,image_info->filename,
3395 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003396 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3397 if (status == MagickFalse)
3398 {
3399 image=DestroyImage(image);
3400 return(MagickFalse);
3401 }
cristyd965a422010-03-03 17:47:35 +00003402 if ((IsBlobSeekable(image) == MagickFalse) ||
3403 (IsBlobExempt(image) != MagickFalse))
3404 {
3405 /*
3406 Copy standard input or pipe to temporary file.
3407 */
3408 *filename='\0';
3409 status=ImageToFile(image,filename,exception);
3410 (void) CloseBlob(image);
3411 if (status == MagickFalse)
3412 {
3413 image=DestroyImage(image);
3414 return(MagickFalse);
3415 }
3416 SetImageInfoFile(image_info,(FILE *) NULL);
3417 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3418 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3419 if (status == MagickFalse)
3420 {
3421 image=DestroyImage(image);
3422 return(MagickFalse);
3423 }
3424 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3425 image_info->temporary=MagickTrue;
3426 }
3427 (void) ResetMagickMemory(magick,0,sizeof(magick));
3428 count=ReadBlob(image,2*MaxTextExtent,magick);
3429 (void) CloseBlob(image);
3430 image=DestroyImage(image);
3431 /*
3432 Check magic.xml configuration file.
3433 */
3434 sans_exception=AcquireExceptionInfo();
3435 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3436 if ((magic_info != (const MagicInfo *) NULL) &&
3437 (GetMagicName(magic_info) != (char *) NULL))
3438 {
3439 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3440 MaxTextExtent);
3441 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3442 if ((magick_info == (const MagickInfo *) NULL) ||
3443 (GetMagickEndianSupport(magick_info) == MagickFalse))
3444 image_info->endian=UndefinedEndian;
3445 sans_exception=DestroyExceptionInfo(sans_exception);
3446 return(MagickTrue);
3447 }
cristy3ed852e2009-09-05 21:47:34 +00003448 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3449 if ((magick_info == (const MagickInfo *) NULL) ||
3450 (GetMagickEndianSupport(magick_info) == MagickFalse))
3451 image_info->endian=UndefinedEndian;
3452 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003453 }
cristy3ed852e2009-09-05 21:47:34 +00003454 return(MagickTrue);
3455}
3456
3457/*
3458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3459% %
3460% %
3461% %
3462% S e t I m a g e I n f o B l o b %
3463% %
3464% %
3465% %
3466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3467%
3468% SetImageInfoBlob() sets the image info blob member.
3469%
3470% The format of the SetImageInfoBlob method is:
3471%
3472% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3473% const size_t length)
3474%
3475% A description of each parameter follows:
3476%
3477% o image_info: the image info.
3478%
3479% o blob: the blob.
3480%
3481% o length: the blob length.
3482%
3483*/
3484MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3485 const size_t length)
3486{
3487 assert(image_info != (ImageInfo *) NULL);
3488 assert(image_info->signature == MagickSignature);
3489 if (image_info->debug != MagickFalse)
3490 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3491 image_info->filename);
3492 image_info->blob=(void *) blob;
3493 image_info->length=length;
3494}
3495
3496/*
3497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498% %
3499% %
3500% %
3501% S e t I m a g e I n f o F i l e %
3502% %
3503% %
3504% %
3505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3506%
3507% SetImageInfoFile() sets the image info file member.
3508%
3509% The format of the SetImageInfoFile method is:
3510%
3511% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3512%
3513% A description of each parameter follows:
3514%
3515% o image_info: the image info.
3516%
3517% o file: the file.
3518%
3519*/
3520MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3521{
3522 assert(image_info != (ImageInfo *) NULL);
3523 assert(image_info->signature == MagickSignature);
3524 if (image_info->debug != MagickFalse)
3525 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3526 image_info->filename);
3527 image_info->file=file;
3528}
3529
3530/*
3531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3532% %
3533% %
3534% %
3535% S e t I m a g e M a s k %
3536% %
3537% %
3538% %
3539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3540%
3541% SetImageMask() associates a mask with the image. The mask must be the same
3542% dimensions as the image.
3543%
3544% The format of the SetImageMask method is:
3545%
3546% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3547%
3548% A description of each parameter follows:
3549%
3550% o image: the image.
3551%
3552% o mask: the image mask.
3553%
3554*/
3555MagickExport MagickBooleanType SetImageMask(Image *image,
3556 const Image *mask)
3557{
3558 assert(image != (Image *) NULL);
3559 if (image->debug != MagickFalse)
3560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3561 assert(image->signature == MagickSignature);
3562 if (mask != (const Image *) NULL)
3563 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3564 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3565 if (image->mask != (Image *) NULL)
3566 image->mask=DestroyImage(image->mask);
3567 image->mask=NewImageList();
3568 if (mask == (Image *) NULL)
3569 return(MagickTrue);
3570 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3571 return(MagickFalse);
3572 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3573 if (image->mask == (Image *) NULL)
3574 return(MagickFalse);
3575 return(MagickTrue);
3576}
3577
3578/*
3579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580% %
3581% %
3582% %
3583% S e t I m a g e O p a c i t y %
3584% %
3585% %
3586% %
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588%
3589% SetImageOpacity() sets the opacity levels of the image.
3590%
3591% The format of the SetImageOpacity method is:
3592%
3593% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3594%
3595% A description of each parameter follows:
3596%
3597% o image: the image.
3598%
3599% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3600% fully transparent.
3601%
3602*/
3603MagickExport MagickBooleanType SetImageOpacity(Image *image,
3604 const Quantum opacity)
3605{
3606 CacheView
3607 *image_view;
3608
3609 ExceptionInfo
3610 *exception;
3611
cristy3ed852e2009-09-05 21:47:34 +00003612 MagickBooleanType
3613 status;
3614
cristycb6d09b2010-06-19 01:59:36 +00003615 ssize_t
3616 y;
3617
cristy3ed852e2009-09-05 21:47:34 +00003618 assert(image != (Image *) NULL);
3619 if (image->debug != MagickFalse)
3620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3621 assert(image->signature == MagickSignature);
3622 image->matte=opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3623 status=MagickTrue;
3624 exception=(&image->exception);
3625 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003626#if defined(MAGICKCORE_OPENMP_SUPPORT)
3627 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003628#endif
cristybb503372010-05-27 20:51:26 +00003629 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003630 {
cristy3ed852e2009-09-05 21:47:34 +00003631 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003632 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003633
cristycb6d09b2010-06-19 01:59:36 +00003634 register ssize_t
3635 x;
3636
cristy3ed852e2009-09-05 21:47:34 +00003637 if (status == MagickFalse)
3638 continue;
3639 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3640 if (q == (PixelPacket *) NULL)
3641 {
3642 status=MagickFalse;
3643 continue;
3644 }
cristybb503372010-05-27 20:51:26 +00003645 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003646 {
cristy46f08202010-01-10 04:04:21 +00003647 SetOpacityPixelComponent(q,opacity);
cristy3ed852e2009-09-05 21:47:34 +00003648 q++;
3649 }
3650 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3651 status=MagickFalse;
3652 }
3653 image_view=DestroyCacheView(image_view);
3654 return(status);
3655}
3656
3657/*
3658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3659% %
3660% %
3661% %
3662% S e t I m a g e T y p e %
3663% %
3664% %
3665% %
3666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3667%
3668% SetImageType() sets the type of image. Choose from these types:
3669%
3670% Bilevel Grayscale GrayscaleMatte
3671% Palette PaletteMatte TrueColor
3672% TrueColorMatte ColorSeparation ColorSeparationMatte
3673% OptimizeType
3674%
3675% The format of the SetImageType method is:
3676%
3677% MagickBooleanType SetImageType(Image *image,const ImageType type)
3678%
3679% A description of each parameter follows:
3680%
3681% o image: the image.
3682%
3683% o type: Image type.
3684%
3685*/
3686MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3687{
3688 const char
3689 *artifact;
3690
3691 ImageInfo
3692 *image_info;
3693
3694 MagickBooleanType
3695 status;
3696
3697 QuantizeInfo
3698 *quantize_info;
3699
3700 assert(image != (Image *) NULL);
3701 if (image->debug != MagickFalse)
3702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3703 assert(image->signature == MagickSignature);
3704 status=MagickTrue;
3705 image_info=AcquireImageInfo();
3706 image_info->dither=image->dither;
3707 artifact=GetImageArtifact(image,"dither");
3708 if (artifact != (const char *) NULL)
3709 (void) SetImageOption(image_info,"dither",artifact);
3710 switch (type)
3711 {
3712 case BilevelType:
3713 {
3714 if (IsGrayImage(image,&image->exception) == MagickFalse)
3715 status=TransformImageColorspace(image,GRAYColorspace);
3716 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
3717 {
3718 quantize_info=AcquireQuantizeInfo(image_info);
3719 quantize_info->number_colors=2;
3720 quantize_info->colorspace=GRAYColorspace;
3721 status=QuantizeImage(quantize_info,image);
3722 quantize_info=DestroyQuantizeInfo(quantize_info);
3723 }
3724 image->matte=MagickFalse;
3725 break;
3726 }
3727 case GrayscaleType:
3728 {
3729 if (IsGrayImage(image,&image->exception) == MagickFalse)
3730 status=TransformImageColorspace(image,GRAYColorspace);
3731 image->matte=MagickFalse;
3732 break;
3733 }
3734 case GrayscaleMatteType:
3735 {
3736 if (IsGrayImage(image,&image->exception) == MagickFalse)
3737 status=TransformImageColorspace(image,GRAYColorspace);
3738 if (image->matte == MagickFalse)
3739 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3740 break;
3741 }
3742 case PaletteType:
3743 {
3744 if (image->colorspace != RGBColorspace)
3745 status=TransformImageColorspace(image,RGBColorspace);
3746 if ((image->storage_class == DirectClass) || (image->colors > 256))
3747 {
3748 quantize_info=AcquireQuantizeInfo(image_info);
3749 quantize_info->number_colors=256;
3750 status=QuantizeImage(quantize_info,image);
3751 quantize_info=DestroyQuantizeInfo(quantize_info);
3752 }
3753 image->matte=MagickFalse;
3754 break;
3755 }
3756 case PaletteBilevelMatteType:
3757 {
3758 if (image->colorspace != RGBColorspace)
3759 status=TransformImageColorspace(image,RGBColorspace);
3760 if (image->matte == MagickFalse)
3761 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3762 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3763 quantize_info=AcquireQuantizeInfo(image_info);
3764 status=QuantizeImage(quantize_info,image);
3765 quantize_info=DestroyQuantizeInfo(quantize_info);
3766 break;
3767 }
3768 case PaletteMatteType:
3769 {
3770 if (image->colorspace != RGBColorspace)
3771 status=TransformImageColorspace(image,RGBColorspace);
3772 if (image->matte == MagickFalse)
3773 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3774 quantize_info=AcquireQuantizeInfo(image_info);
3775 quantize_info->colorspace=TransparentColorspace;
3776 status=QuantizeImage(quantize_info,image);
3777 quantize_info=DestroyQuantizeInfo(quantize_info);
3778 break;
3779 }
3780 case TrueColorType:
3781 {
3782 if (image->colorspace != RGBColorspace)
3783 status=TransformImageColorspace(image,RGBColorspace);
3784 if (image->storage_class != DirectClass)
3785 status=SetImageStorageClass(image,DirectClass);
3786 image->matte=MagickFalse;
3787 break;
3788 }
3789 case TrueColorMatteType:
3790 {
3791 if (image->colorspace != RGBColorspace)
3792 status=TransformImageColorspace(image,RGBColorspace);
3793 if (image->storage_class != DirectClass)
3794 status=SetImageStorageClass(image,DirectClass);
3795 if (image->matte == MagickFalse)
3796 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3797 break;
3798 }
3799 case ColorSeparationType:
3800 {
3801 if (image->colorspace != CMYKColorspace)
3802 {
3803 if (image->colorspace != RGBColorspace)
3804 status=TransformImageColorspace(image,RGBColorspace);
3805 status=TransformImageColorspace(image,CMYKColorspace);
3806 }
3807 if (image->storage_class != DirectClass)
3808 status=SetImageStorageClass(image,DirectClass);
3809 image->matte=MagickFalse;
3810 break;
3811 }
3812 case ColorSeparationMatteType:
3813 {
3814 if (image->colorspace != CMYKColorspace)
3815 {
3816 if (image->colorspace != RGBColorspace)
3817 status=TransformImageColorspace(image,RGBColorspace);
3818 status=TransformImageColorspace(image,CMYKColorspace);
3819 }
3820 if (image->storage_class != DirectClass)
3821 status=SetImageStorageClass(image,DirectClass);
3822 if (image->matte == MagickFalse)
3823 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3824 break;
3825 }
3826 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003827 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003828 break;
3829 }
3830 image->type=type;
3831 image_info=DestroyImageInfo(image_info);
3832 return(status);
3833}
3834
3835/*
3836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837% %
3838% %
3839% %
3840% 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 %
3841% %
3842% %
3843% %
3844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845%
3846% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3847% image and returns the previous setting. A virtual pixel is any pixel access
3848% that is outside the boundaries of the image cache.
3849%
3850% The format of the SetImageVirtualPixelMethod() method is:
3851%
3852% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3853% const VirtualPixelMethod virtual_pixel_method)
3854%
3855% A description of each parameter follows:
3856%
3857% o image: the image.
3858%
3859% o virtual_pixel_method: choose the type of virtual pixel.
3860%
3861*/
3862MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3863 const VirtualPixelMethod virtual_pixel_method)
3864{
3865 assert(image != (const Image *) NULL);
3866 assert(image->signature == MagickSignature);
3867 if (image->debug != MagickFalse)
3868 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3869 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3870}
3871
3872/*
3873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3874% %
3875% %
3876% %
cristy4285d782011-02-09 20:12:28 +00003877% S m u s h I m a g e s %
3878% %
3879% %
3880% %
3881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3882%
3883% SmushImages() takes all images from the current image pointer to the end
3884% of the image list and smushes them to each other top-to-bottom if the
3885% stack parameter is true, otherwise left-to-right.
3886%
3887% The current gravity setting now effects how the image is justified in the
3888% final image.
3889%
3890% The format of the SmushImages method is:
3891%
cristy4ca38e22011-02-10 02:57:49 +00003892% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003893% ExceptionInfo *exception)
3894%
3895% A description of each parameter follows:
3896%
cristy4ca38e22011-02-10 02:57:49 +00003897% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003898%
3899% o stack: A value other than 0 stacks the images top-to-bottom.
3900%
3901% o offset: minimum distance in pixels between images.
3902%
3903% o exception: return any errors or warnings in this structure.
3904%
3905*/
cristy4ca38e22011-02-10 02:57:49 +00003906
cristy7c6dc152011-02-11 14:10:55 +00003907static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003908 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003909{
cristy4d727152011-02-10 19:57:21 +00003910 CacheView
3911 *left_view,
3912 *right_view;
3913
3914 const Image
3915 *left_image,
3916 *right_image;
3917
cristy4d727152011-02-10 19:57:21 +00003918 RectangleInfo
3919 left_geometry,
3920 right_geometry;
3921
cristydab7e912011-02-11 18:19:24 +00003922 register const PixelPacket
3923 *p;
3924
cristy4d727152011-02-10 19:57:21 +00003925 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003926 i,
cristy4d727152011-02-10 19:57:21 +00003927 y;
3928
cristy7c6dc152011-02-11 14:10:55 +00003929 size_t
3930 gap;
3931
cristy4d727152011-02-10 19:57:21 +00003932 ssize_t
cristy4d727152011-02-10 19:57:21 +00003933 x;
3934
3935 if (images->previous == (Image *) NULL)
3936 return(0);
3937 right_image=images;
3938 SetGeometry(smush_image,&right_geometry);
3939 GravityAdjustGeometry(right_image->columns,right_image->rows,
3940 right_image->gravity,&right_geometry);
3941 left_image=images->previous;
3942 SetGeometry(smush_image,&left_geometry);
3943 GravityAdjustGeometry(left_image->columns,left_image->rows,
3944 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003945 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003946 left_view=AcquireCacheView(left_image);
3947 right_view=AcquireCacheView(right_image);
3948 for (y=0; y < (ssize_t) smush_image->rows; y++)
3949 {
3950 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3951 {
cristydab7e912011-02-11 18:19:24 +00003952 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3953 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003954 (GetOpacityPixelComponent(p) != TransparentOpacity) ||
cristy7c6dc152011-02-11 14:10:55 +00003955 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003956 break;
3957 }
cristy4ef6f062011-02-10 20:30:22 +00003958 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003959 for (x=0; x < (ssize_t) right_image->columns; x++)
3960 {
cristydab7e912011-02-11 18:19:24 +00003961 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003962 exception);
cristydab7e912011-02-11 18:19:24 +00003963 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003964 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003965 break;
3966 }
cristy7c6dc152011-02-11 14:10:55 +00003967 if ((x+i) < (ssize_t) gap)
3968 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003969 }
3970 right_view=DestroyCacheView(right_view);
3971 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003972 if (y < (ssize_t) smush_image->rows)
3973 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003974 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003975}
3976
cristy7c6dc152011-02-11 14:10:55 +00003977static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003978 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003979{
cristy4d727152011-02-10 19:57:21 +00003980 CacheView
3981 *bottom_view,
3982 *top_view;
3983
3984 const Image
3985 *bottom_image,
3986 *top_image;
3987
cristy4d727152011-02-10 19:57:21 +00003988 RectangleInfo
3989 bottom_geometry,
3990 top_geometry;
3991
cristydab7e912011-02-11 18:19:24 +00003992 register const PixelPacket
3993 *p;
3994
cristy4d727152011-02-10 19:57:21 +00003995 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003996 i,
cristy4d727152011-02-10 19:57:21 +00003997 x;
3998
cristy7c6dc152011-02-11 14:10:55 +00003999 size_t
4000 gap;
4001
cristy4d727152011-02-10 19:57:21 +00004002 ssize_t
cristy4d727152011-02-10 19:57:21 +00004003 y;
4004
4005 if (images->previous == (Image *) NULL)
4006 return(0);
4007 bottom_image=images;
4008 SetGeometry(smush_image,&bottom_geometry);
4009 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
4010 bottom_image->gravity,&bottom_geometry);
4011 top_image=images->previous;
4012 SetGeometry(smush_image,&top_geometry);
4013 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
4014 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00004015 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00004016 top_view=AcquireCacheView(top_image);
4017 bottom_view=AcquireCacheView(bottom_image);
4018 for (x=0; x < (ssize_t) smush_image->columns; x++)
4019 {
4020 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
4021 {
cristydab7e912011-02-11 18:19:24 +00004022 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
4023 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004024 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00004025 break;
4026 }
cristy4ef6f062011-02-10 20:30:22 +00004027 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00004028 for (y=0; y < (ssize_t) bottom_image->rows; y++)
4029 {
cristydab7e912011-02-11 18:19:24 +00004030 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
4031 exception);
4032 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004033 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00004034 break;
4035 }
cristy7c6dc152011-02-11 14:10:55 +00004036 if ((y+i) < (ssize_t) gap)
4037 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00004038 }
4039 bottom_view=DestroyCacheView(bottom_view);
4040 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00004041 if (x < (ssize_t) smush_image->columns)
4042 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00004043 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00004044}
4045
4046MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00004047 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
4048{
4049#define SmushImageTag "Smush/Image"
4050
4051 CacheView
cristybb5dced2011-02-10 02:17:16 +00004052 *smush_view;
cristy4285d782011-02-09 20:12:28 +00004053
cristy4ca38e22011-02-10 02:57:49 +00004054 const Image
4055 *image;
4056
cristy4285d782011-02-09 20:12:28 +00004057 Image
4058 *smush_image;
4059
4060 MagickBooleanType
4061 matte,
4062 proceed,
4063 status;
4064
4065 MagickOffsetType
4066 n;
4067
4068 RectangleInfo
4069 geometry;
4070
4071 register const Image
4072 *next;
4073
4074 size_t
4075 height,
4076 number_images,
4077 width;
4078
4079 ssize_t
4080 x_offset,
cristy4285d782011-02-09 20:12:28 +00004081 y_offset;
4082
4083 /*
cristy7c6dc152011-02-11 14:10:55 +00004084 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00004085 */
cristy4ca38e22011-02-10 02:57:49 +00004086 assert(images != (Image *) NULL);
4087 assert(images->signature == MagickSignature);
4088 if (images->debug != MagickFalse)
4089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00004090 assert(exception != (ExceptionInfo *) NULL);
4091 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00004092 image=images;
cristy4285d782011-02-09 20:12:28 +00004093 matte=image->matte;
4094 number_images=1;
4095 width=image->columns;
4096 height=image->rows;
4097 next=GetNextImageInList(image);
4098 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4099 {
4100 if (next->matte != MagickFalse)
4101 matte=MagickTrue;
4102 number_images++;
4103 if (stack != MagickFalse)
4104 {
4105 if (next->columns > width)
4106 width=next->columns;
4107 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004108 if (next->previous != (Image *) NULL)
4109 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004110 continue;
4111 }
4112 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004113 if (next->previous != (Image *) NULL)
4114 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004115 if (next->rows > height)
4116 height=next->rows;
4117 }
4118 /*
cristy7c6dc152011-02-11 14:10:55 +00004119 Smush images.
cristy4285d782011-02-09 20:12:28 +00004120 */
4121 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4122 if (smush_image == (Image *) NULL)
4123 return((Image *) NULL);
4124 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4125 {
4126 InheritException(exception,&smush_image->exception);
4127 smush_image=DestroyImage(smush_image);
4128 return((Image *) NULL);
4129 }
4130 smush_image->matte=matte;
4131 (void) SetImageBackgroundColor(smush_image);
4132 status=MagickTrue;
4133 x_offset=0;
4134 y_offset=0;
4135 smush_view=AcquireCacheView(smush_image);
4136 for (n=0; n < (MagickOffsetType) number_images; n++)
4137 {
4138 SetGeometry(smush_image,&geometry);
4139 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4140 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004141 {
4142 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004143 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004144 }
cristy4285d782011-02-09 20:12:28 +00004145 else
cristy4ca38e22011-02-10 02:57:49 +00004146 {
cristy7c6dc152011-02-11 14:10:55 +00004147 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004148 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004149 }
cristybb5dced2011-02-10 02:17:16 +00004150 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004151 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4152 if (proceed == MagickFalse)
4153 break;
4154 if (stack == MagickFalse)
4155 {
4156 x_offset+=(ssize_t) image->columns;
4157 y_offset=0;
4158 }
4159 else
4160 {
4161 x_offset=0;
4162 y_offset+=(ssize_t) image->rows;
4163 }
4164 image=GetNextImageInList(image);
4165 }
cristy4ef6f062011-02-10 20:30:22 +00004166 if (stack == MagickFalse)
4167 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004168 else
cristy4ef6f062011-02-10 20:30:22 +00004169 smush_image->rows=(size_t) y_offset;
4170 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004171 if (status == MagickFalse)
4172 smush_image=DestroyImage(smush_image);
4173 return(smush_image);
4174}
4175
4176/*
4177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4178% %
4179% %
4180% %
cristy3ed852e2009-09-05 21:47:34 +00004181% S t r i p I m a g e %
4182% %
4183% %
4184% %
4185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4186%
cristy376bda92009-12-22 21:15:23 +00004187% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004188%
4189% The format of the StripImage method is:
4190%
4191% MagickBooleanType StripImage(Image *image)
4192%
4193% A description of each parameter follows:
4194%
4195% o image: the image.
4196%
4197*/
4198MagickExport MagickBooleanType StripImage(Image *image)
4199{
4200 assert(image != (Image *) NULL);
4201 if (image->debug != MagickFalse)
4202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4203 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004204 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004205 (void) DeleteImageProperty(image,"date:create");
4206 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004207 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004208 return(MagickTrue);
4209}
4210
4211/*
4212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4213% %
4214% %
4215% %
4216+ S y n c I m a g e %
4217% %
4218% %
4219% %
4220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4221%
4222% SyncImage() initializes the red, green, and blue intensities of each pixel
4223% as defined by the colormap index.
4224%
4225% The format of the SyncImage method is:
4226%
4227% MagickBooleanType SyncImage(Image *image)
4228%
4229% A description of each parameter follows:
4230%
4231% o image: the image.
4232%
4233*/
4234
4235static inline IndexPacket PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004236 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004237{
4238 if (index < image->colors)
4239 return((IndexPacket) index);
4240 *range_exception=MagickTrue;
4241 return((IndexPacket) 0);
4242}
4243
4244MagickExport MagickBooleanType SyncImage(Image *image)
4245{
4246 CacheView
4247 *image_view;
4248
4249 ExceptionInfo
4250 *exception;
4251
cristy3ed852e2009-09-05 21:47:34 +00004252 MagickBooleanType
4253 range_exception,
4254 status;
4255
cristycb6d09b2010-06-19 01:59:36 +00004256 ssize_t
4257 y;
4258
cristy3ed852e2009-09-05 21:47:34 +00004259 assert(image != (Image *) NULL);
4260 if (image->debug != MagickFalse)
4261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4262 assert(image->signature == MagickSignature);
4263 if (image->storage_class == DirectClass)
4264 return(MagickFalse);
4265 range_exception=MagickFalse;
4266 status=MagickTrue;
4267 exception=(&image->exception);
4268 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004269#if defined(MAGICKCORE_OPENMP_SUPPORT)
4270 #pragma omp parallel for schedule(dynamic,4) shared(status)
4271#endif
cristybb503372010-05-27 20:51:26 +00004272 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004273 {
4274 IndexPacket
4275 index;
4276
4277 PixelPacket
4278 pixel;
4279
4280 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004281 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00004282
cristy3ed852e2009-09-05 21:47:34 +00004283 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004284 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004285
cristycb6d09b2010-06-19 01:59:36 +00004286 register ssize_t
4287 x;
4288
cristy48974b92009-12-19 02:36:06 +00004289 if (status == MagickFalse)
4290 continue;
cristy3ed852e2009-09-05 21:47:34 +00004291 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4292 if (q == (PixelPacket *) NULL)
4293 {
4294 status=MagickFalse;
4295 continue;
4296 }
4297 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00004298 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004299 {
cristyc5071682011-04-22 02:06:27 +00004300 index=PushColormapIndex(image,(size_t) indexes[x],&range_exception);
cristybb503372010-05-27 20:51:26 +00004301 pixel=image->colormap[(ssize_t) index];
cristya2d08742011-04-22 19:59:52 +00004302 SetRedPixelComponent(q,pixel.red);
4303 SetGreenPixelComponent(q,pixel.green);
4304 SetBluePixelComponent(q,pixel.blue);
cristyd0272592010-04-21 01:01:49 +00004305 if (image->matte != MagickFalse)
cristya2d08742011-04-22 19:59:52 +00004306 SetOpacityPixelComponent(q,pixel.opacity);
cristy3ed852e2009-09-05 21:47:34 +00004307 q++;
4308 }
4309 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4310 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004311 }
4312 image_view=DestroyCacheView(image_view);
4313 if (range_exception != MagickFalse)
4314 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4315 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4316 return(status);
4317}
cristy1626d332009-11-10 16:58:17 +00004318
4319/*
4320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4321% %
4322% %
4323% %
4324% S y n c I m a g e S e t t i n g s %
4325% %
4326% %
4327% %
4328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4329%
4330% SyncImageSettings() sync the image info options to the image.
4331%
4332% The format of the SyncImageSettings method is:
4333%
4334% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4335% Image *image)
4336% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4337% Image *image)
4338%
4339% A description of each parameter follows:
4340%
4341% o image_info: the image info.
4342%
4343% o image: the image.
4344%
4345*/
4346
4347MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4348 Image *images)
4349{
4350 Image
4351 *image;
4352
4353 assert(image_info != (const ImageInfo *) NULL);
4354 assert(image_info->signature == MagickSignature);
4355 assert(images != (Image *) NULL);
4356 assert(images->signature == MagickSignature);
4357 if (images->debug != MagickFalse)
4358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4359 image=images;
4360 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4361 (void) SyncImageSettings(image_info,image);
4362 (void) DeleteImageOption(image_info,"page");
4363 return(MagickTrue);
4364}
4365
4366MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4367 Image *image)
4368{
4369 char
4370 property[MaxTextExtent];
4371
4372 const char
cristy9a703812010-07-26 14:50:29 +00004373 *option,
4374 *value;
cristy1626d332009-11-10 16:58:17 +00004375
4376 GeometryInfo
4377 geometry_info;
4378
4379 MagickStatusType
4380 flags;
4381
cristy19eb6412010-04-23 14:42:29 +00004382 ResolutionType
4383 units;
4384
cristy1626d332009-11-10 16:58:17 +00004385 /*
4386 Sync image options.
4387 */
4388 assert(image_info != (const ImageInfo *) NULL);
4389 assert(image_info->signature == MagickSignature);
4390 assert(image != (Image *) NULL);
4391 assert(image->signature == MagickSignature);
4392 if (image->debug != MagickFalse)
4393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4394 option=GetImageOption(image_info,"background");
4395 if (option != (const char *) NULL)
4396 (void) QueryColorDatabase(option,&image->background_color,
4397 &image->exception);
4398 option=GetImageOption(image_info,"bias");
4399 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004400 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004401 option=GetImageOption(image_info,"black-point-compensation");
4402 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004403 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004404 MagickBooleanOptions,MagickFalse,option);
4405 option=GetImageOption(image_info,"blue-primary");
4406 if (option != (const char *) NULL)
4407 {
4408 flags=ParseGeometry(option,&geometry_info);
4409 image->chromaticity.blue_primary.x=geometry_info.rho;
4410 image->chromaticity.blue_primary.y=geometry_info.sigma;
4411 if ((flags & SigmaValue) == 0)
4412 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4413 }
4414 option=GetImageOption(image_info,"bordercolor");
4415 if (option != (const char *) NULL)
4416 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4417 option=GetImageOption(image_info,"colors");
4418 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004419 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004420 option=GetImageOption(image_info,"compose");
4421 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004422 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004423 MagickFalse,option);
4424 option=GetImageOption(image_info,"compress");
4425 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004426 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004427 MagickCompressOptions,MagickFalse,option);
4428 option=GetImageOption(image_info,"debug");
4429 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004430 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004431 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004432 option=GetImageOption(image_info,"density");
4433 if (option != (const char *) NULL)
4434 {
4435 GeometryInfo
4436 geometry_info;
4437
4438 /*
4439 Set image density.
4440 */
4441 flags=ParseGeometry(option,&geometry_info);
4442 image->x_resolution=geometry_info.rho;
4443 image->y_resolution=geometry_info.sigma;
4444 if ((flags & SigmaValue) == 0)
4445 image->y_resolution=image->x_resolution;
4446 }
cristy1626d332009-11-10 16:58:17 +00004447 option=GetImageOption(image_info,"depth");
4448 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004449 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004450 option=GetImageOption(image_info,"endian");
4451 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004452 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004453 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004454 option=GetImageOption(image_info,"filter");
4455 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004456 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004457 MagickFalse,option);
4458 option=GetImageOption(image_info,"fuzz");
4459 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004460 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004461 option=GetImageOption(image_info,"gravity");
4462 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004463 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004464 MagickFalse,option);
4465 option=GetImageOption(image_info,"green-primary");
4466 if (option != (const char *) NULL)
4467 {
4468 flags=ParseGeometry(option,&geometry_info);
4469 image->chromaticity.green_primary.x=geometry_info.rho;
4470 image->chromaticity.green_primary.y=geometry_info.sigma;
4471 if ((flags & SigmaValue) == 0)
4472 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4473 }
4474 option=GetImageOption(image_info,"intent");
4475 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004476 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004477 MagickIntentOptions,MagickFalse,option);
4478 option=GetImageOption(image_info,"interlace");
4479 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004480 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004481 MagickFalse,option);
4482 option=GetImageOption(image_info,"interpolate");
4483 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004484 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004485 MagickInterpolateOptions,MagickFalse,option);
4486 option=GetImageOption(image_info,"loop");
4487 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004488 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004489 option=GetImageOption(image_info,"mattecolor");
4490 if (option != (const char *) NULL)
4491 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4492 option=GetImageOption(image_info,"orient");
4493 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004494 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004495 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004496 option=GetImageOption(image_info,"page");
4497 if (option != (const char *) NULL)
4498 {
4499 char
4500 *geometry;
4501
4502 geometry=GetPageGeometry(option);
4503 flags=ParseAbsoluteGeometry(geometry,&image->page);
4504 geometry=DestroyString(geometry);
4505 }
cristy1626d332009-11-10 16:58:17 +00004506 option=GetImageOption(image_info,"quality");
4507 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004508 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004509 option=GetImageOption(image_info,"red-primary");
4510 if (option != (const char *) NULL)
4511 {
4512 flags=ParseGeometry(option,&geometry_info);
4513 image->chromaticity.red_primary.x=geometry_info.rho;
4514 image->chromaticity.red_primary.y=geometry_info.sigma;
4515 if ((flags & SigmaValue) == 0)
4516 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4517 }
4518 if (image_info->quality != UndefinedCompressionQuality)
4519 image->quality=image_info->quality;
4520 option=GetImageOption(image_info,"scene");
4521 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004522 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004523 option=GetImageOption(image_info,"taint");
4524 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004525 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004526 MagickFalse,option);
4527 option=GetImageOption(image_info,"tile-offset");
4528 if (option != (const char *) NULL)
4529 {
4530 char
4531 *geometry;
4532
4533 geometry=GetPageGeometry(option);
4534 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4535 geometry=DestroyString(geometry);
4536 }
4537 option=GetImageOption(image_info,"transparent-color");
4538 if (option != (const char *) NULL)
4539 (void) QueryColorDatabase(option,&image->transparent_color,
4540 &image->exception);
4541 option=GetImageOption(image_info,"type");
4542 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004543 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004544 option);
4545 option=GetImageOption(image_info,"units");
4546 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004547 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004548 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004549 else
4550 units = image_info->units;
4551 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004552 {
cristy19eb6412010-04-23 14:42:29 +00004553 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004554 switch (image->units)
4555 {
4556 case PixelsPerInchResolution:
4557 {
cristy19eb6412010-04-23 14:42:29 +00004558 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004559 {
4560 image->x_resolution/=2.54;
4561 image->y_resolution/=2.54;
4562 }
4563 break;
4564 }
4565 case PixelsPerCentimeterResolution:
4566 {
cristy19eb6412010-04-23 14:42:29 +00004567 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004568 {
cristybb503372010-05-27 20:51:26 +00004569 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004570 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004571 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004572 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004573 }
4574 break;
4575 }
4576 default:
4577 break;
4578 }
cristy19eb6412010-04-23 14:42:29 +00004579 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004580 }
4581 option=GetImageOption(image_info,"white-point");
4582 if (option != (const char *) NULL)
4583 {
4584 flags=ParseGeometry(option,&geometry_info);
4585 image->chromaticity.white_point.x=geometry_info.rho;
4586 image->chromaticity.white_point.y=geometry_info.sigma;
4587 if ((flags & SigmaValue) == 0)
4588 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4589 }
4590 ResetImageOptionIterator(image_info);
4591 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4592 {
4593 value=GetImageOption(image_info,option);
4594 if (value != (const char *) NULL)
4595 {
4596 (void) FormatMagickString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004597 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004598 }
4599 option=GetNextImageOption(image_info);
4600 }
4601 return(MagickTrue);
4602}