blob: 81085be07133db83616efb6fab17ca648be09c2d [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% IIIII M M AAA GGGG EEEEE %
7% I MM MM A A G E %
8% I M M M AAAAA G GG EEE %
9% I M M A A G G E %
10% IIIII M M A A GGGG EEEEE %
11% %
12% %
13% MagickCore Image Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/animate.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/attribute.h"
47#include "MagickCore/blob.h"
48#include "MagickCore/blob-private.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-private.h"
51#include "MagickCore/cache-view.h"
52#include "MagickCore/client.h"
53#include "MagickCore/color.h"
54#include "MagickCore/color-private.h"
55#include "MagickCore/colormap.h"
56#include "MagickCore/colorspace.h"
57#include "MagickCore/colorspace-private.h"
58#include "MagickCore/composite.h"
59#include "MagickCore/composite-private.h"
60#include "MagickCore/compress.h"
61#include "MagickCore/constitute.h"
62#include "MagickCore/display.h"
63#include "MagickCore/draw.h"
64#include "MagickCore/enhance.h"
65#include "MagickCore/exception.h"
66#include "MagickCore/exception-private.h"
67#include "MagickCore/gem.h"
68#include "MagickCore/geometry.h"
69#include "MagickCore/histogram.h"
70#include "MagickCore/image-private.h"
71#include "MagickCore/list.h"
72#include "MagickCore/magic.h"
73#include "MagickCore/magick.h"
74#include "MagickCore/memory_.h"
75#include "MagickCore/module.h"
76#include "MagickCore/monitor.h"
77#include "MagickCore/monitor-private.h"
78#include "MagickCore/option.h"
79#include "MagickCore/paint.h"
80#include "MagickCore/pixel-accessor.h"
81#include "MagickCore/profile.h"
82#include "MagickCore/property.h"
83#include "MagickCore/quantize.h"
84#include "MagickCore/random_.h"
85#include "MagickCore/segment.h"
86#include "MagickCore/semaphore.h"
87#include "MagickCore/signature-private.h"
88#include "MagickCore/statistic.h"
89#include "MagickCore/string_.h"
90#include "MagickCore/string-private.h"
91#include "MagickCore/thread-private.h"
92#include "MagickCore/threshold.h"
93#include "MagickCore/timer.h"
94#include "MagickCore/utility.h"
95#include "MagickCore/version.h"
96#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000097
98/*
99 Constant declaration.
100*/
101const char
cristy7138c592009-09-08 13:58:52 +0000102 BackgroundColor[] = "#ffffff", /* white */
103 BorderColor[] = "#dfdfdf", /* gray */
104 DefaultTileFrame[] = "15x15+3+3",
105 DefaultTileGeometry[] = "120x120+4+3>",
106 DefaultTileLabel[] = "%f\n%G\n%b",
107 ForegroundColor[] = "#000", /* black */
108 LoadImageTag[] = "Load/Image",
109 LoadImagesTag[] = "Load/Images",
110 MatteColor[] = "#bdbdbd", /* gray */
111 PSDensityGeometry[] = "72.0x72.0",
112 PSPageGeometry[] = "612x792",
113 SaveImageTag[] = "Save/Image",
114 SaveImagesTag[] = "Save/Images",
115 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000116
117const double
118 DefaultResolution = 72.0;
119
120/*
121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122% %
123% %
124% %
125% A c q u i r e I m a g e %
126% %
127% %
128% %
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%
131% AcquireImage() returns a pointer to an image structure initialized to
132% default values.
133%
134% The format of the AcquireImage method is:
135%
136% Image *AcquireImage(const ImageInfo *image_info)
137%
138% A description of each parameter follows:
139%
140% o image_info: Many of the image default values are set from this
141% structure. For example, filename, compression, depth, background color,
142% and others.
143%
144*/
145MagickExport Image *AcquireImage(const ImageInfo *image_info)
146{
cristye412c892010-07-26 12:31:36 +0000147 const char
cristyf3a660a2010-07-26 14:17:52 +0000148 *option;
cristye412c892010-07-26 12:31:36 +0000149
cristy3ed852e2009-09-05 21:47:34 +0000150 Image
151 *image;
152
153 MagickStatusType
154 flags;
155
156 /*
157 Allocate image structure.
158 */
159 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy73bd4a52010-10-05 11:24:23 +0000160 image=(Image *) AcquireMagickMemory(sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000161 if (image == (Image *) NULL)
162 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
163 (void) ResetMagickMemory(image,0,sizeof(*image));
164 /*
165 Initialize Image structure.
166 */
167 (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
168 image->storage_class=DirectClass;
169 image->depth=MAGICKCORE_QUANTUM_DEPTH;
170 image->colorspace=RGBColorspace;
171 image->interlace=NoInterlace;
172 image->ticks_per_second=UndefinedTicksPerSecond;
173 image->compose=OverCompositeOp;
174 image->blur=1.0;
175 GetExceptionInfo(&image->exception);
176 (void) QueryColorDatabase(BackgroundColor,&image->background_color,
177 &image->exception);
178 (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
179 (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
180 (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
181 &image->exception);
182 image->x_resolution=DefaultResolution;
183 image->y_resolution=DefaultResolution;
184 image->units=PixelsPerInchResolution;
185 GetTimerInfo(&image->timer);
cristy73724512010-04-12 14:43:14 +0000186 image->ping=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000187 image->cache=AcquirePixelCache(0);
cristy4c08aed2011-07-01 19:47:50 +0000188 image->component_map=AcquirePixelComponentMap();
cristy3ed852e2009-09-05 21:47:34 +0000189 image->blob=CloneBlobInfo((BlobInfo *) NULL);
190 image->debug=IsEventLogging();
191 image->reference_count=1;
192 image->semaphore=AllocateSemaphoreInfo();
193 image->signature=MagickSignature;
194 if (image_info == (ImageInfo *) NULL)
195 return(image);
196 /*
197 Transfer image info.
198 */
199 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
200 MagickFalse);
201 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
202 (void) CopyMagickString(image->magick_filename,image_info->filename,
203 MaxTextExtent);
204 (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
205 if (image_info->size != (char *) NULL)
206 {
207 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
208 image->columns=image->extract_info.width;
209 image->rows=image->extract_info.height;
210 image->offset=image->extract_info.x;
211 image->extract_info.x=0;
212 image->extract_info.y=0;
213 }
214 if (image_info->extract != (char *) NULL)
215 {
216 RectangleInfo
217 geometry;
218
219 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
220 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
221 {
222 image->extract_info=geometry;
223 Swap(image->columns,image->extract_info.width);
224 Swap(image->rows,image->extract_info.height);
225 }
226 }
227 image->compression=image_info->compression;
228 image->quality=image_info->quality;
229 image->endian=image_info->endian;
230 image->interlace=image_info->interlace;
231 image->units=image_info->units;
232 if (image_info->density != (char *) NULL)
233 {
234 GeometryInfo
235 geometry_info;
236
237 flags=ParseGeometry(image_info->density,&geometry_info);
238 image->x_resolution=geometry_info.rho;
239 image->y_resolution=geometry_info.sigma;
240 if ((flags & SigmaValue) == 0)
241 image->y_resolution=image->x_resolution;
242 }
243 if (image_info->page != (char *) NULL)
244 {
245 char
246 *geometry;
247
248 image->page=image->extract_info;
249 geometry=GetPageGeometry(image_info->page);
250 (void) ParseAbsoluteGeometry(geometry,&image->page);
251 geometry=DestroyString(geometry);
252 }
253 if (image_info->depth != 0)
254 image->depth=image_info->depth;
255 image->dither=image_info->dither;
256 image->background_color=image_info->background_color;
257 image->border_color=image_info->border_color;
258 image->matte_color=image_info->matte_color;
259 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000260 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000261 image->progress_monitor=image_info->progress_monitor;
262 image->client_data=image_info->client_data;
263 if (image_info->cache != (void *) NULL)
264 ClonePixelCacheMethods(image->cache,image_info->cache);
265 (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
cristy6b9aca12010-02-21 01:50:11 +0000266 (void) SyncImageSettings(image_info,image);
cristye412c892010-07-26 12:31:36 +0000267 option=GetImageOption(image_info,"delay");
268 if (option != (const char *) NULL)
269 {
270 GeometryInfo
271 geometry_info;
272
273 flags=ParseGeometry(option,&geometry_info);
274 if ((flags & GreaterValue) != 0)
275 {
276 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
277 image->delay=(size_t) floor(geometry_info.rho+0.5);
278 }
279 else
280 if ((flags & LessValue) != 0)
281 {
282 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
283 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
284 }
285 else
286 image->delay=(size_t) floor(geometry_info.rho+0.5);
287 if ((flags & SigmaValue) != 0)
288 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
289 }
290 option=GetImageOption(image_info,"dispose");
291 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000292 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
cristye412c892010-07-26 12:31:36 +0000293 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000294 return(image);
295}
296
297/*
298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299% %
300% %
301% %
cristy3ed852e2009-09-05 21:47:34 +0000302% A c q u i r e I m a g e I n f o %
303% %
304% %
305% %
306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307%
308% AcquireImageInfo() allocates the ImageInfo structure.
309%
310% The format of the AcquireImageInfo method is:
311%
312% ImageInfo *AcquireImageInfo(void)
313%
314*/
315MagickExport ImageInfo *AcquireImageInfo(void)
316{
317 ImageInfo
318 *image_info;
319
cristy73bd4a52010-10-05 11:24:23 +0000320 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000321 if (image_info == (ImageInfo *) NULL)
322 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
323 GetImageInfo(image_info);
324 return(image_info);
325}
326
327/*
328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329% %
330% %
331% %
332% A c q u i r e N e x t I m a g e %
333% %
334% %
335% %
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337%
338% AcquireNextImage() initializes the next image in a sequence to
339% default values. The next member of image points to the newly allocated
340% image. If there is a memory shortage, next is assigned NULL.
341%
342% The format of the AcquireNextImage method is:
343%
344% void AcquireNextImage(const ImageInfo *image_info,Image *image)
345%
346% A description of each parameter follows:
347%
348% o image_info: Many of the image default values are set from this
349% structure. For example, filename, compression, depth, background color,
350% and others.
351%
352% o image: the image.
353%
354*/
355MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
356{
357 /*
358 Allocate image structure.
359 */
360 assert(image != (Image *) NULL);
361 assert(image->signature == MagickSignature);
362 if (image->debug != MagickFalse)
363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
364 image->next=AcquireImage(image_info);
365 if (GetNextImageInList(image) == (Image *) NULL)
366 return;
367 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
368 MaxTextExtent);
369 if (image_info != (ImageInfo *) NULL)
370 (void) CopyMagickString(GetNextImageInList(image)->filename,
371 image_info->filename,MaxTextExtent);
372 DestroyBlob(GetNextImageInList(image));
373 image->next->blob=ReferenceBlob(image->blob);
374 image->next->endian=image->endian;
375 image->next->scene=image->scene+1;
376 image->next->previous=image;
377}
378
379/*
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381% %
382% %
383% %
384% A p p e n d I m a g e s %
385% %
386% %
387% %
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389%
390% AppendImages() takes all images from the current image pointer to the end
391% of the image list and appends them to each other top-to-bottom if the
392% stack parameter is true, otherwise left-to-right.
393%
394% The current gravity setting now effects how the image is justified in the
395% final image.
396%
397% The format of the AppendImages method is:
398%
cristy4ca38e22011-02-10 02:57:49 +0000399% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000400% ExceptionInfo *exception)
401%
402% A description of each parameter follows:
403%
cristy4ca38e22011-02-10 02:57:49 +0000404% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000405%
406% o stack: A value other than 0 stacks the images top-to-bottom.
407%
408% o exception: return any errors or warnings in this structure.
409%
410*/
cristy4ca38e22011-02-10 02:57:49 +0000411MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000412 const MagickBooleanType stack,ExceptionInfo *exception)
413{
414#define AppendImageTag "Append/Image"
415
416 CacheView
417 *append_view,
418 *image_view;
419
cristy4ca38e22011-02-10 02:57:49 +0000420 const Image
421 *image;
422
cristy3ed852e2009-09-05 21:47:34 +0000423 Image
424 *append_image;
425
cristy3ed852e2009-09-05 21:47:34 +0000426 MagickBooleanType
427 matte,
428 proceed,
429 status;
430
cristybb503372010-05-27 20:51:26 +0000431 MagickOffsetType
432 n;
433
cristy3ed852e2009-09-05 21:47:34 +0000434 RectangleInfo
435 geometry;
436
437 register const Image
438 *next;
439
cristybb503372010-05-27 20:51:26 +0000440 size_t
cristy3ed852e2009-09-05 21:47:34 +0000441 height,
442 number_images,
443 width;
444
cristybb503372010-05-27 20:51:26 +0000445 ssize_t
446 x_offset,
447 y,
448 y_offset;
449
cristy3ed852e2009-09-05 21:47:34 +0000450 /*
cristy7c6dc152011-02-11 14:10:55 +0000451 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000452 */
cristy4ca38e22011-02-10 02:57:49 +0000453 assert(images != (Image *) NULL);
454 assert(images->signature == MagickSignature);
455 if (images->debug != MagickFalse)
456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000457 assert(exception != (ExceptionInfo *) NULL);
458 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +0000459 image=images;
cristy3ed852e2009-09-05 21:47:34 +0000460 matte=image->matte;
461 number_images=1;
462 width=image->columns;
463 height=image->rows;
464 next=GetNextImageInList(image);
465 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
466 {
467 if (next->matte != MagickFalse)
468 matte=MagickTrue;
469 number_images++;
470 if (stack != MagickFalse)
471 {
472 if (next->columns > width)
473 width=next->columns;
474 height+=next->rows;
475 continue;
476 }
477 width+=next->columns;
478 if (next->rows > height)
479 height=next->rows;
480 }
481 /*
cristy7c6dc152011-02-11 14:10:55 +0000482 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000483 */
484 append_image=CloneImage(image,width,height,MagickTrue,exception);
485 if (append_image == (Image *) NULL)
486 return((Image *) NULL);
487 if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
488 {
489 InheritException(exception,&append_image->exception);
490 append_image=DestroyImage(append_image);
491 return((Image *) NULL);
492 }
493 append_image->matte=matte;
494 (void) SetImageBackgroundColor(append_image);
495 status=MagickTrue;
496 x_offset=0;
497 y_offset=0;
498 append_view=AcquireCacheView(append_image);
cristybb503372010-05-27 20:51:26 +0000499 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000500 {
501 SetGeometry(append_image,&geometry);
502 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
503 if (stack != MagickFalse)
504 x_offset-=geometry.x;
505 else
506 y_offset-=geometry.y;
507 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +0000508#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1a2bd532010-11-19 02:53:15 +0000509 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
cristy3ed852e2009-09-05 21:47:34 +0000510#endif
cristybb503372010-05-27 20:51:26 +0000511 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000512 {
513 MagickBooleanType
514 sync;
515
cristy4c08aed2011-07-01 19:47:50 +0000516 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000517 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000518
cristy4c08aed2011-07-01 19:47:50 +0000519 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000520 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000521
cristycb6d09b2010-06-19 01:59:36 +0000522 register ssize_t
523 x;
524
cristy3ed852e2009-09-05 21:47:34 +0000525 if (status == MagickFalse)
526 continue;
527 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
528 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
529 image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000530 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000531 {
532 status=MagickFalse;
533 continue;
534 }
cristybb503372010-05-27 20:51:26 +0000535 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000536 {
cristy4c08aed2011-07-01 19:47:50 +0000537 SetPixelRed(append_image,GetPixelRed(image,p),q);
538 SetPixelGreen(append_image,GetPixelGreen(image,p),q);
539 SetPixelBlue(append_image,GetPixelBlue(image,p),q);
cristyff775322011-02-24 15:05:25 +0000540 if ((image->colorspace == CMYKColorspace) &&
541 (append_image->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +0000542 SetPixelBlack(append_image,GetPixelBlack(image,p),q);
543 SetPixelAlpha(append_image,OpaqueAlpha,q);
544 if (image->matte != MagickFalse)
545 SetPixelAlpha(append_image,GetPixelAlpha(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +0000546 p+=GetPixelComponents(image);
547 q+=GetPixelComponents(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000548 }
549 sync=SyncCacheViewAuthenticPixels(append_view,exception);
550 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000551 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000552 }
553 image_view=DestroyCacheView(image_view);
554 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
555 if (proceed == MagickFalse)
556 break;
557 if (stack == MagickFalse)
558 {
cristyeaedf062010-05-29 22:36:02 +0000559 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000560 y_offset=0;
561 }
562 else
563 {
564 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000565 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000566 }
567 image=GetNextImageInList(image);
568 }
569 append_view=DestroyCacheView(append_view);
570 if (status == MagickFalse)
571 append_image=DestroyImage(append_image);
572 return(append_image);
573}
574
575/*
576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577% %
578% %
579% %
cristy3ed852e2009-09-05 21:47:34 +0000580% C a t c h I m a g e E x c e p t i o n %
581% %
582% %
583% %
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585%
586% CatchImageException() returns if no exceptions are found in the image
587% sequence, otherwise it determines the most severe exception and reports
588% it as a warning or error depending on the severity.
589%
590% The format of the CatchImageException method is:
591%
592% ExceptionType CatchImageException(Image *image)
593%
594% A description of each parameter follows:
595%
596% o image: An image sequence.
597%
598*/
599MagickExport ExceptionType CatchImageException(Image *image)
600{
601 ExceptionInfo
602 *exception;
603
604 ExceptionType
605 severity;
606
607 assert(image != (const Image *) NULL);
608 assert(image->signature == MagickSignature);
609 if (image->debug != MagickFalse)
610 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
611 exception=AcquireExceptionInfo();
612 GetImageException(image,exception);
613 CatchException(exception);
614 severity=exception->severity;
615 exception=DestroyExceptionInfo(exception);
616 return(severity);
617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
624% C l i p I m a g e P a t h %
625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629%
630% ClipImagePath() sets the image clip mask based any clipping path information
631% if it exists.
632%
633% The format of the ClipImagePath method is:
634%
635% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
636% const MagickBooleanType inside)
637%
638% A description of each parameter follows:
639%
640% o image: the image.
641%
642% o pathname: name of clipping path resource. If name is preceded by #, use
643% clipping path numbered by name.
644%
645% o inside: if non-zero, later operations take effect inside clipping path.
646% Otherwise later operations take effect outside clipping path.
647%
648*/
649
650MagickExport MagickBooleanType ClipImage(Image *image)
651{
652 return(ClipImagePath(image,"#1",MagickTrue));
653}
654
655MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
656 const MagickBooleanType inside)
657{
658#define ClipImagePathTag "ClipPath/Image"
659
660 char
661 *property;
662
663 const char
664 *value;
665
666 Image
667 *clip_mask;
668
669 ImageInfo
670 *image_info;
671
672 assert(image != (const Image *) NULL);
673 assert(image->signature == MagickSignature);
674 if (image->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
676 assert(pathname != NULL);
677 property=AcquireString(pathname);
cristyb51dff52011-05-19 16:55:47 +0000678 (void) FormatLocaleString(property,MaxTextExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000679 pathname);
680 value=GetImageProperty(image,property);
681 property=DestroyString(property);
682 if (value == (const char *) NULL)
683 {
684 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
685 image->filename);
686 return(MagickFalse);
687 }
688 image_info=AcquireImageInfo();
689 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
690 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
691 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
692 image_info=DestroyImageInfo(image_info);
693 if (clip_mask == (Image *) NULL)
694 return(MagickFalse);
695 if (clip_mask->storage_class == PseudoClass)
696 {
697 (void) SyncImage(clip_mask);
698 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
699 return(MagickFalse);
700 }
701 if (inside == MagickFalse)
702 (void) NegateImage(clip_mask,MagickFalse);
cristyb51dff52011-05-19 16:55:47 +0000703 (void) FormatLocaleString(clip_mask->magick_filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +0000704 "8BIM:1999,2998:%s\nPS",pathname);
705 (void) SetImageClipMask(image,clip_mask);
706 clip_mask=DestroyImage(clip_mask);
707 return(MagickTrue);
708}
709
710/*
711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712% %
713% %
714% %
715% C l o n e I m a g e %
716% %
717% %
718% %
719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720%
721% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000722%
cristy3ed852e2009-09-05 21:47:34 +0000723% If the specified columns and rows is 0, an exact copy of the image is
724% returned, otherwise the pixel data is undefined and must be initialized
725% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
726% failure, a NULL image is returned and exception describes the reason for the
727% failure.
728%
729% The format of the CloneImage method is:
730%
cristybb503372010-05-27 20:51:26 +0000731% Image *CloneImage(const Image *image,const size_t columns,
732% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000733% ExceptionInfo *exception)
734%
735% A description of each parameter follows:
736%
737% o image: the image.
738%
739% o columns: the number of columns in the cloned image.
740%
741% o rows: the number of rows in the cloned image.
742%
743% o detach: With a value other than 0, the cloned image is detached from
744% its parent I/O stream.
745%
746% o exception: return any errors or warnings in this structure.
747%
748*/
cristybb503372010-05-27 20:51:26 +0000749MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000750 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000751{
752 Image
753 *clone_image;
754
755 MagickRealType
756 scale;
757
758 size_t
759 length;
760
761 /*
762 Clone the image.
763 */
764 assert(image != (const Image *) NULL);
765 assert(image->signature == MagickSignature);
766 if (image->debug != MagickFalse)
767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
768 assert(exception != (ExceptionInfo *) NULL);
769 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000770 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000771 if (clone_image == (Image *) NULL)
772 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
773 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
774 clone_image->signature=MagickSignature;
775 clone_image->storage_class=image->storage_class;
cristydcfc1ad2011-07-07 16:25:41 +0000776 clone_image->pixel_components=image->pixel_components;
cristy4c08aed2011-07-01 19:47:50 +0000777 clone_image->metacontent_extent=image->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +0000778 clone_image->colorspace=image->colorspace;
779 clone_image->matte=image->matte;
780 clone_image->columns=image->columns;
781 clone_image->rows=image->rows;
782 clone_image->dither=image->dither;
783 if (image->colormap != (PixelPacket *) NULL)
784 {
785 /*
786 Allocate and copy the image colormap.
787 */
788 clone_image->colors=image->colors;
789 length=(size_t) image->colors;
790 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
791 sizeof(*clone_image->colormap));
792 if (clone_image->colormap == (PixelPacket *) NULL)
793 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
794 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
795 sizeof(*clone_image->colormap));
796 }
797 (void) CloneImageProfiles(clone_image,image);
798 (void) CloneImageProperties(clone_image,image);
799 (void) CloneImageArtifacts(clone_image,image);
800 GetTimerInfo(&clone_image->timer);
801 GetExceptionInfo(&clone_image->exception);
802 InheritException(&clone_image->exception,&image->exception);
803 if (image->ascii85 != (void *) NULL)
804 Ascii85Initialize(clone_image);
805 clone_image->magick_columns=image->magick_columns;
806 clone_image->magick_rows=image->magick_rows;
807 clone_image->type=image->type;
cristy5e0890f2011-07-07 23:30:35 +0000808 clone_image->map=image->map;
cristy4c08aed2011-07-01 19:47:50 +0000809 clone_image->component_map=ClonePixelComponentMap(image->component_map);
cristy3ed852e2009-09-05 21:47:34 +0000810 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
811 MaxTextExtent);
812 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
813 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
814 clone_image->progress_monitor=image->progress_monitor;
815 clone_image->client_data=image->client_data;
816 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000817 clone_image->next=image->next;
818 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000819 clone_image->list=NewImageList();
820 clone_image->clip_mask=NewImageList();
821 clone_image->mask=NewImageList();
822 if (detach == MagickFalse)
823 clone_image->blob=ReferenceBlob(image->blob);
824 else
cristybee00932011-01-15 20:28:27 +0000825 {
826 clone_image->next=NewImageList();
827 clone_image->previous=NewImageList();
828 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
829 }
cristy73724512010-04-12 14:43:14 +0000830 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000831 clone_image->debug=IsEventLogging();
832 clone_image->semaphore=AllocateSemaphoreInfo();
833 if ((columns == 0) && (rows == 0))
834 {
835 if (image->montage != (char *) NULL)
836 (void) CloneString(&clone_image->montage,image->montage);
837 if (image->directory != (char *) NULL)
838 (void) CloneString(&clone_image->directory,image->directory);
839 if (image->clip_mask != (Image *) NULL)
840 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
841 exception);
842 if (image->mask != (Image *) NULL)
843 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
844 clone_image->cache=ReferencePixelCache(image->cache);
845 return(clone_image);
846 }
cristy1ab35fb2011-04-15 01:25:56 +0000847 if ((columns == image->columns) && (rows == image->rows))
848 {
849 if (image->clip_mask != (Image *) NULL)
850 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
851 exception);
852 if (image->mask != (Image *) NULL)
853 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
854 }
cristy3ed852e2009-09-05 21:47:34 +0000855 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000856 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
857 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
858 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000859 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000860 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
861 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
862 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000863 clone_image->columns=columns;
864 clone_image->rows=rows;
865 clone_image->cache=ClonePixelCache(image->cache);
866 return(clone_image);
867}
868
869/*
870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871% %
872% %
873% %
874% C l o n e I m a g e I n f o %
875% %
876% %
877% %
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879%
880% CloneImageInfo() makes a copy of the given image info structure. If
881% NULL is specified, a new image info structure is created initialized to
882% default values.
883%
884% The format of the CloneImageInfo method is:
885%
886% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
887%
888% A description of each parameter follows:
889%
890% o image_info: the image info.
891%
892*/
893MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
894{
895 ImageInfo
896 *clone_info;
897
898 clone_info=AcquireImageInfo();
899 if (image_info == (ImageInfo *) NULL)
900 return(clone_info);
901 clone_info->compression=image_info->compression;
902 clone_info->temporary=image_info->temporary;
903 clone_info->adjoin=image_info->adjoin;
904 clone_info->antialias=image_info->antialias;
905 clone_info->scene=image_info->scene;
906 clone_info->number_scenes=image_info->number_scenes;
907 clone_info->depth=image_info->depth;
908 if (image_info->size != (char *) NULL)
909 (void) CloneString(&clone_info->size,image_info->size);
910 if (image_info->extract != (char *) NULL)
911 (void) CloneString(&clone_info->extract,image_info->extract);
912 if (image_info->scenes != (char *) NULL)
913 (void) CloneString(&clone_info->scenes,image_info->scenes);
914 if (image_info->page != (char *) NULL)
915 (void) CloneString(&clone_info->page,image_info->page);
916 clone_info->interlace=image_info->interlace;
917 clone_info->endian=image_info->endian;
918 clone_info->units=image_info->units;
919 clone_info->quality=image_info->quality;
920 if (image_info->sampling_factor != (char *) NULL)
921 (void) CloneString(&clone_info->sampling_factor,
922 image_info->sampling_factor);
923 if (image_info->server_name != (char *) NULL)
924 (void) CloneString(&clone_info->server_name,image_info->server_name);
925 if (image_info->font != (char *) NULL)
926 (void) CloneString(&clone_info->font,image_info->font);
927 if (image_info->texture != (char *) NULL)
928 (void) CloneString(&clone_info->texture,image_info->texture);
929 if (image_info->density != (char *) NULL)
930 (void) CloneString(&clone_info->density,image_info->density);
931 clone_info->pointsize=image_info->pointsize;
932 clone_info->fuzz=image_info->fuzz;
cristy3ed852e2009-09-05 21:47:34 +0000933 clone_info->background_color=image_info->background_color;
934 clone_info->border_color=image_info->border_color;
935 clone_info->matte_color=image_info->matte_color;
936 clone_info->transparent_color=image_info->transparent_color;
937 clone_info->dither=image_info->dither;
938 clone_info->monochrome=image_info->monochrome;
939 clone_info->colors=image_info->colors;
940 clone_info->colorspace=image_info->colorspace;
941 clone_info->type=image_info->type;
942 clone_info->orientation=image_info->orientation;
943 clone_info->preview_type=image_info->preview_type;
944 clone_info->group=image_info->group;
945 clone_info->ping=image_info->ping;
946 clone_info->verbose=image_info->verbose;
947 if (image_info->view != (char *) NULL)
948 (void) CloneString(&clone_info->view,image_info->view);
949 if (image_info->authenticate != (char *) NULL)
950 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
951 (void) CloneImageOptions(clone_info,image_info);
952 clone_info->progress_monitor=image_info->progress_monitor;
953 clone_info->client_data=image_info->client_data;
954 clone_info->cache=image_info->cache;
955 if (image_info->cache != (void *) NULL)
956 clone_info->cache=ReferencePixelCache(image_info->cache);
957 if (image_info->profile != (void *) NULL)
958 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
959 image_info->profile);
960 SetImageInfoFile(clone_info,image_info->file);
961 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
962 clone_info->stream=image_info->stream;
963 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
964 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
965 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
966 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
967 (void) CopyMagickString(clone_info->filename,image_info->filename,
968 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000969 clone_info->channel=image_info->channel;
970 clone_info->debug=IsEventLogging();
971 clone_info->signature=image_info->signature;
972 return(clone_info);
973}
974
975/*
976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
977% %
978% %
979% %
980% C o m b i n e I m a g e s %
981% %
982% %
983% %
984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985%
986% CombineImages() combines one or more images into a single image. The
987% grayscale value of the pixels of each image in the sequence is assigned in
988% order to the specified channels of the combined image. The typical
989% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
990%
991% The format of the CombineImages method is:
992%
993% Image *CombineImages(const Image *image,const ChannelType channel,
994% ExceptionInfo *exception)
995%
996% A description of each parameter follows:
997%
998% o image: the image.
999%
1000% o exception: return any errors or warnings in this structure.
1001%
1002*/
1003MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1004 ExceptionInfo *exception)
1005{
1006#define CombineImageTag "Combine/Image"
1007
1008 CacheView
1009 *combine_view;
1010
1011 const Image
1012 *next;
1013
1014 Image
1015 *combine_image;
1016
cristy3ed852e2009-09-05 21:47:34 +00001017 MagickBooleanType
1018 status;
1019
cristybb503372010-05-27 20:51:26 +00001020 MagickOffsetType
1021 progress;
1022
1023 ssize_t
1024 y;
1025
cristy3ed852e2009-09-05 21:47:34 +00001026 /*
1027 Ensure the image are the same size.
1028 */
1029 assert(image != (const Image *) NULL);
1030 assert(image->signature == MagickSignature);
1031 if (image->debug != MagickFalse)
1032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1033 assert(exception != (ExceptionInfo *) NULL);
1034 assert(exception->signature == MagickSignature);
1035 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1036 {
1037 if ((next->columns != image->columns) || (next->rows != image->rows))
1038 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1039 }
1040 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1041 if (combine_image == (Image *) NULL)
1042 return((Image *) NULL);
1043 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1044 {
1045 InheritException(exception,&combine_image->exception);
1046 combine_image=DestroyImage(combine_image);
1047 return((Image *) NULL);
1048 }
cristy2b9582a2011-07-04 17:38:56 +00001049 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001050 combine_image->matte=MagickTrue;
1051 (void) SetImageBackgroundColor(combine_image);
1052 /*
1053 Combine images.
1054 */
1055 status=MagickTrue;
1056 progress=0;
1057 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001058 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001059 {
1060 CacheView
1061 *image_view;
1062
1063 const Image
1064 *next;
1065
cristy4c08aed2011-07-01 19:47:50 +00001066 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001067 *pixels;
1068
cristy4c08aed2011-07-01 19:47:50 +00001069 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001070 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001071
cristy4c08aed2011-07-01 19:47:50 +00001072 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001073 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001074
cristycb6d09b2010-06-19 01:59:36 +00001075 register ssize_t
1076 x;
1077
cristy3ed852e2009-09-05 21:47:34 +00001078 if (status == MagickFalse)
1079 continue;
1080 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1081 1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001082 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001083 {
1084 status=MagickFalse;
1085 continue;
1086 }
1087 next=image;
cristy2b9582a2011-07-04 17:38:56 +00001088 if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
1089 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001090 {
1091 image_view=AcquireCacheView(next);
1092 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001093 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001094 continue;
1095 q=pixels;
cristybb503372010-05-27 20:51:26 +00001096 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001097 {
cristy4c08aed2011-07-01 19:47:50 +00001098 SetPixelRed(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001099 p+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00001100 q++;
1101 }
1102 image_view=DestroyCacheView(image_view);
1103 next=GetNextImageInList(next);
1104 }
cristy2b9582a2011-07-04 17:38:56 +00001105 if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
1106 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001107 {
1108 image_view=AcquireCacheView(next);
1109 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001110 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001111 continue;
1112 q=pixels;
cristybb503372010-05-27 20:51:26 +00001113 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
cristy4c08aed2011-07-01 19:47:50 +00001115 SetPixelGreen(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001116 p+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00001117 q++;
1118 }
1119 image_view=DestroyCacheView(image_view);
1120 next=GetNextImageInList(next);
1121 }
cristy2b9582a2011-07-04 17:38:56 +00001122 if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
1123 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001124 {
1125 image_view=AcquireCacheView(next);
1126 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001127 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001128 continue;
1129 q=pixels;
cristybb503372010-05-27 20:51:26 +00001130 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001131 {
cristy4c08aed2011-07-01 19:47:50 +00001132 SetPixelBlue(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001133 p+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00001134 q++;
1135 }
1136 image_view=DestroyCacheView(image_view);
1137 next=GetNextImageInList(next);
1138 }
cristy2b9582a2011-07-04 17:38:56 +00001139 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +00001140 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1141 {
cristy3ed852e2009-09-05 21:47:34 +00001142 image_view=AcquireCacheView(next);
1143 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001144 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001145 continue;
cristy4c08aed2011-07-01 19:47:50 +00001146 q=pixels;
cristybb503372010-05-27 20:51:26 +00001147 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001148 {
cristy4c08aed2011-07-01 19:47:50 +00001149 SetPixelBlack(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001150 p+=GetPixelComponents(image);
cristy4c08aed2011-07-01 19:47:50 +00001151 q++;
1152 }
1153 image_view=DestroyCacheView(image_view);
1154 next=GetNextImageInList(next);
1155 }
cristy2b9582a2011-07-04 17:38:56 +00001156 if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
1157 (next != (Image *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00001158 {
1159 image_view=AcquireCacheView(next);
1160 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1161 if (p == (const Quantum *) NULL)
1162 continue;
1163 q=pixels;
1164 for (x=0; x < (ssize_t) combine_image->columns; x++)
1165 {
1166 SetPixelAlpha(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001167 p+=GetPixelComponents(image);
cristy4c08aed2011-07-01 19:47:50 +00001168 q++;
cristy3ed852e2009-09-05 21:47:34 +00001169 }
1170 image_view=DestroyCacheView(image_view);
1171 next=GetNextImageInList(next);
1172 }
1173 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1174 status=MagickFalse;
1175 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1176 {
1177 MagickBooleanType
1178 proceed;
1179
cristy3ed852e2009-09-05 21:47:34 +00001180 proceed=SetImageProgress(image,CombineImageTag,progress++,
1181 combine_image->rows);
1182 if (proceed == MagickFalse)
1183 status=MagickFalse;
1184 }
1185 }
1186 combine_view=DestroyCacheView(combine_view);
1187 if (status == MagickFalse)
1188 combine_image=DestroyImage(combine_image);
1189 return(combine_image);
1190}
1191
1192/*
1193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194% %
1195% %
1196% %
cristy3ed852e2009-09-05 21:47:34 +00001197% D e s t r o y I m a g e %
1198% %
1199% %
1200% %
1201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202%
1203% DestroyImage() dereferences an image, deallocating memory associated with
1204% the image if the reference count becomes zero.
1205%
1206% The format of the DestroyImage method is:
1207%
1208% Image *DestroyImage(Image *image)
1209%
1210% A description of each parameter follows:
1211%
1212% o image: the image.
1213%
1214*/
1215MagickExport Image *DestroyImage(Image *image)
1216{
1217 MagickBooleanType
1218 destroy;
1219
1220 /*
1221 Dereference image.
1222 */
1223 assert(image != (Image *) NULL);
1224 assert(image->signature == MagickSignature);
1225 if (image->debug != MagickFalse)
1226 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1227 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001228 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001229 image->reference_count--;
1230 if (image->reference_count == 0)
1231 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001232 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001233 if (destroy == MagickFalse)
1234 return((Image *) NULL);
1235 /*
1236 Destroy image.
1237 */
1238 DestroyImagePixels(image);
cristy4c08aed2011-07-01 19:47:50 +00001239 image->component_map=DestroyPixelComponentMap(image->component_map);
cristy3ed852e2009-09-05 21:47:34 +00001240 if (image->clip_mask != (Image *) NULL)
1241 image->clip_mask=DestroyImage(image->clip_mask);
1242 if (image->mask != (Image *) NULL)
1243 image->mask=DestroyImage(image->mask);
1244 if (image->montage != (char *) NULL)
1245 image->montage=DestroyString(image->montage);
1246 if (image->directory != (char *) NULL)
1247 image->directory=DestroyString(image->directory);
1248 if (image->colormap != (PixelPacket *) NULL)
1249 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1250 if (image->geometry != (char *) NULL)
1251 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001252 DestroyImageProfiles(image);
1253 DestroyImageProperties(image);
1254 DestroyImageArtifacts(image);
1255 if (image->ascii85 != (Ascii85Info*) NULL)
1256 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1257 DestroyBlob(image);
1258 (void) DestroyExceptionInfo(&image->exception);
1259 if (image->semaphore != (SemaphoreInfo *) NULL)
1260 DestroySemaphoreInfo(&image->semaphore);
1261 image->signature=(~MagickSignature);
1262 image=(Image *) RelinquishMagickMemory(image);
1263 return(image);
1264}
1265
1266/*
1267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268% %
1269% %
1270% %
1271% D e s t r o y I m a g e I n f o %
1272% %
1273% %
1274% %
1275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1276%
1277% DestroyImageInfo() deallocates memory associated with an ImageInfo
1278% structure.
1279%
1280% The format of the DestroyImageInfo method is:
1281%
1282% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1283%
1284% A description of each parameter follows:
1285%
1286% o image_info: the image info.
1287%
1288*/
1289MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1290{
1291 assert(image_info != (ImageInfo *) NULL);
1292 assert(image_info->signature == MagickSignature);
1293 if (image_info->debug != MagickFalse)
1294 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1295 image_info->filename);
1296 if (image_info->size != (char *) NULL)
1297 image_info->size=DestroyString(image_info->size);
1298 if (image_info->extract != (char *) NULL)
1299 image_info->extract=DestroyString(image_info->extract);
1300 if (image_info->scenes != (char *) NULL)
1301 image_info->scenes=DestroyString(image_info->scenes);
1302 if (image_info->page != (char *) NULL)
1303 image_info->page=DestroyString(image_info->page);
1304 if (image_info->sampling_factor != (char *) NULL)
1305 image_info->sampling_factor=DestroyString(
1306 image_info->sampling_factor);
1307 if (image_info->server_name != (char *) NULL)
1308 image_info->server_name=DestroyString(
1309 image_info->server_name);
1310 if (image_info->font != (char *) NULL)
1311 image_info->font=DestroyString(image_info->font);
1312 if (image_info->texture != (char *) NULL)
1313 image_info->texture=DestroyString(image_info->texture);
1314 if (image_info->density != (char *) NULL)
1315 image_info->density=DestroyString(image_info->density);
1316 if (image_info->view != (char *) NULL)
1317 image_info->view=DestroyString(image_info->view);
1318 if (image_info->authenticate != (char *) NULL)
1319 image_info->authenticate=DestroyString(
1320 image_info->authenticate);
1321 DestroyImageOptions(image_info);
1322 if (image_info->cache != (void *) NULL)
1323 image_info->cache=DestroyPixelCache(image_info->cache);
1324 if (image_info->profile != (StringInfo *) NULL)
1325 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1326 image_info->profile);
1327 image_info->signature=(~MagickSignature);
1328 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1329 return(image_info);
1330}
1331
1332/*
1333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334% %
1335% %
1336% %
1337+ D i s a s s o c i a t e I m a g e S t r e a m %
1338% %
1339% %
1340% %
1341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342%
1343% DisassociateImageStream() disassociates the image stream.
1344%
1345% The format of the DisassociateImageStream method is:
1346%
1347% MagickBooleanType DisassociateImageStream(const Image *image)
1348%
1349% A description of each parameter follows:
1350%
1351% o image: the image.
1352%
1353*/
1354MagickExport void DisassociateImageStream(Image *image)
1355{
1356 assert(image != (const Image *) NULL);
1357 assert(image->signature == MagickSignature);
1358 if (image->debug != MagickFalse)
1359 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1360 (void) DetachBlob(image->blob);
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
1368% G e t I m a g e A l p h a C h a n n e l %
1369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
1374% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1375% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1376% than CMYKA.
1377%
1378% The format of the GetImageAlphaChannel method is:
1379%
1380% MagickBooleanType GetImageAlphaChannel(const Image *image)
1381%
1382% A description of each parameter follows:
1383%
1384% o image: the image.
1385%
1386*/
1387MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1388{
1389 assert(image != (const Image *) NULL);
1390 if (image->debug != MagickFalse)
1391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1392 assert(image->signature == MagickSignature);
1393 return(image->matte);
1394}
1395
1396/*
1397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398% %
1399% %
1400% %
1401% G e t I m a g e C l i p M a s k %
1402% %
1403% %
1404% %
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406%
1407% GetImageClipMask() returns the clip path associated with the image.
1408%
1409% The format of the GetImageClipMask method is:
1410%
1411% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1412%
1413% A description of each parameter follows:
1414%
1415% o image: the image.
1416%
1417*/
1418MagickExport Image *GetImageClipMask(const Image *image,
1419 ExceptionInfo *exception)
1420{
1421 assert(image != (const Image *) NULL);
1422 if (image->debug != MagickFalse)
1423 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1424 assert(image->signature == MagickSignature);
1425 if (image->clip_mask == (Image *) NULL)
1426 return((Image *) NULL);
1427 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1428}
1429
1430/*
1431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432% %
1433% %
1434% %
1435% G e t I m a g e E x c e p t i o n %
1436% %
1437% %
1438% %
1439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440%
1441% GetImageException() traverses an image sequence and returns any
1442% error more severe than noted by the exception parameter.
1443%
1444% The format of the GetImageException method is:
1445%
1446% void GetImageException(Image *image,ExceptionInfo *exception)
1447%
1448% A description of each parameter follows:
1449%
1450% o image: Specifies a pointer to a list of one or more images.
1451%
1452% o exception: return the highest severity exception.
1453%
1454*/
1455MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1456{
1457 register Image
1458 *next;
1459
1460 assert(image != (Image *) NULL);
1461 assert(image->signature == MagickSignature);
1462 if (image->debug != MagickFalse)
1463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1464 assert(exception != (ExceptionInfo *) NULL);
1465 assert(exception->signature == MagickSignature);
1466 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1467 {
1468 if (next->exception.severity == UndefinedException)
1469 continue;
1470 if (next->exception.severity > exception->severity)
1471 InheritException(exception,&next->exception);
1472 next->exception.severity=UndefinedException;
1473 }
1474}
1475
1476/*
1477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478% %
1479% %
1480% %
1481% G e t I m a g e I n f o %
1482% %
1483% %
1484% %
1485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486%
1487% GetImageInfo() initializes image_info to default values.
1488%
1489% The format of the GetImageInfo method is:
1490%
1491% void GetImageInfo(ImageInfo *image_info)
1492%
1493% A description of each parameter follows:
1494%
1495% o image_info: the image info.
1496%
1497*/
1498MagickExport void GetImageInfo(ImageInfo *image_info)
1499{
cristyd9a29192010-10-16 16:49:53 +00001500 const char
1501 *synchronize;
1502
cristy3ed852e2009-09-05 21:47:34 +00001503 ExceptionInfo
1504 *exception;
1505
1506 /*
1507 File and image dimension members.
1508 */
1509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1510 assert(image_info != (ImageInfo *) NULL);
1511 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1512 image_info->adjoin=MagickTrue;
1513 image_info->interlace=NoInterlace;
1514 image_info->channel=DefaultChannels;
1515 image_info->quality=UndefinedCompressionQuality;
1516 image_info->antialias=MagickTrue;
1517 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001518 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1519 if (synchronize != (const char *) NULL)
1520 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001521 exception=AcquireExceptionInfo();
1522 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1523 exception);
1524 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1525 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1526 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1527 exception);
1528 exception=DestroyExceptionInfo(exception);
1529 image_info->debug=IsEventLogging();
1530 image_info->signature=MagickSignature;
1531}
1532
1533/*
1534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535% %
1536% %
1537% %
cristy15781e52009-12-05 23:05:27 +00001538% G e t I m a g e I n f o F i l e %
1539% %
1540% %
1541% %
1542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543%
1544% GetImageInfoFile() returns the image info file member.
1545%
1546% The format of the GetImageInfoFile method is:
1547%
1548% FILE *GetImageInfoFile(const ImageInfo *image_info)
1549%
1550% A description of each parameter follows:
1551%
1552% o image_info: the image info.
1553%
1554*/
1555MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1556{
1557 return(image_info->file);
1558}
1559
1560/*
1561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562% %
1563% %
1564% %
cristy3ed852e2009-09-05 21:47:34 +00001565% G e t I m a g e M a s k %
1566% %
1567% %
1568% %
1569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1570%
1571% GetImageMask() returns the mask associated with the image.
1572%
1573% The format of the GetImageMask method is:
1574%
1575% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1576%
1577% A description of each parameter follows:
1578%
1579% o image: the image.
1580%
1581*/
1582MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1583{
1584 assert(image != (const Image *) NULL);
1585 if (image->debug != MagickFalse)
1586 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1587 assert(image->signature == MagickSignature);
1588 if (image->mask == (Image *) NULL)
1589 return((Image *) NULL);
1590 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1591}
1592
1593/*
1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595% %
1596% %
1597% %
1598+ G e t I m a g e R e f e r e n c e C o u n t %
1599% %
1600% %
1601% %
1602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1603%
1604% GetImageReferenceCount() returns the image reference count.
1605%
1606% The format of the GetReferenceCount method is:
1607%
cristybb503372010-05-27 20:51:26 +00001608% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001609%
1610% A description of each parameter follows:
1611%
1612% o image: the image.
1613%
1614*/
cristybb503372010-05-27 20:51:26 +00001615MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001616{
cristybb503372010-05-27 20:51:26 +00001617 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001618 reference_count;
1619
1620 assert(image != (Image *) NULL);
1621 assert(image->signature == MagickSignature);
1622 if (image->debug != MagickFalse)
1623 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001624 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001625 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001626 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001627 return(reference_count);
1628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
cristy3ed852e2009-09-05 21:47:34 +00001635% 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 %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1642% image. A virtual pixel is any pixel access that is outside the boundaries
1643% of the image cache.
1644%
1645% The format of the GetImageVirtualPixelMethod() method is:
1646%
1647% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1648%
1649% A description of each parameter follows:
1650%
1651% o image: the image.
1652%
1653*/
1654MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1655{
1656 assert(image != (Image *) NULL);
1657 assert(image->signature == MagickSignature);
1658 if (image->debug != MagickFalse)
1659 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1660 return(GetPixelCacheVirtualMethod(image));
1661}
1662
1663/*
1664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1665% %
1666% %
1667% %
1668% I n t e r p r e t I m a g e F i l e n a m e %
1669% %
1670% %
1671% %
1672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673%
1674% InterpretImageFilename() interprets embedded characters in an image filename.
1675% The filename length is returned.
1676%
1677% The format of the InterpretImageFilename method is:
1678%
1679% size_t InterpretImageFilename(const ImageInfo *image_info,
1680% Image *image,const char *format,int value,char *filename)
1681%
1682% A description of each parameter follows.
1683%
1684% o image_info: the image info..
1685%
1686% o image: the image.
1687%
1688% o format: A filename describing the format to use to write the numeric
1689% argument. Only the first numeric format identifier is replaced.
1690%
1691% o value: Numeric value to substitute into format filename.
1692%
1693% o filename: return the formatted filename in this character buffer.
1694%
1695*/
1696MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1697 Image *image,const char *format,int value,char *filename)
1698{
1699 char
1700 *q;
1701
1702 int
1703 c;
1704
1705 MagickBooleanType
1706 canonical;
1707
1708 register const char
1709 *p;
1710
1711 canonical=MagickFalse;
1712 (void) CopyMagickString(filename,format,MaxTextExtent);
1713 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1714 {
1715 q=(char *) p+1;
1716 if (*q == '%')
1717 {
1718 p=q+1;
1719 continue;
1720 }
1721 if (*q == '0')
1722 {
cristybb503372010-05-27 20:51:26 +00001723 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001724 value;
1725
cristybb503372010-05-27 20:51:26 +00001726 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001727 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001728 }
1729 switch (*q)
1730 {
1731 case 'd':
1732 case 'o':
1733 case 'x':
1734 {
1735 q++;
1736 c=(*q);
1737 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001738 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001739 (p-format)),p,value);
1740 *q=c;
1741 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1742 canonical=MagickTrue;
1743 if (*(q-1) != '%')
1744 break;
1745 p++;
1746 break;
1747 }
1748 case '[':
1749 {
1750 char
1751 pattern[MaxTextExtent];
1752
1753 const char
1754 *value;
1755
cristy3ed852e2009-09-05 21:47:34 +00001756 register char
1757 *r;
1758
cristybb503372010-05-27 20:51:26 +00001759 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001760 i;
1761
cristycb6d09b2010-06-19 01:59:36 +00001762 ssize_t
1763 depth;
1764
cristy3ed852e2009-09-05 21:47:34 +00001765 /*
1766 Image option.
1767 */
1768 if (strchr(p,']') == (char *) NULL)
1769 break;
1770 depth=1;
1771 r=q+1;
1772 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1773 {
1774 if (*r == '[')
1775 depth++;
1776 if (*r == ']')
1777 depth--;
1778 if (depth <= 0)
1779 break;
1780 pattern[i]=(*r++);
1781 }
1782 pattern[i]='\0';
1783 if (LocaleNCompare(pattern,"filename:",9) != 0)
1784 break;
1785 value=(const char *) NULL;
1786 if ((image_info != (const ImageInfo *) NULL) &&
1787 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001788 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001789 else
1790 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001791 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001792 else
1793 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001794 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001795 if (value == (const char *) NULL)
1796 break;
1797 q--;
1798 c=(*q);
1799 *q='\0';
1800 (void) CopyMagickString(filename+(p-format),value,(size_t)
1801 (MaxTextExtent-(p-format)));
1802 *q=c;
1803 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1804 canonical=MagickTrue;
1805 if (*(q-1) != '%')
1806 break;
1807 p++;
1808 break;
1809 }
1810 default:
1811 break;
1812 }
1813 }
1814 for (q=filename; *q != '\0'; q++)
1815 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001816 {
1817 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1818 canonical=MagickTrue;
1819 }
cristy3ed852e2009-09-05 21:47:34 +00001820 if (canonical == MagickFalse)
1821 (void) CopyMagickString(filename,format,MaxTextExtent);
1822 return(strlen(filename));
1823}
1824
1825/*
1826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1827% %
1828% %
1829% %
1830% I s H i g h D y n a m i c R a n g e I m a g e %
1831% %
1832% %
1833% %
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835%
1836% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1837% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1838% 0..65535.
1839%
1840% The format of the IsHighDynamicRangeImage method is:
1841%
1842% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1843% ExceptionInfo *exception)
1844%
1845% A description of each parameter follows:
1846%
1847% o image: the image.
1848%
1849% o exception: return any errors or warnings in this structure.
1850%
1851*/
1852MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1853 ExceptionInfo *exception)
1854{
1855#if !defined(MAGICKCORE_HDRI_SUPPORT)
1856 (void) image;
1857 (void) exception;
1858 return(MagickFalse);
1859#else
1860 CacheView
1861 *image_view;
1862
cristy3ed852e2009-09-05 21:47:34 +00001863 MagickBooleanType
1864 status;
1865
cristy4c08aed2011-07-01 19:47:50 +00001866 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001867 zero;
1868
cristycb6d09b2010-06-19 01:59:36 +00001869 ssize_t
1870 y;
1871
cristy3ed852e2009-09-05 21:47:34 +00001872 assert(image != (Image *) NULL);
1873 assert(image->signature == MagickSignature);
1874 if (image->debug != MagickFalse)
1875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1876 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00001877 GetPixelInfo(image,&zero);
cristy3ed852e2009-09-05 21:47:34 +00001878 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001879#if defined(MAGICKCORE_OPENMP_SUPPORT)
1880 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001881#endif
cristybb503372010-05-27 20:51:26 +00001882 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001883 {
cristy4c08aed2011-07-01 19:47:50 +00001884 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001885 pixel;
1886
cristy4c08aed2011-07-01 19:47:50 +00001887 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001888 *p;
1889
cristybb503372010-05-27 20:51:26 +00001890 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001891 x;
1892
1893 if (status == MagickFalse)
1894 continue;
1895 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001896 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001897 {
1898 status=MagickFalse;
1899 continue;
1900 }
cristy3ed852e2009-09-05 21:47:34 +00001901 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001902 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001903 {
cristy4c08aed2011-07-01 19:47:50 +00001904 SetPixelInfo(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001905 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1906 (pixel.red != (QuantumAny) pixel.red))
1907 break;
1908 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1909 (pixel.green != (QuantumAny) pixel.green))
1910 break;
1911 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1912 (pixel.blue != (QuantumAny) pixel.blue))
1913 break;
cristy3ed852e2009-09-05 21:47:34 +00001914 if (pixel.colorspace == CMYKColorspace)
1915 {
cristy4c08aed2011-07-01 19:47:50 +00001916 if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
1917 (pixel.black != (QuantumAny) pixel.black))
cristy3ed852e2009-09-05 21:47:34 +00001918 break;
1919 }
cristy4c08aed2011-07-01 19:47:50 +00001920 if (pixel.matte != MagickFalse)
1921 {
1922 if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
1923 (pixel.alpha != (QuantumAny) pixel.alpha))
1924 break;
1925 }
cristydcfc1ad2011-07-07 16:25:41 +00001926 p+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00001927 }
cristybb503372010-05-27 20:51:26 +00001928 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001929 status=MagickFalse;
1930 }
1931 image_view=DestroyCacheView(image_view);
1932 return(status != MagickFalse ? MagickFalse : MagickTrue);
1933#endif
1934}
1935
1936/*
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938% %
1939% %
1940% %
1941% I s I m a g e O b j e c t %
1942% %
1943% %
1944% %
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946%
1947% IsImageObject() returns MagickTrue if the image sequence contains a valid
1948% set of image objects.
1949%
1950% The format of the IsImageObject method is:
1951%
1952% MagickBooleanType IsImageObject(const Image *image)
1953%
1954% A description of each parameter follows:
1955%
1956% o image: the image.
1957%
1958*/
1959MagickExport MagickBooleanType IsImageObject(const Image *image)
1960{
1961 register const Image
1962 *p;
1963
1964 assert(image != (Image *) NULL);
1965 if (image->debug != MagickFalse)
1966 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1967 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1968 if (p->signature != MagickSignature)
1969 return(MagickFalse);
1970 return(MagickTrue);
1971}
1972
1973/*
1974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975% %
1976% %
1977% %
1978% I s T a i n t I m a g e %
1979% %
1980% %
1981% %
1982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983%
1984% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1985% since it was first constituted.
1986%
1987% The format of the IsTaintImage method is:
1988%
1989% MagickBooleanType IsTaintImage(const Image *image)
1990%
1991% A description of each parameter follows:
1992%
1993% o image: the image.
1994%
1995*/
1996MagickExport MagickBooleanType IsTaintImage(const Image *image)
1997{
1998 char
1999 magick[MaxTextExtent],
2000 filename[MaxTextExtent];
2001
2002 register const Image
2003 *p;
2004
2005 assert(image != (Image *) NULL);
2006 if (image->debug != MagickFalse)
2007 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2008 assert(image->signature == MagickSignature);
2009 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2010 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2011 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2012 {
2013 if (p->taint != MagickFalse)
2014 return(MagickTrue);
2015 if (LocaleCompare(p->magick,magick) != 0)
2016 return(MagickTrue);
2017 if (LocaleCompare(p->filename,filename) != 0)
2018 return(MagickTrue);
2019 }
2020 return(MagickFalse);
2021}
2022
2023/*
2024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025% %
2026% %
2027% %
2028% M o d i f y I m a g e %
2029% %
2030% %
2031% %
2032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2033%
2034% ModifyImage() ensures that there is only a single reference to the image
2035% to be modified, updating the provided image pointer to point to a clone of
2036% the original image if necessary.
2037%
2038% The format of the ModifyImage method is:
2039%
2040% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2041%
2042% A description of each parameter follows:
2043%
2044% o image: the image.
2045%
2046% o exception: return any errors or warnings in this structure.
2047%
2048*/
2049MagickExport MagickBooleanType ModifyImage(Image **image,
2050 ExceptionInfo *exception)
2051{
2052 Image
2053 *clone_image;
2054
2055 assert(image != (Image **) NULL);
2056 assert(*image != (Image *) NULL);
2057 assert((*image)->signature == MagickSignature);
2058 if ((*image)->debug != MagickFalse)
2059 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2060 if (GetImageReferenceCount(*image) <= 1)
2061 return(MagickTrue);
2062 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002063 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002064 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002065 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002066 *image=clone_image;
2067 return(MagickTrue);
2068}
2069
2070/*
2071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072% %
2073% %
2074% %
2075% N e w M a g i c k I m a g e %
2076% %
2077% %
2078% %
2079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2080%
2081% NewMagickImage() creates a blank image canvas of the specified size and
2082% background color.
2083%
2084% The format of the NewMagickImage method is:
2085%
2086% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002087% const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002088% const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002089%
2090% A description of each parameter follows:
2091%
2092% o image: the image.
2093%
2094% o width: the image width.
2095%
2096% o height: the image height.
2097%
2098% o background: the image color.
2099%
2100*/
2101MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002102 const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002103 const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002104{
2105 CacheView
2106 *image_view;
2107
2108 ExceptionInfo
2109 *exception;
2110
2111 Image
2112 *image;
2113
cristybb503372010-05-27 20:51:26 +00002114 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002115 y;
2116
2117 MagickBooleanType
2118 status;
2119
2120 assert(image_info != (const ImageInfo *) NULL);
2121 if (image_info->debug != MagickFalse)
2122 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2123 assert(image_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002124 assert(background != (const PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002125 image=AcquireImage(image_info);
2126 image->columns=width;
2127 image->rows=height;
2128 image->colorspace=background->colorspace;
2129 image->matte=background->matte;
2130 image->fuzz=background->fuzz;
2131 image->depth=background->depth;
2132 status=MagickTrue;
2133 exception=(&image->exception);
2134 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002135#if defined(MAGICKCORE_OPENMP_SUPPORT)
2136 #pragma omp parallel for schedule(dynamic,4) shared(status)
2137#endif
cristybb503372010-05-27 20:51:26 +00002138 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002139 {
cristy4c08aed2011-07-01 19:47:50 +00002140 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002141 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002142
cristycb6d09b2010-06-19 01:59:36 +00002143 register ssize_t
2144 x;
2145
cristy48974b92009-12-19 02:36:06 +00002146 if (status == MagickFalse)
2147 continue;
cristy3ed852e2009-09-05 21:47:34 +00002148 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002149 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002150 {
2151 status=MagickFalse;
2152 continue;
2153 }
cristybb503372010-05-27 20:51:26 +00002154 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002155 {
cristy4c08aed2011-07-01 19:47:50 +00002156 SetPixelPixelInfo(image,background,q);
cristydcfc1ad2011-07-07 16:25:41 +00002157 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002158 }
2159 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2160 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002161 }
2162 image_view=DestroyCacheView(image_view);
2163 if (status == MagickFalse)
2164 image=DestroyImage(image);
2165 return(image);
2166}
2167
2168/*
2169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170% %
2171% %
2172% %
2173% R e f e r e n c e I m a g e %
2174% %
2175% %
2176% %
2177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2178%
2179% ReferenceImage() increments the reference count associated with an image
2180% returning a pointer to the image.
2181%
2182% The format of the ReferenceImage method is:
2183%
2184% Image *ReferenceImage(Image *image)
2185%
2186% A description of each parameter follows:
2187%
2188% o image: the image.
2189%
2190*/
2191MagickExport Image *ReferenceImage(Image *image)
2192{
2193 assert(image != (Image *) NULL);
2194 if (image->debug != MagickFalse)
2195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2196 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002197 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002198 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002199 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002200 return(image);
2201}
2202
2203/*
2204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205% %
2206% %
2207% %
2208% R e s e t I m a g e P a g e %
2209% %
2210% %
2211% %
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213%
2214% ResetImagePage() resets the image page canvas and position.
2215%
2216% The format of the ResetImagePage method is:
2217%
2218% MagickBooleanType ResetImagePage(Image *image,const char *page)
2219%
2220% A description of each parameter follows:
2221%
2222% o image: the image.
2223%
2224% o page: the relative page specification.
2225%
2226*/
2227MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2228{
2229 MagickStatusType
2230 flags;
2231
2232 RectangleInfo
2233 geometry;
2234
2235 assert(image != (Image *) NULL);
2236 assert(image->signature == MagickSignature);
2237 if (image->debug != MagickFalse)
2238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2239 flags=ParseAbsoluteGeometry(page,&geometry);
2240 if ((flags & WidthValue) != 0)
2241 {
2242 if ((flags & HeightValue) == 0)
2243 geometry.height=geometry.width;
2244 image->page.width=geometry.width;
2245 image->page.height=geometry.height;
2246 }
2247 if ((flags & AspectValue) != 0)
2248 {
2249 if ((flags & XValue) != 0)
2250 image->page.x+=geometry.x;
2251 if ((flags & YValue) != 0)
2252 image->page.y+=geometry.y;
2253 }
2254 else
2255 {
2256 if ((flags & XValue) != 0)
2257 {
2258 image->page.x=geometry.x;
2259 if ((image->page.width == 0) && (geometry.x > 0))
2260 image->page.width=image->columns+geometry.x;
2261 }
2262 if ((flags & YValue) != 0)
2263 {
2264 image->page.y=geometry.y;
2265 if ((image->page.height == 0) && (geometry.y > 0))
2266 image->page.height=image->rows+geometry.y;
2267 }
2268 }
2269 return(MagickTrue);
2270}
2271
2272/*
2273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274% %
2275% %
2276% %
2277% S e p a r a t e I m a g e C h a n n e l %
2278% %
2279% %
2280% %
2281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282%
2283% SeparateImageChannel() separates a channel from the image and returns it as
2284% a grayscale image. A channel is a particular color component of each pixel
2285% in the image.
2286%
2287% The format of the SeparateImageChannel method is:
2288%
2289% MagickBooleanType SeparateImageChannel(Image *image,
2290% const ChannelType channel)
2291%
2292% A description of each parameter follows:
2293%
2294% o image: the image.
2295%
2296% o channel: Identify which channel to extract: RedChannel, GreenChannel,
cristy4c08aed2011-07-01 19:47:50 +00002297% BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
cristy3ed852e2009-09-05 21:47:34 +00002298% YellowChannel, or BlackChannel.
2299%
2300*/
2301MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2302 const ChannelType channel)
2303{
2304#define SeparateImageTag "Separate/Image"
2305
2306 CacheView
2307 *image_view;
2308
2309 ExceptionInfo
2310 *exception;
2311
cristy3ed852e2009-09-05 21:47:34 +00002312 MagickBooleanType
2313 status;
2314
cristybb503372010-05-27 20:51:26 +00002315 MagickOffsetType
2316 progress;
2317
2318 ssize_t
2319 y;
2320
cristy3ed852e2009-09-05 21:47:34 +00002321 assert(image != (Image *) NULL);
2322 assert(image->signature == MagickSignature);
2323 if (image->debug != MagickFalse)
2324 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2325 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2326 return(MagickFalse);
2327 /*
2328 Separate image channels.
2329 */
2330 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002331 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002332 image->matte=MagickTrue;
2333 progress=0;
2334 exception=(&image->exception);
2335 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002336#if defined(MAGICKCORE_OPENMP_SUPPORT)
2337 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002338#endif
cristybb503372010-05-27 20:51:26 +00002339 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002340 {
cristy4c08aed2011-07-01 19:47:50 +00002341 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002342 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002343
cristycb6d09b2010-06-19 01:59:36 +00002344 register ssize_t
2345 x;
2346
cristy3ed852e2009-09-05 21:47:34 +00002347 if (status == MagickFalse)
2348 continue;
2349 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002350 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002351 {
2352 status=MagickFalse;
2353 continue;
2354 }
cristy3ed852e2009-09-05 21:47:34 +00002355 switch (channel)
2356 {
2357 case RedChannel:
2358 {
cristybb503372010-05-27 20:51:26 +00002359 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002360 {
cristy4c08aed2011-07-01 19:47:50 +00002361 SetPixelGreen(image,GetPixelRed(image,q),q);
2362 SetPixelBlue(image,GetPixelRed(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002363 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002364 }
2365 break;
2366 }
2367 case GreenChannel:
2368 {
cristybb503372010-05-27 20:51:26 +00002369 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002370 {
cristy4c08aed2011-07-01 19:47:50 +00002371 SetPixelRed(image,GetPixelGreen(image,q),q);
2372 SetPixelBlue(image,GetPixelGreen(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002373 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002374 }
2375 break;
2376 }
2377 case BlueChannel:
2378 {
cristybb503372010-05-27 20:51:26 +00002379 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002380 {
cristy4c08aed2011-07-01 19:47:50 +00002381 SetPixelRed(image,GetPixelBlue(image,q),q);
2382 SetPixelGreen(image,GetPixelBlue(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002383 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002384 }
2385 break;
2386 }
cristy4c08aed2011-07-01 19:47:50 +00002387 case AlphaChannel:
cristy3ed852e2009-09-05 21:47:34 +00002388 {
cristybb503372010-05-27 20:51:26 +00002389 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002390 {
cristy4c08aed2011-07-01 19:47:50 +00002391 SetPixelRed(image,GetPixelAlpha(image,q),q);
2392 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2393 SetPixelBlue(image,GetPixelAlpha(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002394 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002395 }
2396 break;
2397 }
2398 case BlackChannel:
2399 {
2400 if ((image->storage_class != PseudoClass) &&
2401 (image->colorspace != CMYKColorspace))
2402 break;
cristybb503372010-05-27 20:51:26 +00002403 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002404 {
cristy4c08aed2011-07-01 19:47:50 +00002405 SetPixelRed(image,GetPixelBlack(image,q),q);
2406 SetPixelGreen(image,GetPixelBlack(image,q),q);
2407 SetPixelBlue(image,GetPixelBlack(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002408 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002409 }
2410 break;
2411 }
2412 case TrueAlphaChannel:
2413 {
cristybb503372010-05-27 20:51:26 +00002414 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002415 {
cristy4c08aed2011-07-01 19:47:50 +00002416 SetPixelRed(image,GetPixelAlpha(image,q),q);
2417 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2418 SetPixelBlue(image,GetPixelAlpha(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002419 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002420 }
2421 break;
2422 }
2423 case GrayChannels:
2424 {
cristybb503372010-05-27 20:51:26 +00002425 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002426 {
cristy4c08aed2011-07-01 19:47:50 +00002427 SetPixelAlpha(image,GetPixelIntensity(image,q),q);
cristydcfc1ad2011-07-07 16:25:41 +00002428 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002429 }
2430 break;
2431 }
2432 default:
2433 break;
2434 }
2435 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2436 status=MagickFalse;
2437 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2438 {
2439 MagickBooleanType
2440 proceed;
2441
cristyb5d5f722009-11-04 03:03:49 +00002442#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002443 #pragma omp critical (MagickCore_SeparateImageChannel)
2444#endif
2445 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2446 if (proceed == MagickFalse)
2447 status=MagickFalse;
2448 }
2449 }
2450 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002451 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002452 image->matte=MagickFalse;
2453 (void) SetImageColorspace(image,RGBColorspace);
2454 return(status);
2455}
2456
2457/*
2458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459% %
2460% %
2461% %
2462% S e p a r a t e I m a g e s %
2463% %
2464% %
2465% %
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467%
2468% SeparateImages() returns a separate grayscale image for each channel
2469% specified.
2470%
2471% The format of the SeparateImages method is:
2472%
2473% MagickBooleanType SeparateImages(const Image *image,
2474% const ChannelType channel,ExceptionInfo *exception)
2475%
2476% A description of each parameter follows:
2477%
2478% o image: the image.
2479%
2480% o channel: Identify which channels to extract: RedChannel, GreenChannel,
cristy4c08aed2011-07-01 19:47:50 +00002481% BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
cristy3ed852e2009-09-05 21:47:34 +00002482% YellowChannel, or BlackChannel.
2483%
2484% o exception: return any errors or warnings in this structure.
2485%
2486*/
2487MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2488 ExceptionInfo *exception)
2489{
2490 Image
2491 *images,
2492 *separate_image;
2493
2494 assert(image != (Image *) NULL);
2495 assert(image->signature == MagickSignature);
2496 if (image->debug != MagickFalse)
2497 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2498 images=NewImageList();
cristy2b9582a2011-07-04 17:38:56 +00002499 if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002500 {
2501 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2502 (void) SeparateImageChannel(separate_image,RedChannel);
2503 AppendImageToList(&images,separate_image);
2504 }
cristy2b9582a2011-07-04 17:38:56 +00002505 if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002506 {
2507 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2508 (void) SeparateImageChannel(separate_image,GreenChannel);
2509 AppendImageToList(&images,separate_image);
2510 }
cristy2b9582a2011-07-04 17:38:56 +00002511 if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002512 {
2513 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2514 (void) SeparateImageChannel(separate_image,BlueChannel);
2515 AppendImageToList(&images,separate_image);
2516 }
cristy2b9582a2011-07-04 17:38:56 +00002517 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) && (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002518 {
2519 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2520 (void) SeparateImageChannel(separate_image,BlackChannel);
2521 AppendImageToList(&images,separate_image);
2522 }
cristy2b9582a2011-07-04 17:38:56 +00002523 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002524 {
2525 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy4c08aed2011-07-01 19:47:50 +00002526 (void) SeparateImageChannel(separate_image,AlphaChannel);
cristy3ed852e2009-09-05 21:47:34 +00002527 AppendImageToList(&images,separate_image);
2528 }
2529 return(images);
2530}
2531
2532/*
2533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2534% %
2535% %
2536% %
2537% S e t I m a g e A l p h a C h a n n e l %
2538% %
2539% %
2540% %
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542%
2543% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2544% channel.
2545%
2546% The format of the SetImageAlphaChannel method is:
2547%
2548% MagickBooleanType SetImageAlphaChannel(Image *image,
2549% const AlphaChannelType alpha_type)
2550%
2551% A description of each parameter follows:
2552%
2553% o image: the image.
2554%
2555% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2556% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
cristy4c08aed2011-07-01 19:47:50 +00002557% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
2558% TransparentAlphaChannel.
cristy3ed852e2009-09-05 21:47:34 +00002559%
2560*/
2561MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2562 const AlphaChannelType alpha_type)
2563{
2564 MagickBooleanType
2565 status;
2566
2567 assert(image != (Image *) NULL);
2568 if (image->debug != MagickFalse)
2569 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2570 assert(image->signature == MagickSignature);
2571 status=MagickFalse;
2572 switch (alpha_type)
2573 {
2574 case ActivateAlphaChannel:
2575 {
2576 image->matte=MagickTrue;
2577 break;
2578 }
2579 case BackgroundAlphaChannel:
2580 {
2581 CacheView
2582 *image_view;
2583
2584 ExceptionInfo
2585 *exception;
2586
cristy3ed852e2009-09-05 21:47:34 +00002587 MagickBooleanType
2588 status;
2589
cristy4c08aed2011-07-01 19:47:50 +00002590 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002591 background;
2592
2593 PixelPacket
2594 pixel;
2595
cristycb6d09b2010-06-19 01:59:36 +00002596 ssize_t
2597 y;
2598
cristy3ed852e2009-09-05 21:47:34 +00002599 /*
2600 Set transparent pixels to background color.
2601 */
2602 if (image->matte == MagickFalse)
2603 break;
2604 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2605 break;
cristy4c08aed2011-07-01 19:47:50 +00002606 GetPixelInfo(image,&background);
2607 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002608 if (image->colorspace == CMYKColorspace)
2609 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002610 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002611 status=MagickTrue;
2612 exception=(&image->exception);
2613 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002614 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2615 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002616 #endif
cristybb503372010-05-27 20:51:26 +00002617 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002618 {
cristy4c08aed2011-07-01 19:47:50 +00002619 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002620 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002621
cristycb6d09b2010-06-19 01:59:36 +00002622 register ssize_t
2623 x;
2624
cristy3ed852e2009-09-05 21:47:34 +00002625 if (status == MagickFalse)
2626 continue;
2627 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2628 exception);
cristy4c08aed2011-07-01 19:47:50 +00002629 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002630 {
2631 status=MagickFalse;
2632 continue;
2633 }
cristybb503372010-05-27 20:51:26 +00002634 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002635 {
cristy4c08aed2011-07-01 19:47:50 +00002636 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002637 {
cristy4c08aed2011-07-01 19:47:50 +00002638 SetPixelRed(image,pixel.red,q);
2639 SetPixelGreen(image,pixel.green,q);
2640 SetPixelBlue(image,pixel.blue,q);
2641 if (image->colorspace == CMYKColorspace)
2642 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002643 }
cristydcfc1ad2011-07-07 16:25:41 +00002644 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002645 }
cristy3ed852e2009-09-05 21:47:34 +00002646 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2647 status=MagickFalse;
2648 }
2649 image_view=DestroyCacheView(image_view);
2650 return(status);
2651 }
2652 case DeactivateAlphaChannel:
2653 {
2654 image->matte=MagickFalse;
2655 break;
2656 }
2657 case ShapeAlphaChannel:
2658 case CopyAlphaChannel:
2659 {
2660 /*
2661 Special usage case for SeparateImageChannel(): copy grayscale color to
2662 the alpha channel.
2663 */
2664 status=SeparateImageChannel(image,GrayChannels);
2665 image->matte=MagickTrue; /* make sure transparency is now on! */
2666 if (alpha_type == ShapeAlphaChannel)
2667 {
cristy4c08aed2011-07-01 19:47:50 +00002668 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002669 background;
2670
2671 /*
2672 Reset all color channels to background color.
2673 */
cristy4c08aed2011-07-01 19:47:50 +00002674 GetPixelInfo(image,&background);
2675 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002676 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002677 }
2678 break;
2679 }
2680 case ExtractAlphaChannel:
2681 {
2682 status=SeparateImageChannel(image,TrueAlphaChannel);
2683 image->matte=MagickFalse;
2684 break;
2685 }
cristy3ed852e2009-09-05 21:47:34 +00002686 case OpaqueAlphaChannel:
2687 {
cristy4c08aed2011-07-01 19:47:50 +00002688 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002689 image->matte=MagickTrue;
2690 break;
2691 }
2692 case TransparentAlphaChannel:
2693 {
cristy4c08aed2011-07-01 19:47:50 +00002694 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002695 image->matte=MagickTrue;
2696 break;
2697 }
2698 case SetAlphaChannel:
2699 {
2700 if (image->matte == MagickFalse)
2701 {
cristy4c08aed2011-07-01 19:47:50 +00002702 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002703 image->matte=MagickTrue;
2704 }
2705 break;
2706 }
2707 case UndefinedAlphaChannel:
2708 break;
2709 }
2710 return(status);
2711}
2712
2713/*
2714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715% %
2716% %
2717% %
2718% S e t I m a g e B a c k g r o u n d C o l o r %
2719% %
2720% %
2721% %
2722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723%
2724% SetImageBackgroundColor() initializes the image pixels to the image
2725% background color. The background color is defined by the background_color
2726% member of the image structure.
2727%
2728% The format of the SetImage method is:
2729%
2730% MagickBooleanType SetImageBackgroundColor(Image *image)
2731%
2732% A description of each parameter follows:
2733%
2734% o image: the image.
2735%
2736*/
2737MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2738{
2739 CacheView
2740 *image_view;
2741
2742 ExceptionInfo
2743 *exception;
2744
cristy3ed852e2009-09-05 21:47:34 +00002745 MagickBooleanType
2746 status;
2747
cristy4c08aed2011-07-01 19:47:50 +00002748 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002749 background;
2750
2751 PixelPacket
2752 pixel;
2753
cristycb6d09b2010-06-19 01:59:36 +00002754 ssize_t
2755 y;
2756
cristy3ed852e2009-09-05 21:47:34 +00002757 assert(image != (Image *) NULL);
2758 if (image->debug != MagickFalse)
2759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2760 assert(image->signature == MagickSignature);
2761 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2762 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002763 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002764 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002765 GetPixelInfo(image,&background);
2766 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002767 if (image->colorspace == CMYKColorspace)
2768 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002769 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002770 /*
2771 Set image background color.
2772 */
2773 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002774 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002775 exception=(&image->exception);
2776 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002777 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002778 {
cristy4c08aed2011-07-01 19:47:50 +00002779 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002780 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002781
cristycb6d09b2010-06-19 01:59:36 +00002782 register ssize_t
2783 x;
2784
cristy3ed852e2009-09-05 21:47:34 +00002785 if (status == MagickFalse)
2786 continue;
2787 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002788 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002789 {
2790 status=MagickFalse;
2791 continue;
2792 }
cristybb503372010-05-27 20:51:26 +00002793 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002794 {
2795 SetPixelPacket(image,&pixel,q);
2796 if (image->colorspace == CMYKColorspace)
2797 SetPixelBlack(image,pixel.black,q);
cristydcfc1ad2011-07-07 16:25:41 +00002798 q+=GetPixelComponents(image);
cristy4c08aed2011-07-01 19:47:50 +00002799 }
cristy3ed852e2009-09-05 21:47:34 +00002800 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2801 status=MagickFalse;
2802 }
2803 image_view=DestroyCacheView(image_view);
2804 return(status);
2805}
2806
2807/*
2808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809% %
2810% %
2811% %
cristya5b77cb2010-05-07 19:34:48 +00002812% S e t I m a g e C o l o r %
2813% %
2814% %
2815% %
2816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2817%
2818% SetImageColor() set the entire image canvas to the specified color.
2819%
2820% The format of the SetImageColor method is:
2821%
2822% MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002823% const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002824%
2825% A description of each parameter follows:
2826%
2827% o image: the image.
2828%
2829% o background: the image color.
2830%
2831*/
2832MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002833 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002834{
2835 CacheView
2836 *image_view;
2837
2838 ExceptionInfo
2839 *exception;
2840
cristya5b77cb2010-05-07 19:34:48 +00002841 MagickBooleanType
2842 status;
2843
cristycb6d09b2010-06-19 01:59:36 +00002844 ssize_t
2845 y;
2846
cristya5b77cb2010-05-07 19:34:48 +00002847 assert(image != (Image *) NULL);
2848 if (image->debug != MagickFalse)
2849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2850 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002851 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002852 image->colorspace=color->colorspace;
2853 image->matte=color->matte;
2854 image->fuzz=color->fuzz;
2855 image->depth=color->depth;
2856 status=MagickTrue;
2857 exception=(&image->exception);
2858 image_view=AcquireCacheView(image);
2859#if defined(MAGICKCORE_OPENMP_SUPPORT)
2860 #pragma omp parallel for schedule(dynamic,4) shared(status)
2861#endif
cristybb503372010-05-27 20:51:26 +00002862 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002863 {
cristy4c08aed2011-07-01 19:47:50 +00002864 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002865 *restrict q;
2866
cristycb6d09b2010-06-19 01:59:36 +00002867 register ssize_t
2868 x;
2869
cristya5b77cb2010-05-07 19:34:48 +00002870 if (status == MagickFalse)
2871 continue;
2872 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002873 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002874 {
2875 status=MagickFalse;
2876 continue;
2877 }
cristybb503372010-05-27 20:51:26 +00002878 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002879 {
cristy4c08aed2011-07-01 19:47:50 +00002880 SetPixelPixelInfo(image,color,q);
cristydcfc1ad2011-07-07 16:25:41 +00002881 q+=GetPixelComponents(image);
cristya5b77cb2010-05-07 19:34:48 +00002882 }
2883 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2884 status=MagickFalse;
2885 }
2886 image_view=DestroyCacheView(image_view);
2887 return(status);
2888}
2889
2890/*
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892% %
2893% %
2894% %
cristy3ed852e2009-09-05 21:47:34 +00002895% S e t I m a g e S t o r a g e C l a s s %
2896% %
2897% %
2898% %
2899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2900%
2901% SetImageStorageClass() sets the image class: DirectClass for true color
2902% images or PseudoClass for colormapped images.
2903%
2904% The format of the SetImageStorageClass method is:
2905%
2906% MagickBooleanType SetImageStorageClass(Image *image,
2907% const ClassType storage_class)
2908%
2909% A description of each parameter follows:
2910%
2911% o image: the image.
2912%
2913% o storage_class: The image class.
2914%
2915*/
2916MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2917 const ClassType storage_class)
2918{
cristy3ed852e2009-09-05 21:47:34 +00002919 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00002920 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002921}
2922
2923/*
2924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925% %
2926% %
2927% %
2928% S e t I m a g e C l i p M a s k %
2929% %
2930% %
2931% %
2932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933%
2934% SetImageClipMask() associates a clip path with the image. The clip path
2935% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002936% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002937% pixel component from being updated when SyncAuthenticPixels() is applied.
2938%
2939% The format of the SetImageClipMask method is:
2940%
2941% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947% o clip_mask: the image clip path.
2948%
2949*/
2950MagickExport MagickBooleanType SetImageClipMask(Image *image,
2951 const Image *clip_mask)
2952{
2953 assert(image != (Image *) NULL);
2954 if (image->debug != MagickFalse)
2955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2956 assert(image->signature == MagickSignature);
2957 if (clip_mask != (const Image *) NULL)
2958 if ((clip_mask->columns != image->columns) ||
2959 (clip_mask->rows != image->rows))
2960 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2961 if (image->clip_mask != (Image *) NULL)
2962 image->clip_mask=DestroyImage(image->clip_mask);
2963 image->clip_mask=NewImageList();
2964 if (clip_mask == (Image *) NULL)
2965 return(MagickTrue);
2966 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2967 return(MagickFalse);
2968 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2969 if (image->clip_mask == (Image *) NULL)
2970 return(MagickFalse);
2971 return(MagickTrue);
2972}
2973
2974/*
2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976% %
2977% %
2978% %
2979% S e t I m a g e E x t e n t %
2980% %
2981% %
2982% %
2983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2984%
2985% SetImageExtent() sets the image size (i.e. columns & rows).
2986%
2987% The format of the SetImageExtent method is:
2988%
2989% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00002990% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002991%
2992% A description of each parameter follows:
2993%
2994% o image: the image.
2995%
2996% o columns: The image width in pixels.
2997%
2998% o rows: The image height in pixels.
2999%
3000*/
3001MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003002 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003003{
cristy537e2722010-09-21 15:30:59 +00003004 if ((columns == 0) || (rows == 0))
3005 return(MagickFalse);
3006 image->columns=columns;
3007 image->rows=rows;
3008 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003009}
3010
3011/*
3012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013% %
3014% %
3015% %
3016+ S e t I m a g e I n f o %
3017% %
3018% %
3019% %
3020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3021%
3022% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3023% It is set to a type of image format based on the prefix or suffix of the
3024% filename. For example, `ps:image' returns PS indicating a Postscript image.
3025% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3026% precendence over the suffix. Use an optional index enclosed in brackets
3027% after a file name to specify a desired scene of a multi-resolution image
3028% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3029% indicates success.
3030%
3031% The format of the SetImageInfo method is:
3032%
3033% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003034% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003035%
3036% A description of each parameter follows:
3037%
cristyd965a422010-03-03 17:47:35 +00003038% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003039%
cristyd965a422010-03-03 17:47:35 +00003040% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003041%
3042% o exception: return any errors or warnings in this structure.
3043%
3044*/
3045MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003046 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003047{
3048 char
3049 extension[MaxTextExtent],
3050 filename[MaxTextExtent],
3051 magic[MaxTextExtent],
3052 *q,
3053 subimage[MaxTextExtent];
3054
3055 const MagicInfo
3056 *magic_info;
3057
3058 const MagickInfo
3059 *magick_info;
3060
3061 ExceptionInfo
3062 *sans_exception;
3063
3064 Image
3065 *image;
3066
3067 MagickBooleanType
3068 status;
3069
3070 register const char
3071 *p;
3072
3073 ssize_t
3074 count;
3075
3076 unsigned char
3077 magick[2*MaxTextExtent];
3078
3079 /*
3080 Look for 'image.format' in filename.
3081 */
3082 assert(image_info != (ImageInfo *) NULL);
3083 assert(image_info->signature == MagickSignature);
3084 if (image_info->debug != MagickFalse)
3085 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3086 image_info->filename);
3087 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003088 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003089 {
cristyd965a422010-03-03 17:47:35 +00003090 GetPathComponent(image_info->filename,SubimagePath,subimage);
3091 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003092 {
cristyd965a422010-03-03 17:47:35 +00003093 /*
3094 Look for scene specification (e.g. img0001.pcd[4]).
3095 */
3096 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3097 {
3098 if (IsGeometry(subimage) != MagickFalse)
3099 (void) CloneString(&image_info->extract,subimage);
3100 }
3101 else
3102 {
cristybb503372010-05-27 20:51:26 +00003103 size_t
cristyd965a422010-03-03 17:47:35 +00003104 first,
3105 last;
cristy3ed852e2009-09-05 21:47:34 +00003106
cristyd965a422010-03-03 17:47:35 +00003107 (void) CloneString(&image_info->scenes,subimage);
3108 image_info->scene=StringToUnsignedLong(image_info->scenes);
3109 image_info->number_scenes=image_info->scene;
3110 p=image_info->scenes;
3111 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3112 {
3113 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3114 (*p == ','))
3115 p++;
cristybb503372010-05-27 20:51:26 +00003116 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003117 last=first;
3118 while (isspace((int) ((unsigned char) *q)) != 0)
3119 q++;
3120 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003121 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003122 if (first > last)
3123 Swap(first,last);
3124 if (first < image_info->scene)
3125 image_info->scene=first;
3126 if (last > image_info->number_scenes)
3127 image_info->number_scenes=last;
3128 p=q;
3129 }
3130 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003131 }
cristy3ed852e2009-09-05 21:47:34 +00003132 }
3133 }
3134 *extension='\0';
3135 GetPathComponent(image_info->filename,ExtensionPath,extension);
3136#if defined(MAGICKCORE_ZLIB_DELEGATE)
3137 if (*extension != '\0')
3138 if ((LocaleCompare(extension,"gz") == 0) ||
3139 (LocaleCompare(extension,"Z") == 0) ||
3140 (LocaleCompare(extension,"wmz") == 0))
3141 {
3142 char
3143 path[MaxTextExtent];
3144
3145 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3146 path[strlen(path)-strlen(extension)-1]='\0';
3147 GetPathComponent(path,ExtensionPath,extension);
3148 }
3149#endif
3150#if defined(MAGICKCORE_BZLIB_DELEGATE)
3151 if (*extension != '\0')
3152 if (LocaleCompare(extension,"bz2") == 0)
3153 {
3154 char
3155 path[MaxTextExtent];
3156
3157 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3158 path[strlen(path)-strlen(extension)-1]='\0';
3159 GetPathComponent(path,ExtensionPath,extension);
3160 }
3161#endif
3162 image_info->affirm=MagickFalse;
3163 sans_exception=AcquireExceptionInfo();
3164 if (*extension != '\0')
3165 {
3166 MagickFormatType
3167 format_type;
3168
cristybb503372010-05-27 20:51:26 +00003169 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003170 i;
3171
3172 static const char
3173 *format_type_formats[] =
3174 {
3175 "AUTOTRACE",
3176 "BROWSE",
3177 "DCRAW",
3178 "EDIT",
3179 "EPHEMERAL",
3180 "LAUNCH",
3181 "MPEG:DECODE",
3182 "MPEG:ENCODE",
3183 "PRINT",
3184 "PS:ALPHA",
3185 "PS:CMYK",
3186 "PS:COLOR",
3187 "PS:GRAY",
3188 "PS:MONO",
3189 "SCAN",
3190 "SHOW",
3191 "WIN",
3192 (char *) NULL
3193 };
3194
3195 /*
3196 User specified image format.
3197 */
3198 (void) CopyMagickString(magic,extension,MaxTextExtent);
3199 LocaleUpper(magic);
3200 /*
3201 Look for explicit image formats.
3202 */
3203 format_type=UndefinedFormatType;
3204 i=0;
cristydd9a2532010-02-20 19:26:46 +00003205 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003206 (format_type_formats[i] != (char *) NULL))
3207 {
3208 if ((*magic == *format_type_formats[i]) &&
3209 (LocaleCompare(magic,format_type_formats[i]) == 0))
3210 format_type=ExplicitFormatType;
3211 i++;
3212 }
3213 magick_info=GetMagickInfo(magic,sans_exception);
3214 if ((magick_info != (const MagickInfo *) NULL) &&
3215 (magick_info->format_type != UndefinedFormatType))
3216 format_type=magick_info->format_type;
3217 if (format_type == UndefinedFormatType)
3218 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3219 else
3220 if (format_type == ExplicitFormatType)
3221 {
3222 image_info->affirm=MagickTrue;
3223 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3224 }
3225 if (LocaleCompare(magic,"RGB") == 0)
3226 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3227 }
3228 /*
3229 Look for explicit 'format:image' in filename.
3230 */
3231 *magic='\0';
3232 GetPathComponent(image_info->filename,MagickPath,magic);
3233 if (*magic == '\0')
3234 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3235 else
3236 {
3237 /*
3238 User specified image format.
3239 */
3240 LocaleUpper(magic);
3241 if (IsMagickConflict(magic) == MagickFalse)
3242 {
3243 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3244 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3245 image_info->affirm=MagickTrue;
3246 else
3247 image_info->temporary=MagickTrue;
3248 }
3249 }
3250 magick_info=GetMagickInfo(magic,sans_exception);
3251 sans_exception=DestroyExceptionInfo(sans_exception);
3252 if ((magick_info == (const MagickInfo *) NULL) ||
3253 (GetMagickEndianSupport(magick_info) == MagickFalse))
3254 image_info->endian=UndefinedEndian;
3255 GetPathComponent(image_info->filename,CanonicalPath,filename);
3256 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003257 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003258 {
3259 /*
cristyd965a422010-03-03 17:47:35 +00003260 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003261 */
cristyd965a422010-03-03 17:47:35 +00003262 (void) InterpretImageFilename(image_info,(Image *) NULL,
3263 image_info->filename,(int) image_info->scene,filename);
3264 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3265 (strchr(filename,'%') == (char *) NULL))
3266 image_info->adjoin=MagickFalse;
3267 }
3268 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3269 {
3270 /*
3271 Some image formats do not support multiple frames per file.
3272 */
cristy3ed852e2009-09-05 21:47:34 +00003273 magick_info=GetMagickInfo(magic,exception);
3274 if (magick_info != (const MagickInfo *) NULL)
3275 if (GetMagickAdjoin(magick_info) == MagickFalse)
3276 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003277 }
3278 if (image_info->affirm != MagickFalse)
3279 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003280 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003281 {
3282 /*
cristyd965a422010-03-03 17:47:35 +00003283 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003284 */
cristyd965a422010-03-03 17:47:35 +00003285 image=AcquireImage(image_info);
3286 (void) CopyMagickString(image->filename,image_info->filename,
3287 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003288 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3289 if (status == MagickFalse)
3290 {
3291 image=DestroyImage(image);
3292 return(MagickFalse);
3293 }
cristyd965a422010-03-03 17:47:35 +00003294 if ((IsBlobSeekable(image) == MagickFalse) ||
3295 (IsBlobExempt(image) != MagickFalse))
3296 {
3297 /*
3298 Copy standard input or pipe to temporary file.
3299 */
3300 *filename='\0';
3301 status=ImageToFile(image,filename,exception);
3302 (void) CloseBlob(image);
3303 if (status == MagickFalse)
3304 {
3305 image=DestroyImage(image);
3306 return(MagickFalse);
3307 }
3308 SetImageInfoFile(image_info,(FILE *) NULL);
3309 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3310 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3311 if (status == MagickFalse)
3312 {
3313 image=DestroyImage(image);
3314 return(MagickFalse);
3315 }
3316 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3317 image_info->temporary=MagickTrue;
3318 }
3319 (void) ResetMagickMemory(magick,0,sizeof(magick));
3320 count=ReadBlob(image,2*MaxTextExtent,magick);
3321 (void) CloseBlob(image);
3322 image=DestroyImage(image);
3323 /*
3324 Check magic.xml configuration file.
3325 */
3326 sans_exception=AcquireExceptionInfo();
3327 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3328 if ((magic_info != (const MagicInfo *) NULL) &&
3329 (GetMagicName(magic_info) != (char *) NULL))
3330 {
3331 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3332 MaxTextExtent);
3333 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3334 if ((magick_info == (const MagickInfo *) NULL) ||
3335 (GetMagickEndianSupport(magick_info) == MagickFalse))
3336 image_info->endian=UndefinedEndian;
3337 sans_exception=DestroyExceptionInfo(sans_exception);
3338 return(MagickTrue);
3339 }
cristy3ed852e2009-09-05 21:47:34 +00003340 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3341 if ((magick_info == (const MagickInfo *) NULL) ||
3342 (GetMagickEndianSupport(magick_info) == MagickFalse))
3343 image_info->endian=UndefinedEndian;
3344 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003345 }
cristy3ed852e2009-09-05 21:47:34 +00003346 return(MagickTrue);
3347}
3348
3349/*
3350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3351% %
3352% %
3353% %
3354% S e t I m a g e I n f o B l o b %
3355% %
3356% %
3357% %
3358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3359%
3360% SetImageInfoBlob() sets the image info blob member.
3361%
3362% The format of the SetImageInfoBlob method is:
3363%
3364% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3365% const size_t length)
3366%
3367% A description of each parameter follows:
3368%
3369% o image_info: the image info.
3370%
3371% o blob: the blob.
3372%
3373% o length: the blob length.
3374%
3375*/
3376MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3377 const size_t length)
3378{
3379 assert(image_info != (ImageInfo *) NULL);
3380 assert(image_info->signature == MagickSignature);
3381 if (image_info->debug != MagickFalse)
3382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3383 image_info->filename);
3384 image_info->blob=(void *) blob;
3385 image_info->length=length;
3386}
3387
3388/*
3389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3390% %
3391% %
3392% %
3393% S e t I m a g e I n f o F i l e %
3394% %
3395% %
3396% %
3397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3398%
3399% SetImageInfoFile() sets the image info file member.
3400%
3401% The format of the SetImageInfoFile method is:
3402%
3403% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3404%
3405% A description of each parameter follows:
3406%
3407% o image_info: the image info.
3408%
3409% o file: the file.
3410%
3411*/
3412MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3413{
3414 assert(image_info != (ImageInfo *) NULL);
3415 assert(image_info->signature == MagickSignature);
3416 if (image_info->debug != MagickFalse)
3417 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3418 image_info->filename);
3419 image_info->file=file;
3420}
3421
3422/*
3423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3424% %
3425% %
3426% %
3427% S e t I m a g e M a s k %
3428% %
3429% %
3430% %
3431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3432%
3433% SetImageMask() associates a mask with the image. The mask must be the same
3434% dimensions as the image.
3435%
3436% The format of the SetImageMask method is:
3437%
3438% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3439%
3440% A description of each parameter follows:
3441%
3442% o image: the image.
3443%
3444% o mask: the image mask.
3445%
3446*/
3447MagickExport MagickBooleanType SetImageMask(Image *image,
3448 const Image *mask)
3449{
3450 assert(image != (Image *) NULL);
3451 if (image->debug != MagickFalse)
3452 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3453 assert(image->signature == MagickSignature);
3454 if (mask != (const Image *) NULL)
3455 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3456 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3457 if (image->mask != (Image *) NULL)
3458 image->mask=DestroyImage(image->mask);
3459 image->mask=NewImageList();
3460 if (mask == (Image *) NULL)
3461 return(MagickTrue);
3462 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3463 return(MagickFalse);
3464 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3465 if (image->mask == (Image *) NULL)
3466 return(MagickFalse);
3467 return(MagickTrue);
3468}
3469
3470/*
3471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3472% %
3473% %
3474% %
3475% S e t I m a g e O p a c i t y %
3476% %
3477% %
3478% %
3479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480%
3481% SetImageOpacity() sets the opacity levels of the image.
3482%
3483% The format of the SetImageOpacity method is:
3484%
3485% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3486%
3487% A description of each parameter follows:
3488%
3489% o image: the image.
3490%
3491% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3492% fully transparent.
3493%
3494*/
3495MagickExport MagickBooleanType SetImageOpacity(Image *image,
3496 const Quantum opacity)
3497{
3498 CacheView
3499 *image_view;
3500
3501 ExceptionInfo
3502 *exception;
3503
cristy3ed852e2009-09-05 21:47:34 +00003504 MagickBooleanType
3505 status;
3506
cristycb6d09b2010-06-19 01:59:36 +00003507 ssize_t
3508 y;
3509
cristy3ed852e2009-09-05 21:47:34 +00003510 assert(image != (Image *) NULL);
3511 if (image->debug != MagickFalse)
3512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3513 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003514 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003515 status=MagickTrue;
3516 exception=(&image->exception);
3517 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003518#if defined(MAGICKCORE_OPENMP_SUPPORT)
3519 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003520#endif
cristybb503372010-05-27 20:51:26 +00003521 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003522 {
cristy4c08aed2011-07-01 19:47:50 +00003523 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003524 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003525
cristycb6d09b2010-06-19 01:59:36 +00003526 register ssize_t
3527 x;
3528
cristy3ed852e2009-09-05 21:47:34 +00003529 if (status == MagickFalse)
3530 continue;
3531 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003532 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003533 {
3534 status=MagickFalse;
3535 continue;
3536 }
cristybb503372010-05-27 20:51:26 +00003537 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003538 {
cristy4c08aed2011-07-01 19:47:50 +00003539 SetPixelAlpha(image,opacity,q);
cristydcfc1ad2011-07-07 16:25:41 +00003540 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00003541 }
3542 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3543 status=MagickFalse;
3544 }
3545 image_view=DestroyCacheView(image_view);
3546 return(status);
3547}
3548
3549/*
3550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3551% %
3552% %
3553% %
3554% S e t I m a g e T y p e %
3555% %
3556% %
3557% %
3558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559%
3560% SetImageType() sets the type of image. Choose from these types:
3561%
3562% Bilevel Grayscale GrayscaleMatte
3563% Palette PaletteMatte TrueColor
3564% TrueColorMatte ColorSeparation ColorSeparationMatte
3565% OptimizeType
3566%
3567% The format of the SetImageType method is:
3568%
3569% MagickBooleanType SetImageType(Image *image,const ImageType type)
3570%
3571% A description of each parameter follows:
3572%
3573% o image: the image.
3574%
3575% o type: Image type.
3576%
3577*/
3578MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3579{
3580 const char
3581 *artifact;
3582
3583 ImageInfo
3584 *image_info;
3585
3586 MagickBooleanType
3587 status;
3588
3589 QuantizeInfo
3590 *quantize_info;
3591
3592 assert(image != (Image *) NULL);
3593 if (image->debug != MagickFalse)
3594 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3595 assert(image->signature == MagickSignature);
3596 status=MagickTrue;
3597 image_info=AcquireImageInfo();
3598 image_info->dither=image->dither;
3599 artifact=GetImageArtifact(image,"dither");
3600 if (artifact != (const char *) NULL)
3601 (void) SetImageOption(image_info,"dither",artifact);
3602 switch (type)
3603 {
3604 case BilevelType:
3605 {
cristy4c08aed2011-07-01 19:47:50 +00003606 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003607 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003608 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003609 {
3610 quantize_info=AcquireQuantizeInfo(image_info);
3611 quantize_info->number_colors=2;
3612 quantize_info->colorspace=GRAYColorspace;
3613 status=QuantizeImage(quantize_info,image);
3614 quantize_info=DestroyQuantizeInfo(quantize_info);
3615 }
3616 image->matte=MagickFalse;
3617 break;
3618 }
3619 case GrayscaleType:
3620 {
cristy4c08aed2011-07-01 19:47:50 +00003621 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003622 status=TransformImageColorspace(image,GRAYColorspace);
3623 image->matte=MagickFalse;
3624 break;
3625 }
3626 case GrayscaleMatteType:
3627 {
cristy4c08aed2011-07-01 19:47:50 +00003628 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003629 status=TransformImageColorspace(image,GRAYColorspace);
3630 if (image->matte == MagickFalse)
3631 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3632 break;
3633 }
3634 case PaletteType:
3635 {
cristy510d06a2011-07-06 23:43:54 +00003636 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003637 status=TransformImageColorspace(image,RGBColorspace);
3638 if ((image->storage_class == DirectClass) || (image->colors > 256))
3639 {
3640 quantize_info=AcquireQuantizeInfo(image_info);
3641 quantize_info->number_colors=256;
3642 status=QuantizeImage(quantize_info,image);
3643 quantize_info=DestroyQuantizeInfo(quantize_info);
3644 }
3645 image->matte=MagickFalse;
3646 break;
3647 }
3648 case PaletteBilevelMatteType:
3649 {
cristy510d06a2011-07-06 23:43:54 +00003650 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003651 status=TransformImageColorspace(image,RGBColorspace);
3652 if (image->matte == MagickFalse)
3653 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3654 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3655 quantize_info=AcquireQuantizeInfo(image_info);
3656 status=QuantizeImage(quantize_info,image);
3657 quantize_info=DestroyQuantizeInfo(quantize_info);
3658 break;
3659 }
3660 case PaletteMatteType:
3661 {
cristy510d06a2011-07-06 23:43:54 +00003662 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003663 status=TransformImageColorspace(image,RGBColorspace);
3664 if (image->matte == MagickFalse)
3665 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3666 quantize_info=AcquireQuantizeInfo(image_info);
3667 quantize_info->colorspace=TransparentColorspace;
3668 status=QuantizeImage(quantize_info,image);
3669 quantize_info=DestroyQuantizeInfo(quantize_info);
3670 break;
3671 }
3672 case TrueColorType:
3673 {
cristy510d06a2011-07-06 23:43:54 +00003674 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003675 status=TransformImageColorspace(image,RGBColorspace);
3676 if (image->storage_class != DirectClass)
3677 status=SetImageStorageClass(image,DirectClass);
3678 image->matte=MagickFalse;
3679 break;
3680 }
3681 case TrueColorMatteType:
3682 {
cristy510d06a2011-07-06 23:43:54 +00003683 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003684 status=TransformImageColorspace(image,RGBColorspace);
3685 if (image->storage_class != DirectClass)
3686 status=SetImageStorageClass(image,DirectClass);
3687 if (image->matte == MagickFalse)
3688 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3689 break;
3690 }
3691 case ColorSeparationType:
3692 {
3693 if (image->colorspace != CMYKColorspace)
3694 {
cristy510d06a2011-07-06 23:43:54 +00003695 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003696 status=TransformImageColorspace(image,RGBColorspace);
3697 status=TransformImageColorspace(image,CMYKColorspace);
3698 }
3699 if (image->storage_class != DirectClass)
3700 status=SetImageStorageClass(image,DirectClass);
3701 image->matte=MagickFalse;
3702 break;
3703 }
3704 case ColorSeparationMatteType:
3705 {
3706 if (image->colorspace != CMYKColorspace)
3707 {
cristy510d06a2011-07-06 23:43:54 +00003708 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003709 status=TransformImageColorspace(image,RGBColorspace);
3710 status=TransformImageColorspace(image,CMYKColorspace);
3711 }
3712 if (image->storage_class != DirectClass)
3713 status=SetImageStorageClass(image,DirectClass);
3714 if (image->matte == MagickFalse)
3715 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3716 break;
3717 }
3718 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003719 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003720 break;
3721 }
3722 image->type=type;
3723 image_info=DestroyImageInfo(image_info);
3724 return(status);
3725}
3726
3727/*
3728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729% %
3730% %
3731% %
3732% 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 %
3733% %
3734% %
3735% %
3736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3737%
3738% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3739% image and returns the previous setting. A virtual pixel is any pixel access
3740% that is outside the boundaries of the image cache.
3741%
3742% The format of the SetImageVirtualPixelMethod() method is:
3743%
3744% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3745% const VirtualPixelMethod virtual_pixel_method)
3746%
3747% A description of each parameter follows:
3748%
3749% o image: the image.
3750%
3751% o virtual_pixel_method: choose the type of virtual pixel.
3752%
3753*/
3754MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3755 const VirtualPixelMethod virtual_pixel_method)
3756{
3757 assert(image != (const Image *) NULL);
3758 assert(image->signature == MagickSignature);
3759 if (image->debug != MagickFalse)
3760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3761 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3762}
3763
3764/*
3765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766% %
3767% %
3768% %
cristy4285d782011-02-09 20:12:28 +00003769% S m u s h I m a g e s %
3770% %
3771% %
3772% %
3773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3774%
3775% SmushImages() takes all images from the current image pointer to the end
3776% of the image list and smushes them to each other top-to-bottom if the
3777% stack parameter is true, otherwise left-to-right.
3778%
3779% The current gravity setting now effects how the image is justified in the
3780% final image.
3781%
3782% The format of the SmushImages method is:
3783%
cristy4ca38e22011-02-10 02:57:49 +00003784% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003785% ExceptionInfo *exception)
3786%
3787% A description of each parameter follows:
3788%
cristy4ca38e22011-02-10 02:57:49 +00003789% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003790%
3791% o stack: A value other than 0 stacks the images top-to-bottom.
3792%
3793% o offset: minimum distance in pixels between images.
3794%
3795% o exception: return any errors or warnings in this structure.
3796%
3797*/
cristy4ca38e22011-02-10 02:57:49 +00003798
cristy7c6dc152011-02-11 14:10:55 +00003799static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003800 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003801{
cristy4d727152011-02-10 19:57:21 +00003802 CacheView
3803 *left_view,
3804 *right_view;
3805
3806 const Image
3807 *left_image,
3808 *right_image;
3809
cristy4d727152011-02-10 19:57:21 +00003810 RectangleInfo
3811 left_geometry,
3812 right_geometry;
3813
cristy4c08aed2011-07-01 19:47:50 +00003814 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003815 *p;
3816
cristy4d727152011-02-10 19:57:21 +00003817 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003818 i,
cristy4d727152011-02-10 19:57:21 +00003819 y;
3820
cristy7c6dc152011-02-11 14:10:55 +00003821 size_t
3822 gap;
3823
cristy4d727152011-02-10 19:57:21 +00003824 ssize_t
cristy4d727152011-02-10 19:57:21 +00003825 x;
3826
3827 if (images->previous == (Image *) NULL)
3828 return(0);
3829 right_image=images;
3830 SetGeometry(smush_image,&right_geometry);
3831 GravityAdjustGeometry(right_image->columns,right_image->rows,
3832 right_image->gravity,&right_geometry);
3833 left_image=images->previous;
3834 SetGeometry(smush_image,&left_geometry);
3835 GravityAdjustGeometry(left_image->columns,left_image->rows,
3836 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003837 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003838 left_view=AcquireCacheView(left_image);
3839 right_view=AcquireCacheView(right_image);
3840 for (y=0; y < (ssize_t) smush_image->rows; y++)
3841 {
3842 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3843 {
cristydab7e912011-02-11 18:19:24 +00003844 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003845 if ((p == (const Quantum *) NULL) ||
3846 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003847 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003848 break;
3849 }
cristy4ef6f062011-02-10 20:30:22 +00003850 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003851 for (x=0; x < (ssize_t) right_image->columns; x++)
3852 {
cristydab7e912011-02-11 18:19:24 +00003853 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003854 exception);
cristy4c08aed2011-07-01 19:47:50 +00003855 if ((p == (const Quantum *) NULL) ||
3856 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3857 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003858 break;
3859 }
cristy7c6dc152011-02-11 14:10:55 +00003860 if ((x+i) < (ssize_t) gap)
3861 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003862 }
3863 right_view=DestroyCacheView(right_view);
3864 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003865 if (y < (ssize_t) smush_image->rows)
3866 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003867 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003868}
3869
cristy7c6dc152011-02-11 14:10:55 +00003870static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003871 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003872{
cristy4d727152011-02-10 19:57:21 +00003873 CacheView
3874 *bottom_view,
3875 *top_view;
3876
3877 const Image
3878 *bottom_image,
3879 *top_image;
3880
cristy4d727152011-02-10 19:57:21 +00003881 RectangleInfo
3882 bottom_geometry,
3883 top_geometry;
3884
cristy4c08aed2011-07-01 19:47:50 +00003885 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003886 *p;
3887
cristy4d727152011-02-10 19:57:21 +00003888 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003889 i,
cristy4d727152011-02-10 19:57:21 +00003890 x;
3891
cristy7c6dc152011-02-11 14:10:55 +00003892 size_t
3893 gap;
3894
cristy4d727152011-02-10 19:57:21 +00003895 ssize_t
cristy4d727152011-02-10 19:57:21 +00003896 y;
3897
3898 if (images->previous == (Image *) NULL)
3899 return(0);
3900 bottom_image=images;
3901 SetGeometry(smush_image,&bottom_geometry);
3902 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3903 bottom_image->gravity,&bottom_geometry);
3904 top_image=images->previous;
3905 SetGeometry(smush_image,&top_geometry);
3906 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3907 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003908 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003909 top_view=AcquireCacheView(top_image);
3910 bottom_view=AcquireCacheView(bottom_image);
3911 for (x=0; x < (ssize_t) smush_image->columns; x++)
3912 {
3913 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3914 {
cristydab7e912011-02-11 18:19:24 +00003915 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003916 if ((p == (const Quantum *) NULL) ||
3917 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3918 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003919 break;
3920 }
cristy4ef6f062011-02-10 20:30:22 +00003921 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003922 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3923 {
cristydab7e912011-02-11 18:19:24 +00003924 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3925 exception);
cristy4c08aed2011-07-01 19:47:50 +00003926 if ((p == (const Quantum *) NULL) ||
3927 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3928 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003929 break;
3930 }
cristy7c6dc152011-02-11 14:10:55 +00003931 if ((y+i) < (ssize_t) gap)
3932 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003933 }
3934 bottom_view=DestroyCacheView(bottom_view);
3935 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003936 if (x < (ssize_t) smush_image->columns)
3937 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003938 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003939}
3940
3941MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003942 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3943{
3944#define SmushImageTag "Smush/Image"
3945
3946 CacheView
cristybb5dced2011-02-10 02:17:16 +00003947 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003948
cristy4ca38e22011-02-10 02:57:49 +00003949 const Image
3950 *image;
3951
cristy4285d782011-02-09 20:12:28 +00003952 Image
3953 *smush_image;
3954
3955 MagickBooleanType
3956 matte,
3957 proceed,
3958 status;
3959
3960 MagickOffsetType
3961 n;
3962
3963 RectangleInfo
3964 geometry;
3965
3966 register const Image
3967 *next;
3968
3969 size_t
3970 height,
3971 number_images,
3972 width;
3973
3974 ssize_t
3975 x_offset,
cristy4285d782011-02-09 20:12:28 +00003976 y_offset;
3977
3978 /*
cristy7c6dc152011-02-11 14:10:55 +00003979 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003980 */
cristy4ca38e22011-02-10 02:57:49 +00003981 assert(images != (Image *) NULL);
3982 assert(images->signature == MagickSignature);
3983 if (images->debug != MagickFalse)
3984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003985 assert(exception != (ExceptionInfo *) NULL);
3986 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003987 image=images;
cristy4285d782011-02-09 20:12:28 +00003988 matte=image->matte;
3989 number_images=1;
3990 width=image->columns;
3991 height=image->rows;
3992 next=GetNextImageInList(image);
3993 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3994 {
3995 if (next->matte != MagickFalse)
3996 matte=MagickTrue;
3997 number_images++;
3998 if (stack != MagickFalse)
3999 {
4000 if (next->columns > width)
4001 width=next->columns;
4002 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004003 if (next->previous != (Image *) NULL)
4004 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004005 continue;
4006 }
4007 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004008 if (next->previous != (Image *) NULL)
4009 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004010 if (next->rows > height)
4011 height=next->rows;
4012 }
4013 /*
cristy7c6dc152011-02-11 14:10:55 +00004014 Smush images.
cristy4285d782011-02-09 20:12:28 +00004015 */
4016 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4017 if (smush_image == (Image *) NULL)
4018 return((Image *) NULL);
4019 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4020 {
4021 InheritException(exception,&smush_image->exception);
4022 smush_image=DestroyImage(smush_image);
4023 return((Image *) NULL);
4024 }
4025 smush_image->matte=matte;
4026 (void) SetImageBackgroundColor(smush_image);
4027 status=MagickTrue;
4028 x_offset=0;
4029 y_offset=0;
4030 smush_view=AcquireCacheView(smush_image);
4031 for (n=0; n < (MagickOffsetType) number_images; n++)
4032 {
4033 SetGeometry(smush_image,&geometry);
4034 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4035 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004036 {
4037 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004038 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004039 }
cristy4285d782011-02-09 20:12:28 +00004040 else
cristy4ca38e22011-02-10 02:57:49 +00004041 {
cristy7c6dc152011-02-11 14:10:55 +00004042 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004043 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004044 }
cristybb5dced2011-02-10 02:17:16 +00004045 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004046 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4047 if (proceed == MagickFalse)
4048 break;
4049 if (stack == MagickFalse)
4050 {
4051 x_offset+=(ssize_t) image->columns;
4052 y_offset=0;
4053 }
4054 else
4055 {
4056 x_offset=0;
4057 y_offset+=(ssize_t) image->rows;
4058 }
4059 image=GetNextImageInList(image);
4060 }
cristy4ef6f062011-02-10 20:30:22 +00004061 if (stack == MagickFalse)
4062 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004063 else
cristy4ef6f062011-02-10 20:30:22 +00004064 smush_image->rows=(size_t) y_offset;
4065 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004066 if (status == MagickFalse)
4067 smush_image=DestroyImage(smush_image);
4068 return(smush_image);
4069}
4070
4071/*
4072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073% %
4074% %
4075% %
cristy3ed852e2009-09-05 21:47:34 +00004076% S t r i p I m a g e %
4077% %
4078% %
4079% %
4080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4081%
cristy376bda92009-12-22 21:15:23 +00004082% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004083%
4084% The format of the StripImage method is:
4085%
4086% MagickBooleanType StripImage(Image *image)
4087%
4088% A description of each parameter follows:
4089%
4090% o image: the image.
4091%
4092*/
4093MagickExport MagickBooleanType StripImage(Image *image)
4094{
4095 assert(image != (Image *) NULL);
4096 if (image->debug != MagickFalse)
4097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4098 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004099 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004100 (void) DeleteImageProperty(image,"date:create");
4101 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004102 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004103 return(MagickTrue);
4104}
4105
4106/*
4107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4108% %
4109% %
4110% %
4111+ S y n c I m a g e %
4112% %
4113% %
4114% %
4115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4116%
4117% SyncImage() initializes the red, green, and blue intensities of each pixel
4118% as defined by the colormap index.
4119%
4120% The format of the SyncImage method is:
4121%
4122% MagickBooleanType SyncImage(Image *image)
4123%
4124% A description of each parameter follows:
4125%
4126% o image: the image.
4127%
4128*/
4129
cristy4c08aed2011-07-01 19:47:50 +00004130static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004131 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004132{
4133 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004134 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004135 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004136 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004137}
4138
4139MagickExport MagickBooleanType SyncImage(Image *image)
4140{
4141 CacheView
4142 *image_view;
4143
4144 ExceptionInfo
4145 *exception;
4146
cristy3ed852e2009-09-05 21:47:34 +00004147 MagickBooleanType
4148 range_exception,
4149 status;
4150
cristycb6d09b2010-06-19 01:59:36 +00004151 ssize_t
4152 y;
4153
cristy3ed852e2009-09-05 21:47:34 +00004154 assert(image != (Image *) NULL);
4155 if (image->debug != MagickFalse)
4156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4157 assert(image->signature == MagickSignature);
4158 if (image->storage_class == DirectClass)
4159 return(MagickFalse);
4160 range_exception=MagickFalse;
4161 status=MagickTrue;
4162 exception=(&image->exception);
4163 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004164#if defined(MAGICKCORE_OPENMP_SUPPORT)
4165 #pragma omp parallel for schedule(dynamic,4) shared(status)
4166#endif
cristybb503372010-05-27 20:51:26 +00004167 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004168 {
cristy4c08aed2011-07-01 19:47:50 +00004169 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004170 index;
4171
cristy4c08aed2011-07-01 19:47:50 +00004172 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004173 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004174
cristycb6d09b2010-06-19 01:59:36 +00004175 register ssize_t
4176 x;
4177
cristy48974b92009-12-19 02:36:06 +00004178 if (status == MagickFalse)
4179 continue;
cristy3ed852e2009-09-05 21:47:34 +00004180 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004181 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004182 {
4183 status=MagickFalse;
4184 continue;
4185 }
cristybb503372010-05-27 20:51:26 +00004186 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004187 {
cristy4c08aed2011-07-01 19:47:50 +00004188 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004189 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004190 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristydcfc1ad2011-07-07 16:25:41 +00004191 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00004192 }
4193 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4194 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004195 }
4196 image_view=DestroyCacheView(image_view);
4197 if (range_exception != MagickFalse)
4198 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4199 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4200 return(status);
4201}
cristy1626d332009-11-10 16:58:17 +00004202
4203/*
4204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4205% %
4206% %
4207% %
4208% S y n c I m a g e S e t t i n g s %
4209% %
4210% %
4211% %
4212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4213%
4214% SyncImageSettings() sync the image info options to the image.
4215%
4216% The format of the SyncImageSettings method is:
4217%
4218% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4219% Image *image)
4220% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4221% Image *image)
4222%
4223% A description of each parameter follows:
4224%
4225% o image_info: the image info.
4226%
4227% o image: the image.
4228%
4229*/
4230
4231MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4232 Image *images)
4233{
4234 Image
4235 *image;
4236
4237 assert(image_info != (const ImageInfo *) NULL);
4238 assert(image_info->signature == MagickSignature);
4239 assert(images != (Image *) NULL);
4240 assert(images->signature == MagickSignature);
4241 if (images->debug != MagickFalse)
4242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4243 image=images;
4244 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4245 (void) SyncImageSettings(image_info,image);
4246 (void) DeleteImageOption(image_info,"page");
4247 return(MagickTrue);
4248}
4249
4250MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4251 Image *image)
4252{
4253 char
4254 property[MaxTextExtent];
4255
4256 const char
cristy9a703812010-07-26 14:50:29 +00004257 *option,
4258 *value;
cristy1626d332009-11-10 16:58:17 +00004259
4260 GeometryInfo
4261 geometry_info;
4262
4263 MagickStatusType
4264 flags;
4265
cristy19eb6412010-04-23 14:42:29 +00004266 ResolutionType
4267 units;
4268
cristy1626d332009-11-10 16:58:17 +00004269 /*
4270 Sync image options.
4271 */
4272 assert(image_info != (const ImageInfo *) NULL);
4273 assert(image_info->signature == MagickSignature);
4274 assert(image != (Image *) NULL);
4275 assert(image->signature == MagickSignature);
4276 if (image->debug != MagickFalse)
4277 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4278 option=GetImageOption(image_info,"background");
4279 if (option != (const char *) NULL)
4280 (void) QueryColorDatabase(option,&image->background_color,
4281 &image->exception);
4282 option=GetImageOption(image_info,"bias");
4283 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004284 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004285 option=GetImageOption(image_info,"black-point-compensation");
4286 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004287 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004288 MagickBooleanOptions,MagickFalse,option);
4289 option=GetImageOption(image_info,"blue-primary");
4290 if (option != (const char *) NULL)
4291 {
4292 flags=ParseGeometry(option,&geometry_info);
4293 image->chromaticity.blue_primary.x=geometry_info.rho;
4294 image->chromaticity.blue_primary.y=geometry_info.sigma;
4295 if ((flags & SigmaValue) == 0)
4296 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4297 }
4298 option=GetImageOption(image_info,"bordercolor");
4299 if (option != (const char *) NULL)
4300 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4301 option=GetImageOption(image_info,"colors");
4302 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004303 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004304 option=GetImageOption(image_info,"compose");
4305 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004306 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004307 MagickFalse,option);
4308 option=GetImageOption(image_info,"compress");
4309 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004310 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004311 MagickCompressOptions,MagickFalse,option);
4312 option=GetImageOption(image_info,"debug");
4313 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004314 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004315 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004316 option=GetImageOption(image_info,"density");
4317 if (option != (const char *) NULL)
4318 {
4319 GeometryInfo
4320 geometry_info;
4321
4322 /*
4323 Set image density.
4324 */
4325 flags=ParseGeometry(option,&geometry_info);
4326 image->x_resolution=geometry_info.rho;
4327 image->y_resolution=geometry_info.sigma;
4328 if ((flags & SigmaValue) == 0)
4329 image->y_resolution=image->x_resolution;
4330 }
cristy1626d332009-11-10 16:58:17 +00004331 option=GetImageOption(image_info,"depth");
4332 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004333 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004334 option=GetImageOption(image_info,"endian");
4335 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004336 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004337 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004338 option=GetImageOption(image_info,"filter");
4339 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004340 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004341 MagickFalse,option);
4342 option=GetImageOption(image_info,"fuzz");
4343 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004344 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004345 option=GetImageOption(image_info,"gravity");
4346 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004347 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004348 MagickFalse,option);
4349 option=GetImageOption(image_info,"green-primary");
4350 if (option != (const char *) NULL)
4351 {
4352 flags=ParseGeometry(option,&geometry_info);
4353 image->chromaticity.green_primary.x=geometry_info.rho;
4354 image->chromaticity.green_primary.y=geometry_info.sigma;
4355 if ((flags & SigmaValue) == 0)
4356 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4357 }
4358 option=GetImageOption(image_info,"intent");
4359 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004360 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004361 MagickIntentOptions,MagickFalse,option);
4362 option=GetImageOption(image_info,"interlace");
4363 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004364 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004365 MagickFalse,option);
4366 option=GetImageOption(image_info,"interpolate");
4367 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004368 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004369 MagickInterpolateOptions,MagickFalse,option);
4370 option=GetImageOption(image_info,"loop");
4371 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004372 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004373 option=GetImageOption(image_info,"mattecolor");
4374 if (option != (const char *) NULL)
4375 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4376 option=GetImageOption(image_info,"orient");
4377 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004378 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004379 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004380 option=GetImageOption(image_info,"page");
4381 if (option != (const char *) NULL)
4382 {
4383 char
4384 *geometry;
4385
4386 geometry=GetPageGeometry(option);
4387 flags=ParseAbsoluteGeometry(geometry,&image->page);
4388 geometry=DestroyString(geometry);
4389 }
cristy1626d332009-11-10 16:58:17 +00004390 option=GetImageOption(image_info,"quality");
4391 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004392 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004393 option=GetImageOption(image_info,"red-primary");
4394 if (option != (const char *) NULL)
4395 {
4396 flags=ParseGeometry(option,&geometry_info);
4397 image->chromaticity.red_primary.x=geometry_info.rho;
4398 image->chromaticity.red_primary.y=geometry_info.sigma;
4399 if ((flags & SigmaValue) == 0)
4400 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4401 }
4402 if (image_info->quality != UndefinedCompressionQuality)
4403 image->quality=image_info->quality;
4404 option=GetImageOption(image_info,"scene");
4405 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004406 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004407 option=GetImageOption(image_info,"taint");
4408 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004409 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004410 MagickFalse,option);
4411 option=GetImageOption(image_info,"tile-offset");
4412 if (option != (const char *) NULL)
4413 {
4414 char
4415 *geometry;
4416
4417 geometry=GetPageGeometry(option);
4418 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4419 geometry=DestroyString(geometry);
4420 }
4421 option=GetImageOption(image_info,"transparent-color");
4422 if (option != (const char *) NULL)
4423 (void) QueryColorDatabase(option,&image->transparent_color,
4424 &image->exception);
4425 option=GetImageOption(image_info,"type");
4426 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004427 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004428 option);
4429 option=GetImageOption(image_info,"units");
4430 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004431 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004432 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004433 else
4434 units = image_info->units;
4435 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004436 {
cristy19eb6412010-04-23 14:42:29 +00004437 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004438 switch (image->units)
4439 {
4440 case PixelsPerInchResolution:
4441 {
cristy19eb6412010-04-23 14:42:29 +00004442 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004443 {
4444 image->x_resolution/=2.54;
4445 image->y_resolution/=2.54;
4446 }
4447 break;
4448 }
4449 case PixelsPerCentimeterResolution:
4450 {
cristy19eb6412010-04-23 14:42:29 +00004451 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004452 {
cristybb503372010-05-27 20:51:26 +00004453 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004454 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004455 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004456 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004457 }
4458 break;
4459 }
4460 default:
4461 break;
4462 }
cristy19eb6412010-04-23 14:42:29 +00004463 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004464 }
4465 option=GetImageOption(image_info,"white-point");
4466 if (option != (const char *) NULL)
4467 {
4468 flags=ParseGeometry(option,&geometry_info);
4469 image->chromaticity.white_point.x=geometry_info.rho;
4470 image->chromaticity.white_point.y=geometry_info.sigma;
4471 if ((flags & SigmaValue) == 0)
4472 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4473 }
4474 ResetImageOptionIterator(image_info);
4475 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4476 {
4477 value=GetImageOption(image_info,option);
4478 if (value != (const char *) NULL)
4479 {
cristyb51dff52011-05-19 16:55:47 +00004480 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004481 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004482 }
4483 option=GetNextImageOption(image_info);
4484 }
4485 return(MagickTrue);
4486}