blob: 9a0b76511279466b1632904aba0ac2fb86be0e67 [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;
cristy1fe256f2011-04-26 11:36:04 +0000783 clone_image->channels=image->channels;
cristy3ed852e2009-09-05 21:47:34 +0000784 clone_image->colorspace=image->colorspace;
785 clone_image->matte=image->matte;
786 clone_image->columns=image->columns;
787 clone_image->rows=image->rows;
788 clone_image->dither=image->dither;
789 if (image->colormap != (PixelPacket *) NULL)
790 {
791 /*
792 Allocate and copy the image colormap.
793 */
794 clone_image->colors=image->colors;
795 length=(size_t) image->colors;
796 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
797 sizeof(*clone_image->colormap));
798 if (clone_image->colormap == (PixelPacket *) NULL)
799 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
800 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
801 sizeof(*clone_image->colormap));
802 }
803 (void) CloneImageProfiles(clone_image,image);
804 (void) CloneImageProperties(clone_image,image);
805 (void) CloneImageArtifacts(clone_image,image);
806 GetTimerInfo(&clone_image->timer);
807 GetExceptionInfo(&clone_image->exception);
808 InheritException(&clone_image->exception,&image->exception);
809 if (image->ascii85 != (void *) NULL)
810 Ascii85Initialize(clone_image);
811 clone_image->magick_columns=image->magick_columns;
812 clone_image->magick_rows=image->magick_rows;
813 clone_image->type=image->type;
814 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
815 MaxTextExtent);
816 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
817 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
818 clone_image->progress_monitor=image->progress_monitor;
819 clone_image->client_data=image->client_data;
820 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000821 clone_image->next=image->next;
822 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000823 clone_image->list=NewImageList();
824 clone_image->clip_mask=NewImageList();
825 clone_image->mask=NewImageList();
826 if (detach == MagickFalse)
827 clone_image->blob=ReferenceBlob(image->blob);
828 else
cristybee00932011-01-15 20:28:27 +0000829 {
830 clone_image->next=NewImageList();
831 clone_image->previous=NewImageList();
832 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
833 }
cristy73724512010-04-12 14:43:14 +0000834 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000835 clone_image->debug=IsEventLogging();
836 clone_image->semaphore=AllocateSemaphoreInfo();
837 if ((columns == 0) && (rows == 0))
838 {
839 if (image->montage != (char *) NULL)
840 (void) CloneString(&clone_image->montage,image->montage);
841 if (image->directory != (char *) NULL)
842 (void) CloneString(&clone_image->directory,image->directory);
843 if (image->clip_mask != (Image *) NULL)
844 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
845 exception);
846 if (image->mask != (Image *) NULL)
847 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
848 clone_image->cache=ReferencePixelCache(image->cache);
849 return(clone_image);
850 }
cristy1ab35fb2011-04-15 01:25:56 +0000851 if ((columns == image->columns) && (rows == image->rows))
852 {
853 if (image->clip_mask != (Image *) NULL)
854 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
855 exception);
856 if (image->mask != (Image *) NULL)
857 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
858 }
cristy3ed852e2009-09-05 21:47:34 +0000859 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000860 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
861 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
862 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000863 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000864 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
865 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
866 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000867 clone_image->columns=columns;
868 clone_image->rows=rows;
869 clone_image->cache=ClonePixelCache(image->cache);
870 return(clone_image);
871}
872
873/*
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875% %
876% %
877% %
878% C l o n e I m a g e I n f o %
879% %
880% %
881% %
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883%
884% CloneImageInfo() makes a copy of the given image info structure. If
885% NULL is specified, a new image info structure is created initialized to
886% default values.
887%
888% The format of the CloneImageInfo method is:
889%
890% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
891%
892% A description of each parameter follows:
893%
894% o image_info: the image info.
895%
896*/
897MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
898{
899 ImageInfo
900 *clone_info;
901
902 clone_info=AcquireImageInfo();
903 if (image_info == (ImageInfo *) NULL)
904 return(clone_info);
905 clone_info->compression=image_info->compression;
906 clone_info->temporary=image_info->temporary;
907 clone_info->adjoin=image_info->adjoin;
908 clone_info->antialias=image_info->antialias;
909 clone_info->scene=image_info->scene;
910 clone_info->number_scenes=image_info->number_scenes;
911 clone_info->depth=image_info->depth;
912 if (image_info->size != (char *) NULL)
913 (void) CloneString(&clone_info->size,image_info->size);
914 if (image_info->extract != (char *) NULL)
915 (void) CloneString(&clone_info->extract,image_info->extract);
916 if (image_info->scenes != (char *) NULL)
917 (void) CloneString(&clone_info->scenes,image_info->scenes);
918 if (image_info->page != (char *) NULL)
919 (void) CloneString(&clone_info->page,image_info->page);
920 clone_info->interlace=image_info->interlace;
921 clone_info->endian=image_info->endian;
922 clone_info->units=image_info->units;
923 clone_info->quality=image_info->quality;
924 if (image_info->sampling_factor != (char *) NULL)
925 (void) CloneString(&clone_info->sampling_factor,
926 image_info->sampling_factor);
927 if (image_info->server_name != (char *) NULL)
928 (void) CloneString(&clone_info->server_name,image_info->server_name);
929 if (image_info->font != (char *) NULL)
930 (void) CloneString(&clone_info->font,image_info->font);
931 if (image_info->texture != (char *) NULL)
932 (void) CloneString(&clone_info->texture,image_info->texture);
933 if (image_info->density != (char *) NULL)
934 (void) CloneString(&clone_info->density,image_info->density);
935 clone_info->pointsize=image_info->pointsize;
936 clone_info->fuzz=image_info->fuzz;
937 clone_info->pen=image_info->pen;
938 clone_info->background_color=image_info->background_color;
939 clone_info->border_color=image_info->border_color;
940 clone_info->matte_color=image_info->matte_color;
941 clone_info->transparent_color=image_info->transparent_color;
942 clone_info->dither=image_info->dither;
943 clone_info->monochrome=image_info->monochrome;
944 clone_info->colors=image_info->colors;
945 clone_info->colorspace=image_info->colorspace;
946 clone_info->type=image_info->type;
947 clone_info->orientation=image_info->orientation;
948 clone_info->preview_type=image_info->preview_type;
949 clone_info->group=image_info->group;
950 clone_info->ping=image_info->ping;
951 clone_info->verbose=image_info->verbose;
952 if (image_info->view != (char *) NULL)
953 (void) CloneString(&clone_info->view,image_info->view);
954 if (image_info->authenticate != (char *) NULL)
955 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
956 (void) CloneImageOptions(clone_info,image_info);
957 clone_info->progress_monitor=image_info->progress_monitor;
958 clone_info->client_data=image_info->client_data;
959 clone_info->cache=image_info->cache;
960 if (image_info->cache != (void *) NULL)
961 clone_info->cache=ReferencePixelCache(image_info->cache);
962 if (image_info->profile != (void *) NULL)
963 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
964 image_info->profile);
965 SetImageInfoFile(clone_info,image_info->file);
966 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
967 clone_info->stream=image_info->stream;
968 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
969 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
970 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
971 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
972 (void) CopyMagickString(clone_info->filename,image_info->filename,
973 MaxTextExtent);
974 clone_info->subimage=image_info->scene; /* deprecated */
975 clone_info->subrange=image_info->number_scenes; /* deprecated */
976 clone_info->channel=image_info->channel;
977 clone_info->debug=IsEventLogging();
978 clone_info->signature=image_info->signature;
979 return(clone_info);
980}
981
982/*
983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984% %
985% %
986% %
987% C o m b i n e I m a g e s %
988% %
989% %
990% %
991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992%
993% CombineImages() combines one or more images into a single image. The
994% grayscale value of the pixels of each image in the sequence is assigned in
995% order to the specified channels of the combined image. The typical
996% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
997%
998% The format of the CombineImages method is:
999%
1000% Image *CombineImages(const Image *image,const ChannelType channel,
1001% ExceptionInfo *exception)
1002%
1003% A description of each parameter follows:
1004%
1005% o image: the image.
1006%
1007% o exception: return any errors or warnings in this structure.
1008%
1009*/
1010MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1011 ExceptionInfo *exception)
1012{
1013#define CombineImageTag "Combine/Image"
1014
1015 CacheView
1016 *combine_view;
1017
1018 const Image
1019 *next;
1020
1021 Image
1022 *combine_image;
1023
cristy3ed852e2009-09-05 21:47:34 +00001024 MagickBooleanType
1025 status;
1026
cristybb503372010-05-27 20:51:26 +00001027 MagickOffsetType
1028 progress;
1029
1030 ssize_t
1031 y;
1032
cristy3ed852e2009-09-05 21:47:34 +00001033 /*
1034 Ensure the image are the same size.
1035 */
1036 assert(image != (const Image *) NULL);
1037 assert(image->signature == MagickSignature);
1038 if (image->debug != MagickFalse)
1039 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1040 assert(exception != (ExceptionInfo *) NULL);
1041 assert(exception->signature == MagickSignature);
1042 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1043 {
1044 if ((next->columns != image->columns) || (next->rows != image->rows))
1045 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1046 }
1047 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1048 if (combine_image == (Image *) NULL)
1049 return((Image *) NULL);
1050 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1051 {
1052 InheritException(exception,&combine_image->exception);
1053 combine_image=DestroyImage(combine_image);
1054 return((Image *) NULL);
1055 }
1056 if ((channel & OpacityChannel) != 0)
1057 combine_image->matte=MagickTrue;
1058 (void) SetImageBackgroundColor(combine_image);
1059 /*
1060 Combine images.
1061 */
1062 status=MagickTrue;
1063 progress=0;
1064 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001065 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001066 {
1067 CacheView
1068 *image_view;
1069
1070 const Image
1071 *next;
1072
1073 PixelPacket
1074 *pixels;
1075
1076 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001077 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001078
cristy3ed852e2009-09-05 21:47:34 +00001079 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001080 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001081
cristycb6d09b2010-06-19 01:59:36 +00001082 register ssize_t
1083 x;
1084
cristy3ed852e2009-09-05 21:47:34 +00001085 if (status == MagickFalse)
1086 continue;
1087 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1088 1,exception);
1089 if (pixels == (PixelPacket *) NULL)
1090 {
1091 status=MagickFalse;
1092 continue;
1093 }
1094 next=image;
1095 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
1096 {
1097 image_view=AcquireCacheView(next);
1098 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1099 if (p == (const PixelPacket *) NULL)
1100 continue;
1101 q=pixels;
cristybb503372010-05-27 20:51:26 +00001102 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
cristyce70c172010-01-07 17:15:30 +00001104 SetRedPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001105 p++;
1106 q++;
1107 }
1108 image_view=DestroyCacheView(image_view);
1109 next=GetNextImageInList(next);
1110 }
1111 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
1112 {
1113 image_view=AcquireCacheView(next);
1114 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1115 if (p == (const PixelPacket *) NULL)
1116 continue;
1117 q=pixels;
cristybb503372010-05-27 20:51:26 +00001118 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001119 {
cristyce70c172010-01-07 17:15:30 +00001120 SetGreenPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001121 p++;
1122 q++;
1123 }
1124 image_view=DestroyCacheView(image_view);
1125 next=GetNextImageInList(next);
1126 }
1127 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
1128 {
1129 image_view=AcquireCacheView(next);
1130 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1131 if (p == (const PixelPacket *) NULL)
1132 continue;
1133 q=pixels;
cristybb503372010-05-27 20:51:26 +00001134 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001135 {
cristyce70c172010-01-07 17:15:30 +00001136 SetBluePixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001137 p++;
1138 q++;
1139 }
1140 image_view=DestroyCacheView(image_view);
1141 next=GetNextImageInList(next);
1142 }
1143 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
1144 {
1145 image_view=AcquireCacheView(next);
1146 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1147 if (p == (const PixelPacket *) NULL)
1148 continue;
1149 q=pixels;
cristybb503372010-05-27 20:51:26 +00001150 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001151 {
cristyce70c172010-01-07 17:15:30 +00001152 SetOpacityPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001153 p++;
1154 q++;
1155 }
1156 image_view=DestroyCacheView(image_view);
1157 next=GetNextImageInList(next);
1158 }
1159 if (((channel & IndexChannel) != 0) &&
1160 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1161 {
1162 IndexPacket
1163 *indexes;
1164
1165 image_view=AcquireCacheView(next);
1166 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1167 if (p == (const PixelPacket *) NULL)
1168 continue;
1169 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
cristybb503372010-05-27 20:51:26 +00001170 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001171 {
1172 indexes[x]=PixelIntensityToQuantum(p);
1173 p++;
1174 }
1175 image_view=DestroyCacheView(image_view);
1176 next=GetNextImageInList(next);
1177 }
1178 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1179 status=MagickFalse;
1180 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1181 {
1182 MagickBooleanType
1183 proceed;
1184
cristy3ed852e2009-09-05 21:47:34 +00001185 proceed=SetImageProgress(image,CombineImageTag,progress++,
1186 combine_image->rows);
1187 if (proceed == MagickFalse)
1188 status=MagickFalse;
1189 }
1190 }
1191 combine_view=DestroyCacheView(combine_view);
1192 if (status == MagickFalse)
1193 combine_image=DestroyImage(combine_image);
1194 return(combine_image);
1195}
1196
1197/*
1198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199% %
1200% %
1201% %
cristy3ed852e2009-09-05 21:47:34 +00001202% D e s t r o y I m a g e %
1203% %
1204% %
1205% %
1206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207%
1208% DestroyImage() dereferences an image, deallocating memory associated with
1209% the image if the reference count becomes zero.
1210%
1211% The format of the DestroyImage method is:
1212%
1213% Image *DestroyImage(Image *image)
1214%
1215% A description of each parameter follows:
1216%
1217% o image: the image.
1218%
1219*/
1220MagickExport Image *DestroyImage(Image *image)
1221{
1222 MagickBooleanType
1223 destroy;
1224
1225 /*
1226 Dereference image.
1227 */
1228 assert(image != (Image *) NULL);
1229 assert(image->signature == MagickSignature);
1230 if (image->debug != MagickFalse)
1231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1232 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001233 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001234 image->reference_count--;
1235 if (image->reference_count == 0)
1236 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001237 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001238 if (destroy == MagickFalse)
1239 return((Image *) NULL);
1240 /*
1241 Destroy image.
1242 */
1243 DestroyImagePixels(image);
1244 if (image->clip_mask != (Image *) NULL)
1245 image->clip_mask=DestroyImage(image->clip_mask);
1246 if (image->mask != (Image *) NULL)
1247 image->mask=DestroyImage(image->mask);
1248 if (image->montage != (char *) NULL)
1249 image->montage=DestroyString(image->montage);
1250 if (image->directory != (char *) NULL)
1251 image->directory=DestroyString(image->directory);
1252 if (image->colormap != (PixelPacket *) NULL)
1253 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1254 if (image->geometry != (char *) NULL)
1255 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001256 DestroyImageProfiles(image);
1257 DestroyImageProperties(image);
1258 DestroyImageArtifacts(image);
1259 if (image->ascii85 != (Ascii85Info*) NULL)
1260 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1261 DestroyBlob(image);
1262 (void) DestroyExceptionInfo(&image->exception);
1263 if (image->semaphore != (SemaphoreInfo *) NULL)
1264 DestroySemaphoreInfo(&image->semaphore);
1265 image->signature=(~MagickSignature);
1266 image=(Image *) RelinquishMagickMemory(image);
1267 return(image);
1268}
1269
1270/*
1271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272% %
1273% %
1274% %
1275% D e s t r o y I m a g e I n f o %
1276% %
1277% %
1278% %
1279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280%
1281% DestroyImageInfo() deallocates memory associated with an ImageInfo
1282% structure.
1283%
1284% The format of the DestroyImageInfo method is:
1285%
1286% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1287%
1288% A description of each parameter follows:
1289%
1290% o image_info: the image info.
1291%
1292*/
1293MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1294{
1295 assert(image_info != (ImageInfo *) NULL);
1296 assert(image_info->signature == MagickSignature);
1297 if (image_info->debug != MagickFalse)
1298 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1299 image_info->filename);
1300 if (image_info->size != (char *) NULL)
1301 image_info->size=DestroyString(image_info->size);
1302 if (image_info->extract != (char *) NULL)
1303 image_info->extract=DestroyString(image_info->extract);
1304 if (image_info->scenes != (char *) NULL)
1305 image_info->scenes=DestroyString(image_info->scenes);
1306 if (image_info->page != (char *) NULL)
1307 image_info->page=DestroyString(image_info->page);
1308 if (image_info->sampling_factor != (char *) NULL)
1309 image_info->sampling_factor=DestroyString(
1310 image_info->sampling_factor);
1311 if (image_info->server_name != (char *) NULL)
1312 image_info->server_name=DestroyString(
1313 image_info->server_name);
1314 if (image_info->font != (char *) NULL)
1315 image_info->font=DestroyString(image_info->font);
1316 if (image_info->texture != (char *) NULL)
1317 image_info->texture=DestroyString(image_info->texture);
1318 if (image_info->density != (char *) NULL)
1319 image_info->density=DestroyString(image_info->density);
1320 if (image_info->view != (char *) NULL)
1321 image_info->view=DestroyString(image_info->view);
1322 if (image_info->authenticate != (char *) NULL)
1323 image_info->authenticate=DestroyString(
1324 image_info->authenticate);
1325 DestroyImageOptions(image_info);
1326 if (image_info->cache != (void *) NULL)
1327 image_info->cache=DestroyPixelCache(image_info->cache);
1328 if (image_info->profile != (StringInfo *) NULL)
1329 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1330 image_info->profile);
1331 image_info->signature=(~MagickSignature);
1332 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1333 return(image_info);
1334}
1335
1336/*
1337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1338% %
1339% %
1340% %
1341+ D i s a s s o c i a t e I m a g e S t r e a m %
1342% %
1343% %
1344% %
1345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346%
1347% DisassociateImageStream() disassociates the image stream.
1348%
1349% The format of the DisassociateImageStream method is:
1350%
1351% MagickBooleanType DisassociateImageStream(const Image *image)
1352%
1353% A description of each parameter follows:
1354%
1355% o image: the image.
1356%
1357*/
1358MagickExport void DisassociateImageStream(Image *image)
1359{
1360 assert(image != (const Image *) NULL);
1361 assert(image->signature == MagickSignature);
1362 if (image->debug != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1364 (void) DetachBlob(image->blob);
1365}
1366
1367/*
1368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1369% %
1370% %
1371% %
1372% G e t I m a g e A l p h a C h a n n e l %
1373% %
1374% %
1375% %
1376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377%
1378% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1379% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1380% than CMYKA.
1381%
1382% The format of the GetImageAlphaChannel method is:
1383%
1384% MagickBooleanType GetImageAlphaChannel(const Image *image)
1385%
1386% A description of each parameter follows:
1387%
1388% o image: the image.
1389%
1390*/
1391MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1392{
1393 assert(image != (const Image *) NULL);
1394 if (image->debug != MagickFalse)
1395 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1396 assert(image->signature == MagickSignature);
1397 return(image->matte);
1398}
1399
1400/*
1401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402% %
1403% %
1404% %
1405% G e t I m a g e C l i p M a s k %
1406% %
1407% %
1408% %
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410%
1411% GetImageClipMask() returns the clip path associated with the image.
1412%
1413% The format of the GetImageClipMask method is:
1414%
1415% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1416%
1417% A description of each parameter follows:
1418%
1419% o image: the image.
1420%
1421*/
1422MagickExport Image *GetImageClipMask(const Image *image,
1423 ExceptionInfo *exception)
1424{
1425 assert(image != (const Image *) NULL);
1426 if (image->debug != MagickFalse)
1427 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1428 assert(image->signature == MagickSignature);
1429 if (image->clip_mask == (Image *) NULL)
1430 return((Image *) NULL);
1431 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1432}
1433
1434/*
1435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436% %
1437% %
1438% %
1439% G e t I m a g e E x c e p t i o n %
1440% %
1441% %
1442% %
1443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444%
1445% GetImageException() traverses an image sequence and returns any
1446% error more severe than noted by the exception parameter.
1447%
1448% The format of the GetImageException method is:
1449%
1450% void GetImageException(Image *image,ExceptionInfo *exception)
1451%
1452% A description of each parameter follows:
1453%
1454% o image: Specifies a pointer to a list of one or more images.
1455%
1456% o exception: return the highest severity exception.
1457%
1458*/
1459MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1460{
1461 register Image
1462 *next;
1463
1464 assert(image != (Image *) NULL);
1465 assert(image->signature == MagickSignature);
1466 if (image->debug != MagickFalse)
1467 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1468 assert(exception != (ExceptionInfo *) NULL);
1469 assert(exception->signature == MagickSignature);
1470 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1471 {
1472 if (next->exception.severity == UndefinedException)
1473 continue;
1474 if (next->exception.severity > exception->severity)
1475 InheritException(exception,&next->exception);
1476 next->exception.severity=UndefinedException;
1477 }
1478}
1479
1480/*
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482% %
1483% %
1484% %
1485% G e t I m a g e I n f o %
1486% %
1487% %
1488% %
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490%
1491% GetImageInfo() initializes image_info to default values.
1492%
1493% The format of the GetImageInfo method is:
1494%
1495% void GetImageInfo(ImageInfo *image_info)
1496%
1497% A description of each parameter follows:
1498%
1499% o image_info: the image info.
1500%
1501*/
1502MagickExport void GetImageInfo(ImageInfo *image_info)
1503{
cristyd9a29192010-10-16 16:49:53 +00001504 const char
1505 *synchronize;
1506
cristy3ed852e2009-09-05 21:47:34 +00001507 ExceptionInfo
1508 *exception;
1509
1510 /*
1511 File and image dimension members.
1512 */
1513 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1514 assert(image_info != (ImageInfo *) NULL);
1515 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1516 image_info->adjoin=MagickTrue;
1517 image_info->interlace=NoInterlace;
1518 image_info->channel=DefaultChannels;
1519 image_info->quality=UndefinedCompressionQuality;
1520 image_info->antialias=MagickTrue;
1521 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001522 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1523 if (synchronize != (const char *) NULL)
1524 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001525 exception=AcquireExceptionInfo();
1526 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1527 exception);
1528 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1529 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1530 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1531 exception);
1532 exception=DestroyExceptionInfo(exception);
1533 image_info->debug=IsEventLogging();
1534 image_info->signature=MagickSignature;
1535}
1536
1537/*
1538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539% %
1540% %
1541% %
cristy15781e52009-12-05 23:05:27 +00001542% G e t I m a g e I n f o F i l e %
1543% %
1544% %
1545% %
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547%
1548% GetImageInfoFile() returns the image info file member.
1549%
1550% The format of the GetImageInfoFile method is:
1551%
1552% FILE *GetImageInfoFile(const ImageInfo *image_info)
1553%
1554% A description of each parameter follows:
1555%
1556% o image_info: the image info.
1557%
1558*/
1559MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1560{
1561 return(image_info->file);
1562}
1563
1564/*
1565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566% %
1567% %
1568% %
cristy3ed852e2009-09-05 21:47:34 +00001569% G e t I m a g e M a s k %
1570% %
1571% %
1572% %
1573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574%
1575% GetImageMask() returns the mask associated with the image.
1576%
1577% The format of the GetImageMask method is:
1578%
1579% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1580%
1581% A description of each parameter follows:
1582%
1583% o image: the image.
1584%
1585*/
1586MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1587{
1588 assert(image != (const Image *) NULL);
1589 if (image->debug != MagickFalse)
1590 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1591 assert(image->signature == MagickSignature);
1592 if (image->mask == (Image *) NULL)
1593 return((Image *) NULL);
1594 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1595}
1596
1597/*
1598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599% %
1600% %
1601% %
cristy0d267172011-04-25 20:13:48 +00001602% G e t I m a g e C h a n n e l s %
1603% %
1604% %
1605% %
1606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607%
cristy6cb60a52011-04-25 20:33:58 +00001608% GetImageChannels() returns the number of pixel channels associated with the
1609% specified image.
cristy0d267172011-04-25 20:13:48 +00001610%
1611% The format of the GetChannels method is:
1612%
1613% size_t GetImageChannels(Image *image)
1614%
1615% A description of each parameter follows:
1616%
1617% o image: the image.
1618%
1619*/
1620MagickExport size_t GetImageChannels(Image *image)
1621{
1622 assert(image != (Image *) NULL);
1623 assert(image->signature == MagickSignature);
1624 if (image->debug != MagickFalse)
1625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1626 return(image->channels);
1627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
cristy3ed852e2009-09-05 21:47:34 +00001634+ G e t I m a g e R e f e r e n c e C o u n t %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% GetImageReferenceCount() returns the image reference count.
1641%
1642% The format of the GetReferenceCount method is:
1643%
cristybb503372010-05-27 20:51:26 +00001644% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001645%
1646% A description of each parameter follows:
1647%
1648% o image: the image.
1649%
1650*/
cristybb503372010-05-27 20:51:26 +00001651MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001652{
cristybb503372010-05-27 20:51:26 +00001653 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001654 reference_count;
1655
1656 assert(image != (Image *) NULL);
1657 assert(image->signature == MagickSignature);
1658 if (image->debug != MagickFalse)
1659 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001660 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001661 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001662 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001663 return(reference_count);
1664}
1665
1666/*
1667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668% %
1669% %
1670% %
cristy3ed852e2009-09-05 21:47:34 +00001671% 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 %
1672% %
1673% %
1674% %
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676%
1677% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1678% image. A virtual pixel is any pixel access that is outside the boundaries
1679% of the image cache.
1680%
1681% The format of the GetImageVirtualPixelMethod() method is:
1682%
1683% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1684%
1685% A description of each parameter follows:
1686%
1687% o image: the image.
1688%
1689*/
1690MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1691{
1692 assert(image != (Image *) NULL);
1693 assert(image->signature == MagickSignature);
1694 if (image->debug != MagickFalse)
1695 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1696 return(GetPixelCacheVirtualMethod(image));
1697}
1698
1699/*
1700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701% %
1702% %
1703% %
1704% I n t e r p r e t I m a g e F i l e n a m e %
1705% %
1706% %
1707% %
1708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709%
1710% InterpretImageFilename() interprets embedded characters in an image filename.
1711% The filename length is returned.
1712%
1713% The format of the InterpretImageFilename method is:
1714%
1715% size_t InterpretImageFilename(const ImageInfo *image_info,
1716% Image *image,const char *format,int value,char *filename)
1717%
1718% A description of each parameter follows.
1719%
1720% o image_info: the image info..
1721%
1722% o image: the image.
1723%
1724% o format: A filename describing the format to use to write the numeric
1725% argument. Only the first numeric format identifier is replaced.
1726%
1727% o value: Numeric value to substitute into format filename.
1728%
1729% o filename: return the formatted filename in this character buffer.
1730%
1731*/
1732MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1733 Image *image,const char *format,int value,char *filename)
1734{
1735 char
1736 *q;
1737
1738 int
1739 c;
1740
1741 MagickBooleanType
1742 canonical;
1743
1744 register const char
1745 *p;
1746
1747 canonical=MagickFalse;
1748 (void) CopyMagickString(filename,format,MaxTextExtent);
1749 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1750 {
1751 q=(char *) p+1;
1752 if (*q == '%')
1753 {
1754 p=q+1;
1755 continue;
1756 }
1757 if (*q == '0')
1758 {
cristybb503372010-05-27 20:51:26 +00001759 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001760 value;
1761
cristybb503372010-05-27 20:51:26 +00001762 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001763 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001764 }
1765 switch (*q)
1766 {
1767 case 'd':
1768 case 'o':
1769 case 'x':
1770 {
1771 q++;
1772 c=(*q);
1773 *q='\0';
1774 (void) FormatMagickString(filename+(p-format),(size_t) (MaxTextExtent-
1775 (p-format)),p,value);
1776 *q=c;
1777 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1778 canonical=MagickTrue;
1779 if (*(q-1) != '%')
1780 break;
1781 p++;
1782 break;
1783 }
1784 case '[':
1785 {
1786 char
1787 pattern[MaxTextExtent];
1788
1789 const char
1790 *value;
1791
cristy3ed852e2009-09-05 21:47:34 +00001792 register char
1793 *r;
1794
cristybb503372010-05-27 20:51:26 +00001795 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001796 i;
1797
cristycb6d09b2010-06-19 01:59:36 +00001798 ssize_t
1799 depth;
1800
cristy3ed852e2009-09-05 21:47:34 +00001801 /*
1802 Image option.
1803 */
1804 if (strchr(p,']') == (char *) NULL)
1805 break;
1806 depth=1;
1807 r=q+1;
1808 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1809 {
1810 if (*r == '[')
1811 depth++;
1812 if (*r == ']')
1813 depth--;
1814 if (depth <= 0)
1815 break;
1816 pattern[i]=(*r++);
1817 }
1818 pattern[i]='\0';
1819 if (LocaleNCompare(pattern,"filename:",9) != 0)
1820 break;
1821 value=(const char *) NULL;
1822 if ((image_info != (const ImageInfo *) NULL) &&
1823 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001824 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001825 else
1826 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001827 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001828 else
1829 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001830 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001831 if (value == (const char *) NULL)
1832 break;
1833 q--;
1834 c=(*q);
1835 *q='\0';
1836 (void) CopyMagickString(filename+(p-format),value,(size_t)
1837 (MaxTextExtent-(p-format)));
1838 *q=c;
1839 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1840 canonical=MagickTrue;
1841 if (*(q-1) != '%')
1842 break;
1843 p++;
1844 break;
1845 }
1846 default:
1847 break;
1848 }
1849 }
1850 for (q=filename; *q != '\0'; q++)
1851 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001852 {
1853 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1854 canonical=MagickTrue;
1855 }
cristy3ed852e2009-09-05 21:47:34 +00001856 if (canonical == MagickFalse)
1857 (void) CopyMagickString(filename,format,MaxTextExtent);
1858 return(strlen(filename));
1859}
1860
1861/*
1862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863% %
1864% %
1865% %
1866% I s H i g h D y n a m i c R a n g e I m a g e %
1867% %
1868% %
1869% %
1870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1871%
1872% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1873% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1874% 0..65535.
1875%
1876% The format of the IsHighDynamicRangeImage method is:
1877%
1878% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1879% ExceptionInfo *exception)
1880%
1881% A description of each parameter follows:
1882%
1883% o image: the image.
1884%
1885% o exception: return any errors or warnings in this structure.
1886%
1887*/
1888MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1889 ExceptionInfo *exception)
1890{
1891#if !defined(MAGICKCORE_HDRI_SUPPORT)
1892 (void) image;
1893 (void) exception;
1894 return(MagickFalse);
1895#else
1896 CacheView
1897 *image_view;
1898
cristy3ed852e2009-09-05 21:47:34 +00001899 MagickBooleanType
1900 status;
1901
1902 MagickPixelPacket
1903 zero;
1904
cristycb6d09b2010-06-19 01:59:36 +00001905 ssize_t
1906 y;
1907
cristy3ed852e2009-09-05 21:47:34 +00001908 assert(image != (Image *) NULL);
1909 assert(image->signature == MagickSignature);
1910 if (image->debug != MagickFalse)
1911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1912 status=MagickTrue;
1913 GetMagickPixelPacket(image,&zero);
1914 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001915#if defined(MAGICKCORE_OPENMP_SUPPORT)
1916 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001917#endif
cristybb503372010-05-27 20:51:26 +00001918 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001919 {
1920 MagickPixelPacket
1921 pixel;
1922
1923 register const IndexPacket
1924 *indexes;
1925
1926 register const PixelPacket
1927 *p;
1928
cristybb503372010-05-27 20:51:26 +00001929 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001930 x;
1931
1932 if (status == MagickFalse)
1933 continue;
1934 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1935 if (p == (const PixelPacket *) NULL)
1936 {
1937 status=MagickFalse;
1938 continue;
1939 }
1940 indexes=GetCacheViewVirtualIndexQueue(image_view);
1941 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001942 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001943 {
1944 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1945 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1946 (pixel.red != (QuantumAny) pixel.red))
1947 break;
1948 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1949 (pixel.green != (QuantumAny) pixel.green))
1950 break;
1951 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1952 (pixel.blue != (QuantumAny) pixel.blue))
1953 break;
1954 if (pixel.matte != MagickFalse)
1955 {
1956 if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
1957 (pixel.opacity != (QuantumAny) pixel.opacity))
1958 break;
1959 }
1960 if (pixel.colorspace == CMYKColorspace)
1961 {
1962 if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
1963 (pixel.index != (QuantumAny) pixel.index))
1964 break;
1965 }
1966 p++;
1967 }
cristybb503372010-05-27 20:51:26 +00001968 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001969 status=MagickFalse;
1970 }
1971 image_view=DestroyCacheView(image_view);
1972 return(status != MagickFalse ? MagickFalse : MagickTrue);
1973#endif
1974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
1981% I s I m a g e O b j e c t %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% IsImageObject() returns MagickTrue if the image sequence contains a valid
1988% set of image objects.
1989%
1990% The format of the IsImageObject method is:
1991%
1992% MagickBooleanType IsImageObject(const Image *image)
1993%
1994% A description of each parameter follows:
1995%
1996% o image: the image.
1997%
1998*/
1999MagickExport MagickBooleanType IsImageObject(const Image *image)
2000{
2001 register const Image
2002 *p;
2003
2004 assert(image != (Image *) NULL);
2005 if (image->debug != MagickFalse)
2006 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2007 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2008 if (p->signature != MagickSignature)
2009 return(MagickFalse);
2010 return(MagickTrue);
2011}
2012
2013/*
2014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015% %
2016% %
2017% %
2018% I s T a i n t I m a g e %
2019% %
2020% %
2021% %
2022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023%
2024% IsTaintImage() returns MagickTrue any pixel in the image has been altered
2025% since it was first constituted.
2026%
2027% The format of the IsTaintImage method is:
2028%
2029% MagickBooleanType IsTaintImage(const Image *image)
2030%
2031% A description of each parameter follows:
2032%
2033% o image: the image.
2034%
2035*/
2036MagickExport MagickBooleanType IsTaintImage(const Image *image)
2037{
2038 char
2039 magick[MaxTextExtent],
2040 filename[MaxTextExtent];
2041
2042 register const Image
2043 *p;
2044
2045 assert(image != (Image *) NULL);
2046 if (image->debug != MagickFalse)
2047 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2048 assert(image->signature == MagickSignature);
2049 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2050 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2051 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2052 {
2053 if (p->taint != MagickFalse)
2054 return(MagickTrue);
2055 if (LocaleCompare(p->magick,magick) != 0)
2056 return(MagickTrue);
2057 if (LocaleCompare(p->filename,filename) != 0)
2058 return(MagickTrue);
2059 }
2060 return(MagickFalse);
2061}
2062
2063/*
2064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2065% %
2066% %
2067% %
2068% M o d i f y I m a g e %
2069% %
2070% %
2071% %
2072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2073%
2074% ModifyImage() ensures that there is only a single reference to the image
2075% to be modified, updating the provided image pointer to point to a clone of
2076% the original image if necessary.
2077%
2078% The format of the ModifyImage method is:
2079%
2080% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2081%
2082% A description of each parameter follows:
2083%
2084% o image: the image.
2085%
2086% o exception: return any errors or warnings in this structure.
2087%
2088*/
2089MagickExport MagickBooleanType ModifyImage(Image **image,
2090 ExceptionInfo *exception)
2091{
2092 Image
2093 *clone_image;
2094
2095 assert(image != (Image **) NULL);
2096 assert(*image != (Image *) NULL);
2097 assert((*image)->signature == MagickSignature);
2098 if ((*image)->debug != MagickFalse)
2099 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2100 if (GetImageReferenceCount(*image) <= 1)
2101 return(MagickTrue);
2102 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002103 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002104 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002105 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002106 *image=clone_image;
2107 return(MagickTrue);
2108}
2109
2110/*
2111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2112% %
2113% %
2114% %
2115% N e w M a g i c k I m a g e %
2116% %
2117% %
2118% %
2119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120%
2121% NewMagickImage() creates a blank image canvas of the specified size and
2122% background color.
2123%
2124% The format of the NewMagickImage method is:
2125%
2126% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002127% const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002128% const MagickPixelPacket *background)
2129%
2130% A description of each parameter follows:
2131%
2132% o image: the image.
2133%
2134% o width: the image width.
2135%
2136% o height: the image height.
2137%
2138% o background: the image color.
2139%
2140*/
2141MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002142 const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002143 const MagickPixelPacket *background)
2144{
2145 CacheView
2146 *image_view;
2147
2148 ExceptionInfo
2149 *exception;
2150
2151 Image
2152 *image;
2153
cristybb503372010-05-27 20:51:26 +00002154 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002155 y;
2156
2157 MagickBooleanType
2158 status;
2159
2160 assert(image_info != (const ImageInfo *) NULL);
2161 if (image_info->debug != MagickFalse)
2162 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2163 assert(image_info->signature == MagickSignature);
2164 assert(background != (const MagickPixelPacket *) NULL);
2165 image=AcquireImage(image_info);
2166 image->columns=width;
2167 image->rows=height;
2168 image->colorspace=background->colorspace;
2169 image->matte=background->matte;
2170 image->fuzz=background->fuzz;
2171 image->depth=background->depth;
2172 status=MagickTrue;
2173 exception=(&image->exception);
2174 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002175#if defined(MAGICKCORE_OPENMP_SUPPORT)
2176 #pragma omp parallel for schedule(dynamic,4) shared(status)
2177#endif
cristybb503372010-05-27 20:51:26 +00002178 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002179 {
2180 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002181 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002182
cristy3ed852e2009-09-05 21:47:34 +00002183 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002184 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002185
cristycb6d09b2010-06-19 01:59:36 +00002186 register ssize_t
2187 x;
2188
cristy48974b92009-12-19 02:36:06 +00002189 if (status == MagickFalse)
2190 continue;
cristy3ed852e2009-09-05 21:47:34 +00002191 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2192 if (q == (PixelPacket *) NULL)
2193 {
2194 status=MagickFalse;
2195 continue;
2196 }
2197 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002198 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002199 {
2200 SetPixelPacket(image,background,q,indexes+x);
2201 q++;
2202 }
2203 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2204 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002205 }
2206 image_view=DestroyCacheView(image_view);
2207 if (status == MagickFalse)
2208 image=DestroyImage(image);
2209 return(image);
2210}
2211
2212/*
2213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214% %
2215% %
2216% %
2217% R e f e r e n c e I m a g e %
2218% %
2219% %
2220% %
2221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222%
2223% ReferenceImage() increments the reference count associated with an image
2224% returning a pointer to the image.
2225%
2226% The format of the ReferenceImage method is:
2227%
2228% Image *ReferenceImage(Image *image)
2229%
2230% A description of each parameter follows:
2231%
2232% o image: the image.
2233%
2234*/
2235MagickExport Image *ReferenceImage(Image *image)
2236{
2237 assert(image != (Image *) NULL);
2238 if (image->debug != MagickFalse)
2239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2240 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002241 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002242 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002243 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002244 return(image);
2245}
2246
2247/*
2248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249% %
2250% %
2251% %
2252% R e s e t I m a g e P a g e %
2253% %
2254% %
2255% %
2256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2257%
2258% ResetImagePage() resets the image page canvas and position.
2259%
2260% The format of the ResetImagePage method is:
2261%
2262% MagickBooleanType ResetImagePage(Image *image,const char *page)
2263%
2264% A description of each parameter follows:
2265%
2266% o image: the image.
2267%
2268% o page: the relative page specification.
2269%
2270*/
2271MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2272{
2273 MagickStatusType
2274 flags;
2275
2276 RectangleInfo
2277 geometry;
2278
2279 assert(image != (Image *) NULL);
2280 assert(image->signature == MagickSignature);
2281 if (image->debug != MagickFalse)
2282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2283 flags=ParseAbsoluteGeometry(page,&geometry);
2284 if ((flags & WidthValue) != 0)
2285 {
2286 if ((flags & HeightValue) == 0)
2287 geometry.height=geometry.width;
2288 image->page.width=geometry.width;
2289 image->page.height=geometry.height;
2290 }
2291 if ((flags & AspectValue) != 0)
2292 {
2293 if ((flags & XValue) != 0)
2294 image->page.x+=geometry.x;
2295 if ((flags & YValue) != 0)
2296 image->page.y+=geometry.y;
2297 }
2298 else
2299 {
2300 if ((flags & XValue) != 0)
2301 {
2302 image->page.x=geometry.x;
2303 if ((image->page.width == 0) && (geometry.x > 0))
2304 image->page.width=image->columns+geometry.x;
2305 }
2306 if ((flags & YValue) != 0)
2307 {
2308 image->page.y=geometry.y;
2309 if ((image->page.height == 0) && (geometry.y > 0))
2310 image->page.height=image->rows+geometry.y;
2311 }
2312 }
2313 return(MagickTrue);
2314}
2315
2316/*
2317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318% %
2319% %
2320% %
2321% S e p a r a t e I m a g e C h a n n e l %
2322% %
2323% %
2324% %
2325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326%
2327% SeparateImageChannel() separates a channel from the image and returns it as
2328% a grayscale image. A channel is a particular color component of each pixel
2329% in the image.
2330%
2331% The format of the SeparateImageChannel method is:
2332%
2333% MagickBooleanType SeparateImageChannel(Image *image,
2334% const ChannelType channel)
2335%
2336% A description of each parameter follows:
2337%
2338% o image: the image.
2339%
2340% o channel: Identify which channel to extract: RedChannel, GreenChannel,
2341% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2342% YellowChannel, or BlackChannel.
2343%
2344*/
2345MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2346 const ChannelType channel)
2347{
2348#define SeparateImageTag "Separate/Image"
2349
2350 CacheView
2351 *image_view;
2352
2353 ExceptionInfo
2354 *exception;
2355
cristy3ed852e2009-09-05 21:47:34 +00002356 MagickBooleanType
2357 status;
2358
cristybb503372010-05-27 20:51:26 +00002359 MagickOffsetType
2360 progress;
2361
2362 ssize_t
2363 y;
2364
cristy3ed852e2009-09-05 21:47:34 +00002365 assert(image != (Image *) NULL);
2366 assert(image->signature == MagickSignature);
2367 if (image->debug != MagickFalse)
2368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2369 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2370 return(MagickFalse);
2371 /*
2372 Separate image channels.
2373 */
2374 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002375 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002376 image->matte=MagickTrue;
2377 progress=0;
2378 exception=(&image->exception);
2379 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002380#if defined(MAGICKCORE_OPENMP_SUPPORT)
2381 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002382#endif
cristybb503372010-05-27 20:51:26 +00002383 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002384 {
2385 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002386 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002387
cristy3ed852e2009-09-05 21:47:34 +00002388 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002389 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002390
cristycb6d09b2010-06-19 01:59:36 +00002391 register ssize_t
2392 x;
2393
cristy3ed852e2009-09-05 21:47:34 +00002394 if (status == MagickFalse)
2395 continue;
2396 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2397 if (q == (PixelPacket *) NULL)
2398 {
2399 status=MagickFalse;
2400 continue;
2401 }
2402 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2403 switch (channel)
2404 {
2405 case RedChannel:
2406 {
cristybb503372010-05-27 20:51:26 +00002407 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002408 {
cristyc5071682011-04-22 02:06:27 +00002409 SetGreenPixelComponent(q,GetRedPixelComponent(q));
2410 SetBluePixelComponent(q,GetRedPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002411 q++;
2412 }
2413 break;
2414 }
2415 case GreenChannel:
2416 {
cristybb503372010-05-27 20:51:26 +00002417 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002418 {
cristyc5071682011-04-22 02:06:27 +00002419 SetRedPixelComponent(q,GetGreenPixelComponent(q));
2420 SetBluePixelComponent(q,GetGreenPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002421 q++;
2422 }
2423 break;
2424 }
2425 case BlueChannel:
2426 {
cristybb503372010-05-27 20:51:26 +00002427 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002428 {
cristyc5071682011-04-22 02:06:27 +00002429 SetRedPixelComponent(q,GetBluePixelComponent(q));
2430 SetGreenPixelComponent(q,GetBluePixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002431 q++;
2432 }
2433 break;
2434 }
2435 case OpacityChannel:
2436 {
cristybb503372010-05-27 20:51:26 +00002437 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002438 {
cristyc5071682011-04-22 02:06:27 +00002439 SetRedPixelComponent(q,GetOpacityPixelComponent(q));
2440 SetGreenPixelComponent(q,GetOpacityPixelComponent(q));
2441 SetBluePixelComponent(q,GetOpacityPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002442 q++;
2443 }
2444 break;
2445 }
2446 case BlackChannel:
2447 {
2448 if ((image->storage_class != PseudoClass) &&
2449 (image->colorspace != CMYKColorspace))
2450 break;
cristybb503372010-05-27 20:51:26 +00002451 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002452 {
cristyc5071682011-04-22 02:06:27 +00002453 SetRedPixelComponent(q,indexes[x]);
2454 SetGreenPixelComponent(q,indexes[x]);
2455 SetBluePixelComponent(q,indexes[x]);
cristy3ed852e2009-09-05 21:47:34 +00002456 q++;
2457 }
2458 break;
2459 }
2460 case TrueAlphaChannel:
2461 {
cristybb503372010-05-27 20:51:26 +00002462 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002463 {
cristy4e82e512011-04-24 01:33:42 +00002464 SetRedPixelComponent(q,GetAlphaPixelComponent(q));
2465 SetGreenPixelComponent(q,GetAlphaPixelComponent(q));
2466 SetBluePixelComponent(q,GetAlphaPixelComponent(q));
cristy3ed852e2009-09-05 21:47:34 +00002467 q++;
2468 }
2469 break;
2470 }
2471 case GrayChannels:
2472 {
cristybb503372010-05-27 20:51:26 +00002473 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002474 {
cristy4e82e512011-04-24 01:33:42 +00002475 SetOpacityPixelComponent(q,(QuantumRange-
cristyc5071682011-04-22 02:06:27 +00002476 PixelIntensityToQuantum(q)));
cristy3ed852e2009-09-05 21:47:34 +00002477 q++;
2478 }
2479 break;
2480 }
2481 default:
2482 break;
2483 }
2484 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2485 status=MagickFalse;
2486 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2487 {
2488 MagickBooleanType
2489 proceed;
2490
cristyb5d5f722009-11-04 03:03:49 +00002491#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002492 #pragma omp critical (MagickCore_SeparateImageChannel)
2493#endif
2494 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2495 if (proceed == MagickFalse)
2496 status=MagickFalse;
2497 }
2498 }
2499 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002500 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002501 image->matte=MagickFalse;
2502 (void) SetImageColorspace(image,RGBColorspace);
2503 return(status);
2504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
2511% S e p a r a t e I m a g e s %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% SeparateImages() returns a separate grayscale image for each channel
2518% specified.
2519%
2520% The format of the SeparateImages method is:
2521%
2522% MagickBooleanType SeparateImages(const Image *image,
2523% const ChannelType channel,ExceptionInfo *exception)
2524%
2525% A description of each parameter follows:
2526%
2527% o image: the image.
2528%
2529% o channel: Identify which channels to extract: RedChannel, GreenChannel,
2530% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2531% YellowChannel, or BlackChannel.
2532%
2533% o exception: return any errors or warnings in this structure.
2534%
2535*/
2536MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2537 ExceptionInfo *exception)
2538{
2539 Image
2540 *images,
2541 *separate_image;
2542
2543 assert(image != (Image *) NULL);
2544 assert(image->signature == MagickSignature);
2545 if (image->debug != MagickFalse)
2546 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2547 images=NewImageList();
2548 if ((channel & RedChannel) != 0)
2549 {
2550 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2551 (void) SeparateImageChannel(separate_image,RedChannel);
2552 AppendImageToList(&images,separate_image);
2553 }
2554 if ((channel & GreenChannel) != 0)
2555 {
2556 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2557 (void) SeparateImageChannel(separate_image,GreenChannel);
2558 AppendImageToList(&images,separate_image);
2559 }
2560 if ((channel & BlueChannel) != 0)
2561 {
2562 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2563 (void) SeparateImageChannel(separate_image,BlueChannel);
2564 AppendImageToList(&images,separate_image);
2565 }
2566 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
2567 {
2568 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2569 (void) SeparateImageChannel(separate_image,BlackChannel);
2570 AppendImageToList(&images,separate_image);
2571 }
2572 if ((channel & OpacityChannel) != 0)
2573 {
2574 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2575 (void) SeparateImageChannel(separate_image,OpacityChannel);
2576 AppendImageToList(&images,separate_image);
2577 }
2578 return(images);
2579}
2580
2581/*
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583% %
2584% %
2585% %
2586% S e t I m a g e A l p h a C h a n n e l %
2587% %
2588% %
2589% %
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591%
2592% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2593% channel.
2594%
2595% The format of the SetImageAlphaChannel method is:
2596%
2597% MagickBooleanType SetImageAlphaChannel(Image *image,
2598% const AlphaChannelType alpha_type)
2599%
2600% A description of each parameter follows:
2601%
2602% o image: the image.
2603%
2604% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2605% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
2606% OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
2607% ShapeAlphaChannel, and TransparentAlphaChannel.
2608%
2609*/
2610MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2611 const AlphaChannelType alpha_type)
2612{
2613 MagickBooleanType
2614 status;
2615
2616 assert(image != (Image *) NULL);
2617 if (image->debug != MagickFalse)
2618 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2619 assert(image->signature == MagickSignature);
2620 status=MagickFalse;
2621 switch (alpha_type)
2622 {
2623 case ActivateAlphaChannel:
2624 {
2625 image->matte=MagickTrue;
2626 break;
2627 }
2628 case BackgroundAlphaChannel:
2629 {
2630 CacheView
2631 *image_view;
2632
2633 ExceptionInfo
2634 *exception;
2635
2636 IndexPacket
2637 index;
2638
cristy3ed852e2009-09-05 21:47:34 +00002639 MagickBooleanType
2640 status;
2641
2642 MagickPixelPacket
2643 background;
2644
2645 PixelPacket
2646 pixel;
2647
cristycb6d09b2010-06-19 01:59:36 +00002648 ssize_t
2649 y;
2650
cristy3ed852e2009-09-05 21:47:34 +00002651 /*
2652 Set transparent pixels to background color.
2653 */
2654 if (image->matte == MagickFalse)
2655 break;
2656 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2657 break;
2658 GetMagickPixelPacket(image,&background);
2659 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2660 NULL,&background);
2661 if (image->colorspace == CMYKColorspace)
2662 ConvertRGBToCMYK(&background);
2663 index=0;
2664 SetPixelPacket(image,&background,&pixel,&index);
2665 status=MagickTrue;
2666 exception=(&image->exception);
2667 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002668 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2669 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002670 #endif
cristybb503372010-05-27 20:51:26 +00002671 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002672 {
2673 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002674 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002675
cristy3ed852e2009-09-05 21:47:34 +00002676 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002677 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002678
cristycb6d09b2010-06-19 01:59:36 +00002679 register ssize_t
2680 x;
2681
cristy3ed852e2009-09-05 21:47:34 +00002682 if (status == MagickFalse)
2683 continue;
2684 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2685 exception);
2686 if (q == (PixelPacket *) NULL)
2687 {
2688 status=MagickFalse;
2689 continue;
2690 }
cristybb503372010-05-27 20:51:26 +00002691 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002692 {
2693 if (q->opacity == TransparentOpacity)
2694 {
cristya2d08742011-04-22 19:59:52 +00002695 SetRedPixelComponent(q,pixel.red);
2696 SetGreenPixelComponent(q,pixel.green);
2697 SetBluePixelComponent(q,pixel.blue);
cristy3ed852e2009-09-05 21:47:34 +00002698 }
2699 q++;
2700 }
2701 if (image->colorspace == CMYKColorspace)
2702 {
2703 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002704 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002705 indexes[x]=index;
2706 }
2707 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2708 status=MagickFalse;
2709 }
2710 image_view=DestroyCacheView(image_view);
2711 return(status);
2712 }
2713 case DeactivateAlphaChannel:
2714 {
2715 image->matte=MagickFalse;
2716 break;
2717 }
2718 case ShapeAlphaChannel:
2719 case CopyAlphaChannel:
2720 {
2721 /*
2722 Special usage case for SeparateImageChannel(): copy grayscale color to
2723 the alpha channel.
2724 */
2725 status=SeparateImageChannel(image,GrayChannels);
2726 image->matte=MagickTrue; /* make sure transparency is now on! */
2727 if (alpha_type == ShapeAlphaChannel)
2728 {
2729 MagickPixelPacket
2730 background;
2731
2732 /*
2733 Reset all color channels to background color.
2734 */
2735 GetMagickPixelPacket(image,&background);
2736 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
2737 NULL,&background);
cristy308b4e62009-09-21 14:40:44 +00002738 (void) LevelColorsImage(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002739 }
2740 break;
2741 }
2742 case ExtractAlphaChannel:
2743 {
2744 status=SeparateImageChannel(image,TrueAlphaChannel);
2745 image->matte=MagickFalse;
2746 break;
2747 }
cristyf64d18b2010-04-30 12:47:03 +00002748 case ResetAlphaChannel: /* deprecated */
cristy3ed852e2009-09-05 21:47:34 +00002749 case OpaqueAlphaChannel:
2750 {
2751 status=SetImageOpacity(image,OpaqueOpacity);
2752 image->matte=MagickTrue;
2753 break;
2754 }
2755 case TransparentAlphaChannel:
2756 {
2757 status=SetImageOpacity(image,TransparentOpacity);
2758 image->matte=MagickTrue;
2759 break;
2760 }
2761 case SetAlphaChannel:
2762 {
2763 if (image->matte == MagickFalse)
2764 {
2765 status=SetImageOpacity(image,OpaqueOpacity);
2766 image->matte=MagickTrue;
2767 }
2768 break;
2769 }
2770 case UndefinedAlphaChannel:
2771 break;
2772 }
2773 return(status);
2774}
2775
2776/*
2777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2778% %
2779% %
2780% %
2781% S e t I m a g e B a c k g r o u n d C o l o r %
2782% %
2783% %
2784% %
2785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2786%
2787% SetImageBackgroundColor() initializes the image pixels to the image
2788% background color. The background color is defined by the background_color
2789% member of the image structure.
2790%
2791% The format of the SetImage method is:
2792%
2793% MagickBooleanType SetImageBackgroundColor(Image *image)
2794%
2795% A description of each parameter follows:
2796%
2797% o image: the image.
2798%
2799*/
2800MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2801{
2802 CacheView
2803 *image_view;
2804
2805 ExceptionInfo
2806 *exception;
2807
2808 IndexPacket
2809 index;
2810
cristy3ed852e2009-09-05 21:47:34 +00002811 MagickBooleanType
2812 status;
2813
2814 MagickPixelPacket
2815 background;
2816
2817 PixelPacket
2818 pixel;
2819
cristycb6d09b2010-06-19 01:59:36 +00002820 ssize_t
2821 y;
2822
cristy3ed852e2009-09-05 21:47:34 +00002823 assert(image != (Image *) NULL);
2824 if (image->debug != MagickFalse)
2825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2826 assert(image->signature == MagickSignature);
2827 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2828 return(MagickFalse);
2829 if (image->background_color.opacity != OpaqueOpacity)
2830 image->matte=MagickTrue;
2831 GetMagickPixelPacket(image,&background);
2832 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2833 NULL,&background);
2834 if (image->colorspace == CMYKColorspace)
2835 ConvertRGBToCMYK(&background);
2836 index=0;
2837 SetPixelPacket(image,&background,&pixel,&index);
2838 /*
2839 Set image background color.
2840 */
2841 status=MagickTrue;
2842 exception=(&image->exception);
2843 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002844 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002845 {
cristy3ed852e2009-09-05 21:47:34 +00002846 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002847 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002848
cristycb6d09b2010-06-19 01:59:36 +00002849 register ssize_t
2850 x;
2851
cristy3ed852e2009-09-05 21:47:34 +00002852 if (status == MagickFalse)
2853 continue;
2854 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2855 if (q == (PixelPacket *) NULL)
2856 {
2857 status=MagickFalse;
2858 continue;
2859 }
cristybb503372010-05-27 20:51:26 +00002860 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002861 *q++=pixel;
2862 if (image->colorspace == CMYKColorspace)
2863 {
cristy29058e62011-02-24 03:12:50 +00002864 register IndexPacket
2865 *restrict indexes;
2866
cristy3ed852e2009-09-05 21:47:34 +00002867 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002868 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002869 indexes[x]=index;
2870 }
2871 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2872 status=MagickFalse;
2873 }
2874 image_view=DestroyCacheView(image_view);
2875 return(status);
2876}
2877
2878/*
2879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880% %
2881% %
2882% %
cristy0d267172011-04-25 20:13:48 +00002883% S e t I m a g e C h a n n e l s %
2884% %
2885% %
2886% %
2887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888%
2889% SetImageChannels() sets the number of pixels channels associated with the
2890% image.
2891%
2892% The format of the SetImageChannels method is:
2893%
2894% MagickBooleanType SetImageChannels(Image *image,const size_t channels)
2895%
2896% A description of each parameter follows:
2897%
2898% o image: the image.
2899%
2900% o channels: The number of pixel channels.
2901%
2902*/
2903MagickExport MagickBooleanType SetImageChannels(Image *image,
2904 const size_t channels)
2905{
2906 image->channels=channels;
2907 return(MagickTrue);
2908}
2909
2910/*
2911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2912% %
2913% %
2914% %
cristya5b77cb2010-05-07 19:34:48 +00002915% S e t I m a g e C o l o r %
2916% %
2917% %
2918% %
2919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920%
2921% SetImageColor() set the entire image canvas to the specified color.
2922%
2923% The format of the SetImageColor method is:
2924%
2925% MagickBooleanType SetImageColor(Image *image,
2926% const MagickPixelPacket *color)
2927%
2928% A description of each parameter follows:
2929%
2930% o image: the image.
2931%
2932% o background: the image color.
2933%
2934*/
2935MagickExport MagickBooleanType SetImageColor(Image *image,
2936 const MagickPixelPacket *color)
2937{
2938 CacheView
2939 *image_view;
2940
2941 ExceptionInfo
2942 *exception;
2943
cristya5b77cb2010-05-07 19:34:48 +00002944 MagickBooleanType
2945 status;
2946
cristycb6d09b2010-06-19 01:59:36 +00002947 ssize_t
2948 y;
2949
cristya5b77cb2010-05-07 19:34:48 +00002950 assert(image != (Image *) NULL);
2951 if (image->debug != MagickFalse)
2952 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2953 assert(image->signature == MagickSignature);
2954 assert(color != (const MagickPixelPacket *) NULL);
2955 image->colorspace=color->colorspace;
2956 image->matte=color->matte;
2957 image->fuzz=color->fuzz;
2958 image->depth=color->depth;
2959 status=MagickTrue;
2960 exception=(&image->exception);
2961 image_view=AcquireCacheView(image);
2962#if defined(MAGICKCORE_OPENMP_SUPPORT)
2963 #pragma omp parallel for schedule(dynamic,4) shared(status)
2964#endif
cristybb503372010-05-27 20:51:26 +00002965 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002966 {
2967 register IndexPacket
2968 *restrict indexes;
2969
cristya5b77cb2010-05-07 19:34:48 +00002970 register PixelPacket
2971 *restrict q;
2972
cristycb6d09b2010-06-19 01:59:36 +00002973 register ssize_t
2974 x;
2975
cristya5b77cb2010-05-07 19:34:48 +00002976 if (status == MagickFalse)
2977 continue;
2978 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2979 if (q == (PixelPacket *) NULL)
2980 {
2981 status=MagickFalse;
2982 continue;
2983 }
2984 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002985 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002986 {
2987 SetPixelPacket(image,color,q,indexes+x);
2988 q++;
2989 }
2990 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2991 status=MagickFalse;
2992 }
2993 image_view=DestroyCacheView(image_view);
2994 return(status);
2995}
2996
2997/*
2998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999% %
3000% %
3001% %
cristy3ed852e2009-09-05 21:47:34 +00003002% S e t I m a g e S t o r a g e C l a s s %
3003% %
3004% %
3005% %
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007%
3008% SetImageStorageClass() sets the image class: DirectClass for true color
3009% images or PseudoClass for colormapped images.
3010%
3011% The format of the SetImageStorageClass method is:
3012%
3013% MagickBooleanType SetImageStorageClass(Image *image,
3014% const ClassType storage_class)
3015%
3016% A description of each parameter follows:
3017%
3018% o image: the image.
3019%
3020% o storage_class: The image class.
3021%
3022*/
3023MagickExport MagickBooleanType SetImageStorageClass(Image *image,
3024 const ClassType storage_class)
3025{
cristy3ed852e2009-09-05 21:47:34 +00003026 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00003027 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003028}
3029
3030/*
3031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3032% %
3033% %
3034% %
3035% S e t I m a g e C l i p M a s k %
3036% %
3037% %
3038% %
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040%
3041% SetImageClipMask() associates a clip path with the image. The clip path
3042% must be the same dimensions as the image. Set any pixel component of
3043% the clip path to TransparentOpacity to prevent that corresponding image
3044% pixel component from being updated when SyncAuthenticPixels() is applied.
3045%
3046% The format of the SetImageClipMask method is:
3047%
3048% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
3049%
3050% A description of each parameter follows:
3051%
3052% o image: the image.
3053%
3054% o clip_mask: the image clip path.
3055%
3056*/
3057MagickExport MagickBooleanType SetImageClipMask(Image *image,
3058 const Image *clip_mask)
3059{
3060 assert(image != (Image *) NULL);
3061 if (image->debug != MagickFalse)
3062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3063 assert(image->signature == MagickSignature);
3064 if (clip_mask != (const Image *) NULL)
3065 if ((clip_mask->columns != image->columns) ||
3066 (clip_mask->rows != image->rows))
3067 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3068 if (image->clip_mask != (Image *) NULL)
3069 image->clip_mask=DestroyImage(image->clip_mask);
3070 image->clip_mask=NewImageList();
3071 if (clip_mask == (Image *) NULL)
3072 return(MagickTrue);
3073 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3074 return(MagickFalse);
3075 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
3076 if (image->clip_mask == (Image *) NULL)
3077 return(MagickFalse);
3078 return(MagickTrue);
3079}
3080
3081/*
3082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083% %
3084% %
3085% %
3086% S e t I m a g e E x t e n t %
3087% %
3088% %
3089% %
3090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3091%
3092% SetImageExtent() sets the image size (i.e. columns & rows).
3093%
3094% The format of the SetImageExtent method is:
3095%
3096% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003097% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003098%
3099% A description of each parameter follows:
3100%
3101% o image: the image.
3102%
3103% o columns: The image width in pixels.
3104%
3105% o rows: The image height in pixels.
3106%
3107*/
3108MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003109 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003110{
cristy537e2722010-09-21 15:30:59 +00003111 if ((columns == 0) || (rows == 0))
3112 return(MagickFalse);
3113 image->columns=columns;
3114 image->rows=rows;
3115 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003116}
3117
3118/*
3119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3120% %
3121% %
3122% %
3123+ S e t I m a g e I n f o %
3124% %
3125% %
3126% %
3127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3128%
3129% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3130% It is set to a type of image format based on the prefix or suffix of the
3131% filename. For example, `ps:image' returns PS indicating a Postscript image.
3132% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3133% precendence over the suffix. Use an optional index enclosed in brackets
3134% after a file name to specify a desired scene of a multi-resolution image
3135% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3136% indicates success.
3137%
3138% The format of the SetImageInfo method is:
3139%
3140% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003141% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003142%
3143% A description of each parameter follows:
3144%
cristyd965a422010-03-03 17:47:35 +00003145% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003146%
cristyd965a422010-03-03 17:47:35 +00003147% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003148%
3149% o exception: return any errors or warnings in this structure.
3150%
3151*/
3152MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003153 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003154{
3155 char
3156 extension[MaxTextExtent],
3157 filename[MaxTextExtent],
3158 magic[MaxTextExtent],
3159 *q,
3160 subimage[MaxTextExtent];
3161
3162 const MagicInfo
3163 *magic_info;
3164
3165 const MagickInfo
3166 *magick_info;
3167
3168 ExceptionInfo
3169 *sans_exception;
3170
3171 Image
3172 *image;
3173
3174 MagickBooleanType
3175 status;
3176
3177 register const char
3178 *p;
3179
3180 ssize_t
3181 count;
3182
3183 unsigned char
3184 magick[2*MaxTextExtent];
3185
3186 /*
3187 Look for 'image.format' in filename.
3188 */
3189 assert(image_info != (ImageInfo *) NULL);
3190 assert(image_info->signature == MagickSignature);
3191 if (image_info->debug != MagickFalse)
3192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3193 image_info->filename);
3194 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003195 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003196 {
cristyd965a422010-03-03 17:47:35 +00003197 GetPathComponent(image_info->filename,SubimagePath,subimage);
3198 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003199 {
cristyd965a422010-03-03 17:47:35 +00003200 /*
3201 Look for scene specification (e.g. img0001.pcd[4]).
3202 */
3203 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3204 {
3205 if (IsGeometry(subimage) != MagickFalse)
3206 (void) CloneString(&image_info->extract,subimage);
3207 }
3208 else
3209 {
cristybb503372010-05-27 20:51:26 +00003210 size_t
cristyd965a422010-03-03 17:47:35 +00003211 first,
3212 last;
cristy3ed852e2009-09-05 21:47:34 +00003213
cristyd965a422010-03-03 17:47:35 +00003214 (void) CloneString(&image_info->scenes,subimage);
3215 image_info->scene=StringToUnsignedLong(image_info->scenes);
3216 image_info->number_scenes=image_info->scene;
3217 p=image_info->scenes;
3218 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3219 {
3220 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3221 (*p == ','))
3222 p++;
cristybb503372010-05-27 20:51:26 +00003223 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003224 last=first;
3225 while (isspace((int) ((unsigned char) *q)) != 0)
3226 q++;
3227 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003228 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003229 if (first > last)
3230 Swap(first,last);
3231 if (first < image_info->scene)
3232 image_info->scene=first;
3233 if (last > image_info->number_scenes)
3234 image_info->number_scenes=last;
3235 p=q;
3236 }
3237 image_info->number_scenes-=image_info->scene-1;
3238 image_info->subimage=image_info->scene;
3239 image_info->subrange=image_info->number_scenes;
3240 }
cristy3ed852e2009-09-05 21:47:34 +00003241 }
3242 }
3243 *extension='\0';
3244 GetPathComponent(image_info->filename,ExtensionPath,extension);
3245#if defined(MAGICKCORE_ZLIB_DELEGATE)
3246 if (*extension != '\0')
3247 if ((LocaleCompare(extension,"gz") == 0) ||
3248 (LocaleCompare(extension,"Z") == 0) ||
3249 (LocaleCompare(extension,"wmz") == 0))
3250 {
3251 char
3252 path[MaxTextExtent];
3253
3254 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3255 path[strlen(path)-strlen(extension)-1]='\0';
3256 GetPathComponent(path,ExtensionPath,extension);
3257 }
3258#endif
3259#if defined(MAGICKCORE_BZLIB_DELEGATE)
3260 if (*extension != '\0')
3261 if (LocaleCompare(extension,"bz2") == 0)
3262 {
3263 char
3264 path[MaxTextExtent];
3265
3266 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3267 path[strlen(path)-strlen(extension)-1]='\0';
3268 GetPathComponent(path,ExtensionPath,extension);
3269 }
3270#endif
3271 image_info->affirm=MagickFalse;
3272 sans_exception=AcquireExceptionInfo();
3273 if (*extension != '\0')
3274 {
3275 MagickFormatType
3276 format_type;
3277
cristybb503372010-05-27 20:51:26 +00003278 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003279 i;
3280
3281 static const char
3282 *format_type_formats[] =
3283 {
3284 "AUTOTRACE",
3285 "BROWSE",
3286 "DCRAW",
3287 "EDIT",
3288 "EPHEMERAL",
3289 "LAUNCH",
3290 "MPEG:DECODE",
3291 "MPEG:ENCODE",
3292 "PRINT",
3293 "PS:ALPHA",
3294 "PS:CMYK",
3295 "PS:COLOR",
3296 "PS:GRAY",
3297 "PS:MONO",
3298 "SCAN",
3299 "SHOW",
3300 "WIN",
3301 (char *) NULL
3302 };
3303
3304 /*
3305 User specified image format.
3306 */
3307 (void) CopyMagickString(magic,extension,MaxTextExtent);
3308 LocaleUpper(magic);
3309 /*
3310 Look for explicit image formats.
3311 */
3312 format_type=UndefinedFormatType;
3313 i=0;
cristydd9a2532010-02-20 19:26:46 +00003314 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003315 (format_type_formats[i] != (char *) NULL))
3316 {
3317 if ((*magic == *format_type_formats[i]) &&
3318 (LocaleCompare(magic,format_type_formats[i]) == 0))
3319 format_type=ExplicitFormatType;
3320 i++;
3321 }
3322 magick_info=GetMagickInfo(magic,sans_exception);
3323 if ((magick_info != (const MagickInfo *) NULL) &&
3324 (magick_info->format_type != UndefinedFormatType))
3325 format_type=magick_info->format_type;
3326 if (format_type == UndefinedFormatType)
3327 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3328 else
3329 if (format_type == ExplicitFormatType)
3330 {
3331 image_info->affirm=MagickTrue;
3332 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3333 }
3334 if (LocaleCompare(magic,"RGB") == 0)
3335 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3336 }
3337 /*
3338 Look for explicit 'format:image' in filename.
3339 */
3340 *magic='\0';
3341 GetPathComponent(image_info->filename,MagickPath,magic);
3342 if (*magic == '\0')
3343 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3344 else
3345 {
3346 /*
3347 User specified image format.
3348 */
3349 LocaleUpper(magic);
3350 if (IsMagickConflict(magic) == MagickFalse)
3351 {
3352 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3353 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3354 image_info->affirm=MagickTrue;
3355 else
3356 image_info->temporary=MagickTrue;
3357 }
3358 }
3359 magick_info=GetMagickInfo(magic,sans_exception);
3360 sans_exception=DestroyExceptionInfo(sans_exception);
3361 if ((magick_info == (const MagickInfo *) NULL) ||
3362 (GetMagickEndianSupport(magick_info) == MagickFalse))
3363 image_info->endian=UndefinedEndian;
3364 GetPathComponent(image_info->filename,CanonicalPath,filename);
3365 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003366 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003367 {
3368 /*
cristyd965a422010-03-03 17:47:35 +00003369 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003370 */
cristyd965a422010-03-03 17:47:35 +00003371 (void) InterpretImageFilename(image_info,(Image *) NULL,
3372 image_info->filename,(int) image_info->scene,filename);
3373 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3374 (strchr(filename,'%') == (char *) NULL))
3375 image_info->adjoin=MagickFalse;
3376 }
3377 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3378 {
3379 /*
3380 Some image formats do not support multiple frames per file.
3381 */
cristy3ed852e2009-09-05 21:47:34 +00003382 magick_info=GetMagickInfo(magic,exception);
3383 if (magick_info != (const MagickInfo *) NULL)
3384 if (GetMagickAdjoin(magick_info) == MagickFalse)
3385 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003386 }
3387 if (image_info->affirm != MagickFalse)
3388 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003389 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003390 {
3391 /*
cristyd965a422010-03-03 17:47:35 +00003392 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003393 */
cristyd965a422010-03-03 17:47:35 +00003394 image=AcquireImage(image_info);
3395 (void) CopyMagickString(image->filename,image_info->filename,
3396 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003397 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3398 if (status == MagickFalse)
3399 {
3400 image=DestroyImage(image);
3401 return(MagickFalse);
3402 }
cristyd965a422010-03-03 17:47:35 +00003403 if ((IsBlobSeekable(image) == MagickFalse) ||
3404 (IsBlobExempt(image) != MagickFalse))
3405 {
3406 /*
3407 Copy standard input or pipe to temporary file.
3408 */
3409 *filename='\0';
3410 status=ImageToFile(image,filename,exception);
3411 (void) CloseBlob(image);
3412 if (status == MagickFalse)
3413 {
3414 image=DestroyImage(image);
3415 return(MagickFalse);
3416 }
3417 SetImageInfoFile(image_info,(FILE *) NULL);
3418 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3419 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3420 if (status == MagickFalse)
3421 {
3422 image=DestroyImage(image);
3423 return(MagickFalse);
3424 }
3425 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3426 image_info->temporary=MagickTrue;
3427 }
3428 (void) ResetMagickMemory(magick,0,sizeof(magick));
3429 count=ReadBlob(image,2*MaxTextExtent,magick);
3430 (void) CloseBlob(image);
3431 image=DestroyImage(image);
3432 /*
3433 Check magic.xml configuration file.
3434 */
3435 sans_exception=AcquireExceptionInfo();
3436 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3437 if ((magic_info != (const MagicInfo *) NULL) &&
3438 (GetMagicName(magic_info) != (char *) NULL))
3439 {
3440 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3441 MaxTextExtent);
3442 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3443 if ((magick_info == (const MagickInfo *) NULL) ||
3444 (GetMagickEndianSupport(magick_info) == MagickFalse))
3445 image_info->endian=UndefinedEndian;
3446 sans_exception=DestroyExceptionInfo(sans_exception);
3447 return(MagickTrue);
3448 }
cristy3ed852e2009-09-05 21:47:34 +00003449 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3450 if ((magick_info == (const MagickInfo *) NULL) ||
3451 (GetMagickEndianSupport(magick_info) == MagickFalse))
3452 image_info->endian=UndefinedEndian;
3453 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003454 }
cristy3ed852e2009-09-05 21:47:34 +00003455 return(MagickTrue);
3456}
3457
3458/*
3459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3460% %
3461% %
3462% %
3463% S e t I m a g e I n f o B l o b %
3464% %
3465% %
3466% %
3467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3468%
3469% SetImageInfoBlob() sets the image info blob member.
3470%
3471% The format of the SetImageInfoBlob method is:
3472%
3473% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3474% const size_t length)
3475%
3476% A description of each parameter follows:
3477%
3478% o image_info: the image info.
3479%
3480% o blob: the blob.
3481%
3482% o length: the blob length.
3483%
3484*/
3485MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3486 const size_t length)
3487{
3488 assert(image_info != (ImageInfo *) NULL);
3489 assert(image_info->signature == MagickSignature);
3490 if (image_info->debug != MagickFalse)
3491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3492 image_info->filename);
3493 image_info->blob=(void *) blob;
3494 image_info->length=length;
3495}
3496
3497/*
3498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3499% %
3500% %
3501% %
3502% S e t I m a g e I n f o F i l e %
3503% %
3504% %
3505% %
3506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507%
3508% SetImageInfoFile() sets the image info file member.
3509%
3510% The format of the SetImageInfoFile method is:
3511%
3512% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3513%
3514% A description of each parameter follows:
3515%
3516% o image_info: the image info.
3517%
3518% o file: the file.
3519%
3520*/
3521MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3522{
3523 assert(image_info != (ImageInfo *) NULL);
3524 assert(image_info->signature == MagickSignature);
3525 if (image_info->debug != MagickFalse)
3526 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3527 image_info->filename);
3528 image_info->file=file;
3529}
3530
3531/*
3532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3533% %
3534% %
3535% %
3536% S e t I m a g e M a s k %
3537% %
3538% %
3539% %
3540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3541%
3542% SetImageMask() associates a mask with the image. The mask must be the same
3543% dimensions as the image.
3544%
3545% The format of the SetImageMask method is:
3546%
3547% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3548%
3549% A description of each parameter follows:
3550%
3551% o image: the image.
3552%
3553% o mask: the image mask.
3554%
3555*/
3556MagickExport MagickBooleanType SetImageMask(Image *image,
3557 const Image *mask)
3558{
3559 assert(image != (Image *) NULL);
3560 if (image->debug != MagickFalse)
3561 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3562 assert(image->signature == MagickSignature);
3563 if (mask != (const Image *) NULL)
3564 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3565 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3566 if (image->mask != (Image *) NULL)
3567 image->mask=DestroyImage(image->mask);
3568 image->mask=NewImageList();
3569 if (mask == (Image *) NULL)
3570 return(MagickTrue);
3571 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3572 return(MagickFalse);
3573 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3574 if (image->mask == (Image *) NULL)
3575 return(MagickFalse);
3576 return(MagickTrue);
3577}
3578
3579/*
3580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3581% %
3582% %
3583% %
3584% S e t I m a g e O p a c i t y %
3585% %
3586% %
3587% %
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589%
3590% SetImageOpacity() sets the opacity levels of the image.
3591%
3592% The format of the SetImageOpacity method is:
3593%
3594% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3595%
3596% A description of each parameter follows:
3597%
3598% o image: the image.
3599%
3600% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3601% fully transparent.
3602%
3603*/
3604MagickExport MagickBooleanType SetImageOpacity(Image *image,
3605 const Quantum opacity)
3606{
3607 CacheView
3608 *image_view;
3609
3610 ExceptionInfo
3611 *exception;
3612
cristy3ed852e2009-09-05 21:47:34 +00003613 MagickBooleanType
3614 status;
3615
cristycb6d09b2010-06-19 01:59:36 +00003616 ssize_t
3617 y;
3618
cristy3ed852e2009-09-05 21:47:34 +00003619 assert(image != (Image *) NULL);
3620 if (image->debug != MagickFalse)
3621 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3622 assert(image->signature == MagickSignature);
3623 image->matte=opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3624 status=MagickTrue;
3625 exception=(&image->exception);
3626 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003627#if defined(MAGICKCORE_OPENMP_SUPPORT)
3628 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003629#endif
cristybb503372010-05-27 20:51:26 +00003630 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003631 {
cristy3ed852e2009-09-05 21:47:34 +00003632 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003633 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003634
cristycb6d09b2010-06-19 01:59:36 +00003635 register ssize_t
3636 x;
3637
cristy3ed852e2009-09-05 21:47:34 +00003638 if (status == MagickFalse)
3639 continue;
3640 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3641 if (q == (PixelPacket *) NULL)
3642 {
3643 status=MagickFalse;
3644 continue;
3645 }
cristybb503372010-05-27 20:51:26 +00003646 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003647 {
cristy46f08202010-01-10 04:04:21 +00003648 SetOpacityPixelComponent(q,opacity);
cristy3ed852e2009-09-05 21:47:34 +00003649 q++;
3650 }
3651 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3652 status=MagickFalse;
3653 }
3654 image_view=DestroyCacheView(image_view);
3655 return(status);
3656}
3657
3658/*
3659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3660% %
3661% %
3662% %
3663% S e t I m a g e T y p e %
3664% %
3665% %
3666% %
3667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3668%
3669% SetImageType() sets the type of image. Choose from these types:
3670%
3671% Bilevel Grayscale GrayscaleMatte
3672% Palette PaletteMatte TrueColor
3673% TrueColorMatte ColorSeparation ColorSeparationMatte
3674% OptimizeType
3675%
3676% The format of the SetImageType method is:
3677%
3678% MagickBooleanType SetImageType(Image *image,const ImageType type)
3679%
3680% A description of each parameter follows:
3681%
3682% o image: the image.
3683%
3684% o type: Image type.
3685%
3686*/
3687MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3688{
3689 const char
3690 *artifact;
3691
3692 ImageInfo
3693 *image_info;
3694
3695 MagickBooleanType
3696 status;
3697
3698 QuantizeInfo
3699 *quantize_info;
3700
3701 assert(image != (Image *) NULL);
3702 if (image->debug != MagickFalse)
3703 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3704 assert(image->signature == MagickSignature);
3705 status=MagickTrue;
3706 image_info=AcquireImageInfo();
3707 image_info->dither=image->dither;
3708 artifact=GetImageArtifact(image,"dither");
3709 if (artifact != (const char *) NULL)
3710 (void) SetImageOption(image_info,"dither",artifact);
3711 switch (type)
3712 {
3713 case BilevelType:
3714 {
3715 if (IsGrayImage(image,&image->exception) == MagickFalse)
3716 status=TransformImageColorspace(image,GRAYColorspace);
3717 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
3718 {
3719 quantize_info=AcquireQuantizeInfo(image_info);
3720 quantize_info->number_colors=2;
3721 quantize_info->colorspace=GRAYColorspace;
3722 status=QuantizeImage(quantize_info,image);
3723 quantize_info=DestroyQuantizeInfo(quantize_info);
3724 }
3725 image->matte=MagickFalse;
3726 break;
3727 }
3728 case GrayscaleType:
3729 {
3730 if (IsGrayImage(image,&image->exception) == MagickFalse)
3731 status=TransformImageColorspace(image,GRAYColorspace);
3732 image->matte=MagickFalse;
3733 break;
3734 }
3735 case GrayscaleMatteType:
3736 {
3737 if (IsGrayImage(image,&image->exception) == MagickFalse)
3738 status=TransformImageColorspace(image,GRAYColorspace);
3739 if (image->matte == MagickFalse)
3740 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3741 break;
3742 }
3743 case PaletteType:
3744 {
3745 if (image->colorspace != RGBColorspace)
3746 status=TransformImageColorspace(image,RGBColorspace);
3747 if ((image->storage_class == DirectClass) || (image->colors > 256))
3748 {
3749 quantize_info=AcquireQuantizeInfo(image_info);
3750 quantize_info->number_colors=256;
3751 status=QuantizeImage(quantize_info,image);
3752 quantize_info=DestroyQuantizeInfo(quantize_info);
3753 }
3754 image->matte=MagickFalse;
3755 break;
3756 }
3757 case PaletteBilevelMatteType:
3758 {
3759 if (image->colorspace != RGBColorspace)
3760 status=TransformImageColorspace(image,RGBColorspace);
3761 if (image->matte == MagickFalse)
3762 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3763 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3764 quantize_info=AcquireQuantizeInfo(image_info);
3765 status=QuantizeImage(quantize_info,image);
3766 quantize_info=DestroyQuantizeInfo(quantize_info);
3767 break;
3768 }
3769 case PaletteMatteType:
3770 {
3771 if (image->colorspace != RGBColorspace)
3772 status=TransformImageColorspace(image,RGBColorspace);
3773 if (image->matte == MagickFalse)
3774 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3775 quantize_info=AcquireQuantizeInfo(image_info);
3776 quantize_info->colorspace=TransparentColorspace;
3777 status=QuantizeImage(quantize_info,image);
3778 quantize_info=DestroyQuantizeInfo(quantize_info);
3779 break;
3780 }
3781 case TrueColorType:
3782 {
3783 if (image->colorspace != RGBColorspace)
3784 status=TransformImageColorspace(image,RGBColorspace);
3785 if (image->storage_class != DirectClass)
3786 status=SetImageStorageClass(image,DirectClass);
3787 image->matte=MagickFalse;
3788 break;
3789 }
3790 case TrueColorMatteType:
3791 {
3792 if (image->colorspace != RGBColorspace)
3793 status=TransformImageColorspace(image,RGBColorspace);
3794 if (image->storage_class != DirectClass)
3795 status=SetImageStorageClass(image,DirectClass);
3796 if (image->matte == MagickFalse)
3797 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3798 break;
3799 }
3800 case ColorSeparationType:
3801 {
3802 if (image->colorspace != CMYKColorspace)
3803 {
3804 if (image->colorspace != RGBColorspace)
3805 status=TransformImageColorspace(image,RGBColorspace);
3806 status=TransformImageColorspace(image,CMYKColorspace);
3807 }
3808 if (image->storage_class != DirectClass)
3809 status=SetImageStorageClass(image,DirectClass);
3810 image->matte=MagickFalse;
3811 break;
3812 }
3813 case ColorSeparationMatteType:
3814 {
3815 if (image->colorspace != CMYKColorspace)
3816 {
3817 if (image->colorspace != RGBColorspace)
3818 status=TransformImageColorspace(image,RGBColorspace);
3819 status=TransformImageColorspace(image,CMYKColorspace);
3820 }
3821 if (image->storage_class != DirectClass)
3822 status=SetImageStorageClass(image,DirectClass);
3823 if (image->matte == MagickFalse)
3824 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3825 break;
3826 }
3827 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003828 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003829 break;
3830 }
3831 image->type=type;
3832 image_info=DestroyImageInfo(image_info);
3833 return(status);
3834}
3835
3836/*
3837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838% %
3839% %
3840% %
3841% 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 %
3842% %
3843% %
3844% %
3845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846%
3847% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3848% image and returns the previous setting. A virtual pixel is any pixel access
3849% that is outside the boundaries of the image cache.
3850%
3851% The format of the SetImageVirtualPixelMethod() method is:
3852%
3853% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3854% const VirtualPixelMethod virtual_pixel_method)
3855%
3856% A description of each parameter follows:
3857%
3858% o image: the image.
3859%
3860% o virtual_pixel_method: choose the type of virtual pixel.
3861%
3862*/
3863MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3864 const VirtualPixelMethod virtual_pixel_method)
3865{
3866 assert(image != (const Image *) NULL);
3867 assert(image->signature == MagickSignature);
3868 if (image->debug != MagickFalse)
3869 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3870 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3871}
3872
3873/*
3874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3875% %
3876% %
3877% %
cristy4285d782011-02-09 20:12:28 +00003878% S m u s h I m a g e s %
3879% %
3880% %
3881% %
3882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3883%
3884% SmushImages() takes all images from the current image pointer to the end
3885% of the image list and smushes them to each other top-to-bottom if the
3886% stack parameter is true, otherwise left-to-right.
3887%
3888% The current gravity setting now effects how the image is justified in the
3889% final image.
3890%
3891% The format of the SmushImages method is:
3892%
cristy4ca38e22011-02-10 02:57:49 +00003893% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003894% ExceptionInfo *exception)
3895%
3896% A description of each parameter follows:
3897%
cristy4ca38e22011-02-10 02:57:49 +00003898% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003899%
3900% o stack: A value other than 0 stacks the images top-to-bottom.
3901%
3902% o offset: minimum distance in pixels between images.
3903%
3904% o exception: return any errors or warnings in this structure.
3905%
3906*/
cristy4ca38e22011-02-10 02:57:49 +00003907
cristy7c6dc152011-02-11 14:10:55 +00003908static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003909 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003910{
cristy4d727152011-02-10 19:57:21 +00003911 CacheView
3912 *left_view,
3913 *right_view;
3914
3915 const Image
3916 *left_image,
3917 *right_image;
3918
cristy4d727152011-02-10 19:57:21 +00003919 RectangleInfo
3920 left_geometry,
3921 right_geometry;
3922
cristydab7e912011-02-11 18:19:24 +00003923 register const PixelPacket
3924 *p;
3925
cristy4d727152011-02-10 19:57:21 +00003926 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003927 i,
cristy4d727152011-02-10 19:57:21 +00003928 y;
3929
cristy7c6dc152011-02-11 14:10:55 +00003930 size_t
3931 gap;
3932
cristy4d727152011-02-10 19:57:21 +00003933 ssize_t
cristy4d727152011-02-10 19:57:21 +00003934 x;
3935
3936 if (images->previous == (Image *) NULL)
3937 return(0);
3938 right_image=images;
3939 SetGeometry(smush_image,&right_geometry);
3940 GravityAdjustGeometry(right_image->columns,right_image->rows,
3941 right_image->gravity,&right_geometry);
3942 left_image=images->previous;
3943 SetGeometry(smush_image,&left_geometry);
3944 GravityAdjustGeometry(left_image->columns,left_image->rows,
3945 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003946 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003947 left_view=AcquireCacheView(left_image);
3948 right_view=AcquireCacheView(right_image);
3949 for (y=0; y < (ssize_t) smush_image->rows; y++)
3950 {
3951 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3952 {
cristydab7e912011-02-11 18:19:24 +00003953 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3954 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003955 (GetOpacityPixelComponent(p) != TransparentOpacity) ||
cristy7c6dc152011-02-11 14:10:55 +00003956 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003957 break;
3958 }
cristy4ef6f062011-02-10 20:30:22 +00003959 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003960 for (x=0; x < (ssize_t) right_image->columns; x++)
3961 {
cristydab7e912011-02-11 18:19:24 +00003962 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003963 exception);
cristydab7e912011-02-11 18:19:24 +00003964 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00003965 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003966 break;
3967 }
cristy7c6dc152011-02-11 14:10:55 +00003968 if ((x+i) < (ssize_t) gap)
3969 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003970 }
3971 right_view=DestroyCacheView(right_view);
3972 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003973 if (y < (ssize_t) smush_image->rows)
3974 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003975 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003976}
3977
cristy7c6dc152011-02-11 14:10:55 +00003978static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003979 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003980{
cristy4d727152011-02-10 19:57:21 +00003981 CacheView
3982 *bottom_view,
3983 *top_view;
3984
3985 const Image
3986 *bottom_image,
3987 *top_image;
3988
cristy4d727152011-02-10 19:57:21 +00003989 RectangleInfo
3990 bottom_geometry,
3991 top_geometry;
3992
cristydab7e912011-02-11 18:19:24 +00003993 register const PixelPacket
3994 *p;
3995
cristy4d727152011-02-10 19:57:21 +00003996 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003997 i,
cristy4d727152011-02-10 19:57:21 +00003998 x;
3999
cristy7c6dc152011-02-11 14:10:55 +00004000 size_t
4001 gap;
4002
cristy4d727152011-02-10 19:57:21 +00004003 ssize_t
cristy4d727152011-02-10 19:57:21 +00004004 y;
4005
4006 if (images->previous == (Image *) NULL)
4007 return(0);
4008 bottom_image=images;
4009 SetGeometry(smush_image,&bottom_geometry);
4010 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
4011 bottom_image->gravity,&bottom_geometry);
4012 top_image=images->previous;
4013 SetGeometry(smush_image,&top_geometry);
4014 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
4015 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00004016 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00004017 top_view=AcquireCacheView(top_image);
4018 bottom_view=AcquireCacheView(bottom_image);
4019 for (x=0; x < (ssize_t) smush_image->columns; x++)
4020 {
4021 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
4022 {
cristydab7e912011-02-11 18:19:24 +00004023 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
4024 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004025 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00004026 break;
4027 }
cristy4ef6f062011-02-10 20:30:22 +00004028 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00004029 for (y=0; y < (ssize_t) bottom_image->rows; y++)
4030 {
cristydab7e912011-02-11 18:19:24 +00004031 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
4032 exception);
4033 if ((p == (const PixelPacket *) NULL) ||
cristy89bbeaf2011-04-22 20:25:27 +00004034 (GetOpacityPixelComponent(p) != TransparentOpacity) || ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00004035 break;
4036 }
cristy7c6dc152011-02-11 14:10:55 +00004037 if ((y+i) < (ssize_t) gap)
4038 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00004039 }
4040 bottom_view=DestroyCacheView(bottom_view);
4041 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00004042 if (x < (ssize_t) smush_image->columns)
4043 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00004044 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00004045}
4046
4047MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00004048 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
4049{
4050#define SmushImageTag "Smush/Image"
4051
4052 CacheView
cristybb5dced2011-02-10 02:17:16 +00004053 *smush_view;
cristy4285d782011-02-09 20:12:28 +00004054
cristy4ca38e22011-02-10 02:57:49 +00004055 const Image
4056 *image;
4057
cristy4285d782011-02-09 20:12:28 +00004058 Image
4059 *smush_image;
4060
4061 MagickBooleanType
4062 matte,
4063 proceed,
4064 status;
4065
4066 MagickOffsetType
4067 n;
4068
4069 RectangleInfo
4070 geometry;
4071
4072 register const Image
4073 *next;
4074
4075 size_t
4076 height,
4077 number_images,
4078 width;
4079
4080 ssize_t
4081 x_offset,
cristy4285d782011-02-09 20:12:28 +00004082 y_offset;
4083
4084 /*
cristy7c6dc152011-02-11 14:10:55 +00004085 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00004086 */
cristy4ca38e22011-02-10 02:57:49 +00004087 assert(images != (Image *) NULL);
4088 assert(images->signature == MagickSignature);
4089 if (images->debug != MagickFalse)
4090 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00004091 assert(exception != (ExceptionInfo *) NULL);
4092 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00004093 image=images;
cristy4285d782011-02-09 20:12:28 +00004094 matte=image->matte;
4095 number_images=1;
4096 width=image->columns;
4097 height=image->rows;
4098 next=GetNextImageInList(image);
4099 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4100 {
4101 if (next->matte != MagickFalse)
4102 matte=MagickTrue;
4103 number_images++;
4104 if (stack != MagickFalse)
4105 {
4106 if (next->columns > width)
4107 width=next->columns;
4108 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004109 if (next->previous != (Image *) NULL)
4110 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004111 continue;
4112 }
4113 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004114 if (next->previous != (Image *) NULL)
4115 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004116 if (next->rows > height)
4117 height=next->rows;
4118 }
4119 /*
cristy7c6dc152011-02-11 14:10:55 +00004120 Smush images.
cristy4285d782011-02-09 20:12:28 +00004121 */
4122 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4123 if (smush_image == (Image *) NULL)
4124 return((Image *) NULL);
4125 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4126 {
4127 InheritException(exception,&smush_image->exception);
4128 smush_image=DestroyImage(smush_image);
4129 return((Image *) NULL);
4130 }
4131 smush_image->matte=matte;
4132 (void) SetImageBackgroundColor(smush_image);
4133 status=MagickTrue;
4134 x_offset=0;
4135 y_offset=0;
4136 smush_view=AcquireCacheView(smush_image);
4137 for (n=0; n < (MagickOffsetType) number_images; n++)
4138 {
4139 SetGeometry(smush_image,&geometry);
4140 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4141 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004142 {
4143 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004144 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004145 }
cristy4285d782011-02-09 20:12:28 +00004146 else
cristy4ca38e22011-02-10 02:57:49 +00004147 {
cristy7c6dc152011-02-11 14:10:55 +00004148 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004149 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004150 }
cristybb5dced2011-02-10 02:17:16 +00004151 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004152 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4153 if (proceed == MagickFalse)
4154 break;
4155 if (stack == MagickFalse)
4156 {
4157 x_offset+=(ssize_t) image->columns;
4158 y_offset=0;
4159 }
4160 else
4161 {
4162 x_offset=0;
4163 y_offset+=(ssize_t) image->rows;
4164 }
4165 image=GetNextImageInList(image);
4166 }
cristy4ef6f062011-02-10 20:30:22 +00004167 if (stack == MagickFalse)
4168 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004169 else
cristy4ef6f062011-02-10 20:30:22 +00004170 smush_image->rows=(size_t) y_offset;
4171 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004172 if (status == MagickFalse)
4173 smush_image=DestroyImage(smush_image);
4174 return(smush_image);
4175}
4176
4177/*
4178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4179% %
4180% %
4181% %
cristy3ed852e2009-09-05 21:47:34 +00004182% S t r i p I m a g e %
4183% %
4184% %
4185% %
4186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4187%
cristy376bda92009-12-22 21:15:23 +00004188% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004189%
4190% The format of the StripImage method is:
4191%
4192% MagickBooleanType StripImage(Image *image)
4193%
4194% A description of each parameter follows:
4195%
4196% o image: the image.
4197%
4198*/
4199MagickExport MagickBooleanType StripImage(Image *image)
4200{
4201 assert(image != (Image *) NULL);
4202 if (image->debug != MagickFalse)
4203 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4204 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004205 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004206 (void) DeleteImageProperty(image,"date:create");
4207 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004208 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004209 return(MagickTrue);
4210}
4211
4212/*
4213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4214% %
4215% %
4216% %
4217+ S y n c I m a g e %
4218% %
4219% %
4220% %
4221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4222%
4223% SyncImage() initializes the red, green, and blue intensities of each pixel
4224% as defined by the colormap index.
4225%
4226% The format of the SyncImage method is:
4227%
4228% MagickBooleanType SyncImage(Image *image)
4229%
4230% A description of each parameter follows:
4231%
4232% o image: the image.
4233%
4234*/
4235
4236static inline IndexPacket PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004237 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004238{
4239 if (index < image->colors)
4240 return((IndexPacket) index);
4241 *range_exception=MagickTrue;
4242 return((IndexPacket) 0);
4243}
4244
4245MagickExport MagickBooleanType SyncImage(Image *image)
4246{
4247 CacheView
4248 *image_view;
4249
4250 ExceptionInfo
4251 *exception;
4252
cristy3ed852e2009-09-05 21:47:34 +00004253 MagickBooleanType
4254 range_exception,
4255 status;
4256
cristycb6d09b2010-06-19 01:59:36 +00004257 ssize_t
4258 y;
4259
cristy3ed852e2009-09-05 21:47:34 +00004260 assert(image != (Image *) NULL);
4261 if (image->debug != MagickFalse)
4262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4263 assert(image->signature == MagickSignature);
4264 if (image->storage_class == DirectClass)
4265 return(MagickFalse);
4266 range_exception=MagickFalse;
4267 status=MagickTrue;
4268 exception=(&image->exception);
4269 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004270#if defined(MAGICKCORE_OPENMP_SUPPORT)
4271 #pragma omp parallel for schedule(dynamic,4) shared(status)
4272#endif
cristybb503372010-05-27 20:51:26 +00004273 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004274 {
4275 IndexPacket
4276 index;
4277
4278 PixelPacket
4279 pixel;
4280
4281 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004282 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00004283
cristy3ed852e2009-09-05 21:47:34 +00004284 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004285 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004286
cristycb6d09b2010-06-19 01:59:36 +00004287 register ssize_t
4288 x;
4289
cristy48974b92009-12-19 02:36:06 +00004290 if (status == MagickFalse)
4291 continue;
cristy3ed852e2009-09-05 21:47:34 +00004292 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4293 if (q == (PixelPacket *) NULL)
4294 {
4295 status=MagickFalse;
4296 continue;
4297 }
4298 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00004299 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004300 {
cristyc5071682011-04-22 02:06:27 +00004301 index=PushColormapIndex(image,(size_t) indexes[x],&range_exception);
cristybb503372010-05-27 20:51:26 +00004302 pixel=image->colormap[(ssize_t) index];
cristya2d08742011-04-22 19:59:52 +00004303 SetRedPixelComponent(q,pixel.red);
4304 SetGreenPixelComponent(q,pixel.green);
4305 SetBluePixelComponent(q,pixel.blue);
cristyd0272592010-04-21 01:01:49 +00004306 if (image->matte != MagickFalse)
cristya2d08742011-04-22 19:59:52 +00004307 SetOpacityPixelComponent(q,pixel.opacity);
cristy3ed852e2009-09-05 21:47:34 +00004308 q++;
4309 }
4310 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4311 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004312 }
4313 image_view=DestroyCacheView(image_view);
4314 if (range_exception != MagickFalse)
4315 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4316 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4317 return(status);
4318}
cristy1626d332009-11-10 16:58:17 +00004319
4320/*
4321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4322% %
4323% %
4324% %
4325% S y n c I m a g e S e t t i n g s %
4326% %
4327% %
4328% %
4329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330%
4331% SyncImageSettings() sync the image info options to the image.
4332%
4333% The format of the SyncImageSettings method is:
4334%
4335% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4336% Image *image)
4337% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4338% Image *image)
4339%
4340% A description of each parameter follows:
4341%
4342% o image_info: the image info.
4343%
4344% o image: the image.
4345%
4346*/
4347
4348MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4349 Image *images)
4350{
4351 Image
4352 *image;
4353
4354 assert(image_info != (const ImageInfo *) NULL);
4355 assert(image_info->signature == MagickSignature);
4356 assert(images != (Image *) NULL);
4357 assert(images->signature == MagickSignature);
4358 if (images->debug != MagickFalse)
4359 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4360 image=images;
4361 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4362 (void) SyncImageSettings(image_info,image);
4363 (void) DeleteImageOption(image_info,"page");
4364 return(MagickTrue);
4365}
4366
4367MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4368 Image *image)
4369{
4370 char
4371 property[MaxTextExtent];
4372
4373 const char
cristy9a703812010-07-26 14:50:29 +00004374 *option,
4375 *value;
cristy1626d332009-11-10 16:58:17 +00004376
4377 GeometryInfo
4378 geometry_info;
4379
4380 MagickStatusType
4381 flags;
4382
cristy19eb6412010-04-23 14:42:29 +00004383 ResolutionType
4384 units;
4385
cristy1626d332009-11-10 16:58:17 +00004386 /*
4387 Sync image options.
4388 */
4389 assert(image_info != (const ImageInfo *) NULL);
4390 assert(image_info->signature == MagickSignature);
4391 assert(image != (Image *) NULL);
4392 assert(image->signature == MagickSignature);
4393 if (image->debug != MagickFalse)
4394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4395 option=GetImageOption(image_info,"background");
4396 if (option != (const char *) NULL)
4397 (void) QueryColorDatabase(option,&image->background_color,
4398 &image->exception);
4399 option=GetImageOption(image_info,"bias");
4400 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004401 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004402 option=GetImageOption(image_info,"black-point-compensation");
4403 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004404 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004405 MagickBooleanOptions,MagickFalse,option);
4406 option=GetImageOption(image_info,"blue-primary");
4407 if (option != (const char *) NULL)
4408 {
4409 flags=ParseGeometry(option,&geometry_info);
4410 image->chromaticity.blue_primary.x=geometry_info.rho;
4411 image->chromaticity.blue_primary.y=geometry_info.sigma;
4412 if ((flags & SigmaValue) == 0)
4413 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4414 }
4415 option=GetImageOption(image_info,"bordercolor");
4416 if (option != (const char *) NULL)
4417 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4418 option=GetImageOption(image_info,"colors");
4419 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004420 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004421 option=GetImageOption(image_info,"compose");
4422 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004423 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004424 MagickFalse,option);
4425 option=GetImageOption(image_info,"compress");
4426 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004427 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004428 MagickCompressOptions,MagickFalse,option);
4429 option=GetImageOption(image_info,"debug");
4430 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004431 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004432 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004433 option=GetImageOption(image_info,"density");
4434 if (option != (const char *) NULL)
4435 {
4436 GeometryInfo
4437 geometry_info;
4438
4439 /*
4440 Set image density.
4441 */
4442 flags=ParseGeometry(option,&geometry_info);
4443 image->x_resolution=geometry_info.rho;
4444 image->y_resolution=geometry_info.sigma;
4445 if ((flags & SigmaValue) == 0)
4446 image->y_resolution=image->x_resolution;
4447 }
cristy1626d332009-11-10 16:58:17 +00004448 option=GetImageOption(image_info,"depth");
4449 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004450 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004451 option=GetImageOption(image_info,"endian");
4452 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004453 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004454 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004455 option=GetImageOption(image_info,"filter");
4456 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004457 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004458 MagickFalse,option);
4459 option=GetImageOption(image_info,"fuzz");
4460 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004461 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004462 option=GetImageOption(image_info,"gravity");
4463 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004464 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004465 MagickFalse,option);
4466 option=GetImageOption(image_info,"green-primary");
4467 if (option != (const char *) NULL)
4468 {
4469 flags=ParseGeometry(option,&geometry_info);
4470 image->chromaticity.green_primary.x=geometry_info.rho;
4471 image->chromaticity.green_primary.y=geometry_info.sigma;
4472 if ((flags & SigmaValue) == 0)
4473 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4474 }
4475 option=GetImageOption(image_info,"intent");
4476 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004477 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004478 MagickIntentOptions,MagickFalse,option);
4479 option=GetImageOption(image_info,"interlace");
4480 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004481 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004482 MagickFalse,option);
4483 option=GetImageOption(image_info,"interpolate");
4484 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004485 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004486 MagickInterpolateOptions,MagickFalse,option);
4487 option=GetImageOption(image_info,"loop");
4488 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004489 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004490 option=GetImageOption(image_info,"mattecolor");
4491 if (option != (const char *) NULL)
4492 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4493 option=GetImageOption(image_info,"orient");
4494 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004495 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004496 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004497 option=GetImageOption(image_info,"page");
4498 if (option != (const char *) NULL)
4499 {
4500 char
4501 *geometry;
4502
4503 geometry=GetPageGeometry(option);
4504 flags=ParseAbsoluteGeometry(geometry,&image->page);
4505 geometry=DestroyString(geometry);
4506 }
cristy1626d332009-11-10 16:58:17 +00004507 option=GetImageOption(image_info,"quality");
4508 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004509 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004510 option=GetImageOption(image_info,"red-primary");
4511 if (option != (const char *) NULL)
4512 {
4513 flags=ParseGeometry(option,&geometry_info);
4514 image->chromaticity.red_primary.x=geometry_info.rho;
4515 image->chromaticity.red_primary.y=geometry_info.sigma;
4516 if ((flags & SigmaValue) == 0)
4517 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4518 }
4519 if (image_info->quality != UndefinedCompressionQuality)
4520 image->quality=image_info->quality;
4521 option=GetImageOption(image_info,"scene");
4522 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004523 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004524 option=GetImageOption(image_info,"taint");
4525 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004526 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004527 MagickFalse,option);
4528 option=GetImageOption(image_info,"tile-offset");
4529 if (option != (const char *) NULL)
4530 {
4531 char
4532 *geometry;
4533
4534 geometry=GetPageGeometry(option);
4535 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4536 geometry=DestroyString(geometry);
4537 }
4538 option=GetImageOption(image_info,"transparent-color");
4539 if (option != (const char *) NULL)
4540 (void) QueryColorDatabase(option,&image->transparent_color,
4541 &image->exception);
4542 option=GetImageOption(image_info,"type");
4543 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004544 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004545 option);
4546 option=GetImageOption(image_info,"units");
4547 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004548 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004549 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004550 else
4551 units = image_info->units;
4552 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004553 {
cristy19eb6412010-04-23 14:42:29 +00004554 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004555 switch (image->units)
4556 {
4557 case PixelsPerInchResolution:
4558 {
cristy19eb6412010-04-23 14:42:29 +00004559 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004560 {
4561 image->x_resolution/=2.54;
4562 image->y_resolution/=2.54;
4563 }
4564 break;
4565 }
4566 case PixelsPerCentimeterResolution:
4567 {
cristy19eb6412010-04-23 14:42:29 +00004568 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004569 {
cristybb503372010-05-27 20:51:26 +00004570 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004571 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004572 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004573 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004574 }
4575 break;
4576 }
4577 default:
4578 break;
4579 }
cristy19eb6412010-04-23 14:42:29 +00004580 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004581 }
4582 option=GetImageOption(image_info,"white-point");
4583 if (option != (const char *) NULL)
4584 {
4585 flags=ParseGeometry(option,&geometry_info);
4586 image->chromaticity.white_point.x=geometry_info.rho;
4587 image->chromaticity.white_point.y=geometry_info.sigma;
4588 if ((flags & SigmaValue) == 0)
4589 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4590 }
4591 ResetImageOptionIterator(image_info);
4592 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4593 {
4594 value=GetImageOption(image_info,option);
4595 if (value != (const char *) NULL)
4596 {
4597 (void) FormatMagickString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004598 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004599 }
4600 option=GetNextImageOption(image_info);
4601 }
4602 return(MagickTrue);
4603}