blob: 97a8cc78064b356697b6e802ab3cd0f2ca4ceec1 [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%
cristy3139dc22011-07-08 00:11:42 +0000993% Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000994%
995% A description of each parameter follows:
996%
997% o image: the image.
998%
999% o exception: return any errors or warnings in this structure.
1000%
1001*/
cristy3139dc22011-07-08 00:11:42 +00001002MagickExport Image *CombineImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001003{
1004#define CombineImageTag "Combine/Image"
1005
1006 CacheView
1007 *combine_view;
1008
1009 const Image
1010 *next;
1011
1012 Image
1013 *combine_image;
1014
cristy3ed852e2009-09-05 21:47:34 +00001015 MagickBooleanType
1016 status;
1017
cristybb503372010-05-27 20:51:26 +00001018 MagickOffsetType
1019 progress;
1020
1021 ssize_t
1022 y;
1023
cristy3ed852e2009-09-05 21:47:34 +00001024 /*
1025 Ensure the image are the same size.
1026 */
1027 assert(image != (const Image *) NULL);
1028 assert(image->signature == MagickSignature);
1029 if (image->debug != MagickFalse)
1030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1031 assert(exception != (ExceptionInfo *) NULL);
1032 assert(exception->signature == MagickSignature);
1033 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1034 {
1035 if ((next->columns != image->columns) || (next->rows != image->rows))
1036 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1037 }
1038 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1039 if (combine_image == (Image *) NULL)
1040 return((Image *) NULL);
1041 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1042 {
1043 InheritException(exception,&combine_image->exception);
1044 combine_image=DestroyImage(combine_image);
1045 return((Image *) NULL);
1046 }
cristy2b9582a2011-07-04 17:38:56 +00001047 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001048 combine_image->matte=MagickTrue;
1049 (void) SetImageBackgroundColor(combine_image);
1050 /*
1051 Combine images.
1052 */
1053 status=MagickTrue;
1054 progress=0;
1055 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001056 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001057 {
1058 CacheView
1059 *image_view;
1060
1061 const Image
1062 *next;
1063
cristy4c08aed2011-07-01 19:47:50 +00001064 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001065 *pixels;
1066
cristy4c08aed2011-07-01 19:47:50 +00001067 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00001068 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001069
cristy4c08aed2011-07-01 19:47:50 +00001070 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001071 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001072
cristycb6d09b2010-06-19 01:59:36 +00001073 register ssize_t
1074 x;
1075
cristy3ed852e2009-09-05 21:47:34 +00001076 if (status == MagickFalse)
1077 continue;
1078 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1079 1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001080 if (pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001081 {
1082 status=MagickFalse;
1083 continue;
1084 }
1085 next=image;
cristy2b9582a2011-07-04 17:38:56 +00001086 if (((GetPixelRedTraits(image) & ActivePixelTrait) != 0) &&
1087 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001088 {
1089 image_view=AcquireCacheView(next);
1090 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001091 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001092 continue;
1093 q=pixels;
cristybb503372010-05-27 20:51:26 +00001094 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001095 {
cristy4c08aed2011-07-01 19:47:50 +00001096 SetPixelRed(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001097 p+=GetPixelComponents(image);
cristy3139dc22011-07-08 00:11:42 +00001098 q+=GetPixelComponents(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001099 }
1100 image_view=DestroyCacheView(image_view);
1101 next=GetNextImageInList(next);
1102 }
cristy2b9582a2011-07-04 17:38:56 +00001103 if (((GetPixelGreenTraits(image) & ActivePixelTrait) != 0) &&
1104 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001105 {
1106 image_view=AcquireCacheView(next);
1107 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001108 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001109 continue;
1110 q=pixels;
cristybb503372010-05-27 20:51:26 +00001111 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001112 {
cristy4c08aed2011-07-01 19:47:50 +00001113 SetPixelGreen(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001114 p+=GetPixelComponents(image);
cristy3139dc22011-07-08 00:11:42 +00001115 q+=GetPixelComponents(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001116 }
1117 image_view=DestroyCacheView(image_view);
1118 next=GetNextImageInList(next);
1119 }
cristy2b9582a2011-07-04 17:38:56 +00001120 if (((GetPixelBlueTraits(image) & ActivePixelTrait) != 0) &&
1121 (next != (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001122 {
1123 image_view=AcquireCacheView(next);
1124 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001125 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001126 continue;
1127 q=pixels;
cristybb503372010-05-27 20:51:26 +00001128 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001129 {
cristy4c08aed2011-07-01 19:47:50 +00001130 SetPixelBlue(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001131 p+=GetPixelComponents(image);
cristy3139dc22011-07-08 00:11:42 +00001132 q+=GetPixelComponents(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001133 }
1134 image_view=DestroyCacheView(image_view);
1135 next=GetNextImageInList(next);
1136 }
cristy2b9582a2011-07-04 17:38:56 +00001137 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +00001138 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1139 {
cristy3ed852e2009-09-05 21:47:34 +00001140 image_view=AcquireCacheView(next);
1141 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001142 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001143 continue;
cristy4c08aed2011-07-01 19:47:50 +00001144 q=pixels;
cristybb503372010-05-27 20:51:26 +00001145 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001146 {
cristy4c08aed2011-07-01 19:47:50 +00001147 SetPixelBlack(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001148 p+=GetPixelComponents(image);
cristy3139dc22011-07-08 00:11:42 +00001149 q+=GetPixelComponents(combine_image);
cristy4c08aed2011-07-01 19:47:50 +00001150 }
1151 image_view=DestroyCacheView(image_view);
1152 next=GetNextImageInList(next);
1153 }
cristy2b9582a2011-07-04 17:38:56 +00001154 if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
1155 (next != (Image *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00001156 {
1157 image_view=AcquireCacheView(next);
1158 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1159 if (p == (const Quantum *) NULL)
1160 continue;
1161 q=pixels;
1162 for (x=0; x < (ssize_t) combine_image->columns; x++)
1163 {
1164 SetPixelAlpha(image,GetPixelIntensity(image,p),q);
cristydcfc1ad2011-07-07 16:25:41 +00001165 p+=GetPixelComponents(image);
cristy3139dc22011-07-08 00:11:42 +00001166 q+=GetPixelComponents(combine_image);
cristy3ed852e2009-09-05 21:47:34 +00001167 }
1168 image_view=DestroyCacheView(image_view);
1169 next=GetNextImageInList(next);
1170 }
1171 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1172 status=MagickFalse;
1173 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1174 {
1175 MagickBooleanType
1176 proceed;
1177
cristy3ed852e2009-09-05 21:47:34 +00001178 proceed=SetImageProgress(image,CombineImageTag,progress++,
1179 combine_image->rows);
1180 if (proceed == MagickFalse)
1181 status=MagickFalse;
1182 }
1183 }
1184 combine_view=DestroyCacheView(combine_view);
1185 if (status == MagickFalse)
1186 combine_image=DestroyImage(combine_image);
1187 return(combine_image);
1188}
1189
1190/*
1191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192% %
1193% %
1194% %
cristy3ed852e2009-09-05 21:47:34 +00001195% D e s t r o y I m a g e %
1196% %
1197% %
1198% %
1199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200%
1201% DestroyImage() dereferences an image, deallocating memory associated with
1202% the image if the reference count becomes zero.
1203%
1204% The format of the DestroyImage method is:
1205%
1206% Image *DestroyImage(Image *image)
1207%
1208% A description of each parameter follows:
1209%
1210% o image: the image.
1211%
1212*/
1213MagickExport Image *DestroyImage(Image *image)
1214{
1215 MagickBooleanType
1216 destroy;
1217
1218 /*
1219 Dereference image.
1220 */
1221 assert(image != (Image *) NULL);
1222 assert(image->signature == MagickSignature);
1223 if (image->debug != MagickFalse)
1224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1225 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001226 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001227 image->reference_count--;
1228 if (image->reference_count == 0)
1229 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001230 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001231 if (destroy == MagickFalse)
1232 return((Image *) NULL);
1233 /*
1234 Destroy image.
1235 */
1236 DestroyImagePixels(image);
cristy4c08aed2011-07-01 19:47:50 +00001237 image->component_map=DestroyPixelComponentMap(image->component_map);
cristy3ed852e2009-09-05 21:47:34 +00001238 if (image->clip_mask != (Image *) NULL)
1239 image->clip_mask=DestroyImage(image->clip_mask);
1240 if (image->mask != (Image *) NULL)
1241 image->mask=DestroyImage(image->mask);
1242 if (image->montage != (char *) NULL)
1243 image->montage=DestroyString(image->montage);
1244 if (image->directory != (char *) NULL)
1245 image->directory=DestroyString(image->directory);
1246 if (image->colormap != (PixelPacket *) NULL)
1247 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1248 if (image->geometry != (char *) NULL)
1249 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001250 DestroyImageProfiles(image);
1251 DestroyImageProperties(image);
1252 DestroyImageArtifacts(image);
1253 if (image->ascii85 != (Ascii85Info*) NULL)
1254 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1255 DestroyBlob(image);
1256 (void) DestroyExceptionInfo(&image->exception);
1257 if (image->semaphore != (SemaphoreInfo *) NULL)
1258 DestroySemaphoreInfo(&image->semaphore);
1259 image->signature=(~MagickSignature);
1260 image=(Image *) RelinquishMagickMemory(image);
1261 return(image);
1262}
1263
1264/*
1265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266% %
1267% %
1268% %
1269% D e s t r o y I m a g e I n f o %
1270% %
1271% %
1272% %
1273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1274%
1275% DestroyImageInfo() deallocates memory associated with an ImageInfo
1276% structure.
1277%
1278% The format of the DestroyImageInfo method is:
1279%
1280% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1281%
1282% A description of each parameter follows:
1283%
1284% o image_info: the image info.
1285%
1286*/
1287MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1288{
1289 assert(image_info != (ImageInfo *) NULL);
1290 assert(image_info->signature == MagickSignature);
1291 if (image_info->debug != MagickFalse)
1292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1293 image_info->filename);
1294 if (image_info->size != (char *) NULL)
1295 image_info->size=DestroyString(image_info->size);
1296 if (image_info->extract != (char *) NULL)
1297 image_info->extract=DestroyString(image_info->extract);
1298 if (image_info->scenes != (char *) NULL)
1299 image_info->scenes=DestroyString(image_info->scenes);
1300 if (image_info->page != (char *) NULL)
1301 image_info->page=DestroyString(image_info->page);
1302 if (image_info->sampling_factor != (char *) NULL)
1303 image_info->sampling_factor=DestroyString(
1304 image_info->sampling_factor);
1305 if (image_info->server_name != (char *) NULL)
1306 image_info->server_name=DestroyString(
1307 image_info->server_name);
1308 if (image_info->font != (char *) NULL)
1309 image_info->font=DestroyString(image_info->font);
1310 if (image_info->texture != (char *) NULL)
1311 image_info->texture=DestroyString(image_info->texture);
1312 if (image_info->density != (char *) NULL)
1313 image_info->density=DestroyString(image_info->density);
1314 if (image_info->view != (char *) NULL)
1315 image_info->view=DestroyString(image_info->view);
1316 if (image_info->authenticate != (char *) NULL)
1317 image_info->authenticate=DestroyString(
1318 image_info->authenticate);
1319 DestroyImageOptions(image_info);
1320 if (image_info->cache != (void *) NULL)
1321 image_info->cache=DestroyPixelCache(image_info->cache);
1322 if (image_info->profile != (StringInfo *) NULL)
1323 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1324 image_info->profile);
1325 image_info->signature=(~MagickSignature);
1326 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1327 return(image_info);
1328}
1329
1330/*
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332% %
1333% %
1334% %
1335+ D i s a s s o c i a t e I m a g e S t r e a m %
1336% %
1337% %
1338% %
1339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340%
1341% DisassociateImageStream() disassociates the image stream.
1342%
1343% The format of the DisassociateImageStream method is:
1344%
1345% MagickBooleanType DisassociateImageStream(const Image *image)
1346%
1347% A description of each parameter follows:
1348%
1349% o image: the image.
1350%
1351*/
1352MagickExport void DisassociateImageStream(Image *image)
1353{
1354 assert(image != (const Image *) NULL);
1355 assert(image->signature == MagickSignature);
1356 if (image->debug != MagickFalse)
1357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1358 (void) DetachBlob(image->blob);
1359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
1366% G e t I m a g e A l p h a C h a n n e l %
1367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
1372% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1373% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1374% than CMYKA.
1375%
1376% The format of the GetImageAlphaChannel method is:
1377%
1378% MagickBooleanType GetImageAlphaChannel(const Image *image)
1379%
1380% A description of each parameter follows:
1381%
1382% o image: the image.
1383%
1384*/
1385MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1386{
1387 assert(image != (const Image *) NULL);
1388 if (image->debug != MagickFalse)
1389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1390 assert(image->signature == MagickSignature);
1391 return(image->matte);
1392}
1393
1394/*
1395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396% %
1397% %
1398% %
1399% G e t I m a g e C l i p M a s k %
1400% %
1401% %
1402% %
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404%
1405% GetImageClipMask() returns the clip path associated with the image.
1406%
1407% The format of the GetImageClipMask method is:
1408%
1409% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1410%
1411% A description of each parameter follows:
1412%
1413% o image: the image.
1414%
1415*/
1416MagickExport Image *GetImageClipMask(const Image *image,
1417 ExceptionInfo *exception)
1418{
1419 assert(image != (const Image *) NULL);
1420 if (image->debug != MagickFalse)
1421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1422 assert(image->signature == MagickSignature);
1423 if (image->clip_mask == (Image *) NULL)
1424 return((Image *) NULL);
1425 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1426}
1427
1428/*
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430% %
1431% %
1432% %
1433% G e t I m a g e E x c e p t i o n %
1434% %
1435% %
1436% %
1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438%
1439% GetImageException() traverses an image sequence and returns any
1440% error more severe than noted by the exception parameter.
1441%
1442% The format of the GetImageException method is:
1443%
1444% void GetImageException(Image *image,ExceptionInfo *exception)
1445%
1446% A description of each parameter follows:
1447%
1448% o image: Specifies a pointer to a list of one or more images.
1449%
1450% o exception: return the highest severity exception.
1451%
1452*/
1453MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1454{
1455 register Image
1456 *next;
1457
1458 assert(image != (Image *) NULL);
1459 assert(image->signature == MagickSignature);
1460 if (image->debug != MagickFalse)
1461 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1462 assert(exception != (ExceptionInfo *) NULL);
1463 assert(exception->signature == MagickSignature);
1464 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1465 {
1466 if (next->exception.severity == UndefinedException)
1467 continue;
1468 if (next->exception.severity > exception->severity)
1469 InheritException(exception,&next->exception);
1470 next->exception.severity=UndefinedException;
1471 }
1472}
1473
1474/*
1475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476% %
1477% %
1478% %
1479% G e t I m a g e I n f o %
1480% %
1481% %
1482% %
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484%
1485% GetImageInfo() initializes image_info to default values.
1486%
1487% The format of the GetImageInfo method is:
1488%
1489% void GetImageInfo(ImageInfo *image_info)
1490%
1491% A description of each parameter follows:
1492%
1493% o image_info: the image info.
1494%
1495*/
1496MagickExport void GetImageInfo(ImageInfo *image_info)
1497{
cristyd9a29192010-10-16 16:49:53 +00001498 const char
1499 *synchronize;
1500
cristy3ed852e2009-09-05 21:47:34 +00001501 ExceptionInfo
1502 *exception;
1503
1504 /*
1505 File and image dimension members.
1506 */
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1508 assert(image_info != (ImageInfo *) NULL);
1509 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1510 image_info->adjoin=MagickTrue;
1511 image_info->interlace=NoInterlace;
1512 image_info->channel=DefaultChannels;
1513 image_info->quality=UndefinedCompressionQuality;
1514 image_info->antialias=MagickTrue;
1515 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001516 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1517 if (synchronize != (const char *) NULL)
1518 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001519 exception=AcquireExceptionInfo();
1520 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1521 exception);
1522 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1523 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1524 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1525 exception);
1526 exception=DestroyExceptionInfo(exception);
1527 image_info->debug=IsEventLogging();
1528 image_info->signature=MagickSignature;
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
cristy15781e52009-12-05 23:05:27 +00001536% G e t I m a g e I n f o F i l e %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% GetImageInfoFile() returns the image info file member.
1543%
1544% The format of the GetImageInfoFile method is:
1545%
1546% FILE *GetImageInfoFile(const ImageInfo *image_info)
1547%
1548% A description of each parameter follows:
1549%
1550% o image_info: the image info.
1551%
1552*/
1553MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1554{
1555 return(image_info->file);
1556}
1557
1558/*
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560% %
1561% %
1562% %
cristy3ed852e2009-09-05 21:47:34 +00001563% G e t I m a g e M a s k %
1564% %
1565% %
1566% %
1567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568%
1569% GetImageMask() returns the mask associated with the image.
1570%
1571% The format of the GetImageMask method is:
1572%
1573% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1574%
1575% A description of each parameter follows:
1576%
1577% o image: the image.
1578%
1579*/
1580MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1581{
1582 assert(image != (const Image *) NULL);
1583 if (image->debug != MagickFalse)
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1585 assert(image->signature == MagickSignature);
1586 if (image->mask == (Image *) NULL)
1587 return((Image *) NULL);
1588 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ G e t I m a g e R e f e r e n c e C o u n t %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetImageReferenceCount() returns the image reference count.
1603%
1604% The format of the GetReferenceCount method is:
1605%
cristybb503372010-05-27 20:51:26 +00001606% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001607%
1608% A description of each parameter follows:
1609%
1610% o image: the image.
1611%
1612*/
cristybb503372010-05-27 20:51:26 +00001613MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001614{
cristybb503372010-05-27 20:51:26 +00001615 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001616 reference_count;
1617
1618 assert(image != (Image *) NULL);
1619 assert(image->signature == MagickSignature);
1620 if (image->debug != MagickFalse)
1621 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001622 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001623 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001624 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001625 return(reference_count);
1626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
cristy3ed852e2009-09-05 21:47:34 +00001633% 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 %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1640% image. A virtual pixel is any pixel access that is outside the boundaries
1641% of the image cache.
1642%
1643% The format of the GetImageVirtualPixelMethod() method is:
1644%
1645% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1646%
1647% A description of each parameter follows:
1648%
1649% o image: the image.
1650%
1651*/
1652MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1653{
1654 assert(image != (Image *) NULL);
1655 assert(image->signature == MagickSignature);
1656 if (image->debug != MagickFalse)
1657 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1658 return(GetPixelCacheVirtualMethod(image));
1659}
1660
1661/*
1662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1663% %
1664% %
1665% %
1666% I n t e r p r e t I m a g e F i l e n a m e %
1667% %
1668% %
1669% %
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671%
1672% InterpretImageFilename() interprets embedded characters in an image filename.
1673% The filename length is returned.
1674%
1675% The format of the InterpretImageFilename method is:
1676%
1677% size_t InterpretImageFilename(const ImageInfo *image_info,
1678% Image *image,const char *format,int value,char *filename)
1679%
1680% A description of each parameter follows.
1681%
1682% o image_info: the image info..
1683%
1684% o image: the image.
1685%
1686% o format: A filename describing the format to use to write the numeric
1687% argument. Only the first numeric format identifier is replaced.
1688%
1689% o value: Numeric value to substitute into format filename.
1690%
1691% o filename: return the formatted filename in this character buffer.
1692%
1693*/
1694MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1695 Image *image,const char *format,int value,char *filename)
1696{
1697 char
1698 *q;
1699
1700 int
1701 c;
1702
1703 MagickBooleanType
1704 canonical;
1705
1706 register const char
1707 *p;
1708
1709 canonical=MagickFalse;
1710 (void) CopyMagickString(filename,format,MaxTextExtent);
1711 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1712 {
1713 q=(char *) p+1;
1714 if (*q == '%')
1715 {
1716 p=q+1;
1717 continue;
1718 }
1719 if (*q == '0')
1720 {
cristybb503372010-05-27 20:51:26 +00001721 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001722 value;
1723
cristybb503372010-05-27 20:51:26 +00001724 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001725 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001726 }
1727 switch (*q)
1728 {
1729 case 'd':
1730 case 'o':
1731 case 'x':
1732 {
1733 q++;
1734 c=(*q);
1735 *q='\0';
cristyb51dff52011-05-19 16:55:47 +00001736 (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
cristy3ed852e2009-09-05 21:47:34 +00001737 (p-format)),p,value);
1738 *q=c;
1739 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1740 canonical=MagickTrue;
1741 if (*(q-1) != '%')
1742 break;
1743 p++;
1744 break;
1745 }
1746 case '[':
1747 {
1748 char
1749 pattern[MaxTextExtent];
1750
1751 const char
1752 *value;
1753
cristy3ed852e2009-09-05 21:47:34 +00001754 register char
1755 *r;
1756
cristybb503372010-05-27 20:51:26 +00001757 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001758 i;
1759
cristycb6d09b2010-06-19 01:59:36 +00001760 ssize_t
1761 depth;
1762
cristy3ed852e2009-09-05 21:47:34 +00001763 /*
1764 Image option.
1765 */
1766 if (strchr(p,']') == (char *) NULL)
1767 break;
1768 depth=1;
1769 r=q+1;
1770 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1771 {
1772 if (*r == '[')
1773 depth++;
1774 if (*r == ']')
1775 depth--;
1776 if (depth <= 0)
1777 break;
1778 pattern[i]=(*r++);
1779 }
1780 pattern[i]='\0';
1781 if (LocaleNCompare(pattern,"filename:",9) != 0)
1782 break;
1783 value=(const char *) NULL;
1784 if ((image_info != (const ImageInfo *) NULL) &&
1785 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001786 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001787 else
1788 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001789 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001790 else
1791 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001792 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001793 if (value == (const char *) NULL)
1794 break;
1795 q--;
1796 c=(*q);
1797 *q='\0';
1798 (void) CopyMagickString(filename+(p-format),value,(size_t)
1799 (MaxTextExtent-(p-format)));
1800 *q=c;
1801 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1802 canonical=MagickTrue;
1803 if (*(q-1) != '%')
1804 break;
1805 p++;
1806 break;
1807 }
1808 default:
1809 break;
1810 }
1811 }
1812 for (q=filename; *q != '\0'; q++)
1813 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001814 {
1815 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1816 canonical=MagickTrue;
1817 }
cristy3ed852e2009-09-05 21:47:34 +00001818 if (canonical == MagickFalse)
1819 (void) CopyMagickString(filename,format,MaxTextExtent);
1820 return(strlen(filename));
1821}
1822
1823/*
1824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1825% %
1826% %
1827% %
1828% I s H i g h D y n a m i c R a n g e I m a g e %
1829% %
1830% %
1831% %
1832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833%
1834% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1835% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1836% 0..65535.
1837%
1838% The format of the IsHighDynamicRangeImage method is:
1839%
1840% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1841% ExceptionInfo *exception)
1842%
1843% A description of each parameter follows:
1844%
1845% o image: the image.
1846%
1847% o exception: return any errors or warnings in this structure.
1848%
1849*/
1850MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1851 ExceptionInfo *exception)
1852{
1853#if !defined(MAGICKCORE_HDRI_SUPPORT)
1854 (void) image;
1855 (void) exception;
1856 return(MagickFalse);
1857#else
1858 CacheView
1859 *image_view;
1860
cristy3ed852e2009-09-05 21:47:34 +00001861 MagickBooleanType
1862 status;
1863
cristy4c08aed2011-07-01 19:47:50 +00001864 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001865 zero;
1866
cristycb6d09b2010-06-19 01:59:36 +00001867 ssize_t
1868 y;
1869
cristy3ed852e2009-09-05 21:47:34 +00001870 assert(image != (Image *) NULL);
1871 assert(image->signature == MagickSignature);
1872 if (image->debug != MagickFalse)
1873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1874 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00001875 GetPixelInfo(image,&zero);
cristy3ed852e2009-09-05 21:47:34 +00001876 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001877#if defined(MAGICKCORE_OPENMP_SUPPORT)
1878 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001879#endif
cristybb503372010-05-27 20:51:26 +00001880 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001881 {
cristy4c08aed2011-07-01 19:47:50 +00001882 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00001883 pixel;
1884
cristy4c08aed2011-07-01 19:47:50 +00001885 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001886 *p;
1887
cristybb503372010-05-27 20:51:26 +00001888 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001889 x;
1890
1891 if (status == MagickFalse)
1892 continue;
1893 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001894 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001895 {
1896 status=MagickFalse;
1897 continue;
1898 }
cristy3ed852e2009-09-05 21:47:34 +00001899 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001900 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001901 {
cristy4c08aed2011-07-01 19:47:50 +00001902 SetPixelInfo(image,p,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00001903 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1904 (pixel.red != (QuantumAny) pixel.red))
1905 break;
1906 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1907 (pixel.green != (QuantumAny) pixel.green))
1908 break;
1909 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1910 (pixel.blue != (QuantumAny) pixel.blue))
1911 break;
cristy3ed852e2009-09-05 21:47:34 +00001912 if (pixel.colorspace == CMYKColorspace)
1913 {
cristy4c08aed2011-07-01 19:47:50 +00001914 if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
1915 (pixel.black != (QuantumAny) pixel.black))
cristy3ed852e2009-09-05 21:47:34 +00001916 break;
1917 }
cristy4c08aed2011-07-01 19:47:50 +00001918 if (pixel.matte != MagickFalse)
1919 {
1920 if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
1921 (pixel.alpha != (QuantumAny) pixel.alpha))
1922 break;
1923 }
cristydcfc1ad2011-07-07 16:25:41 +00001924 p+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00001925 }
cristybb503372010-05-27 20:51:26 +00001926 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001927 status=MagickFalse;
1928 }
1929 image_view=DestroyCacheView(image_view);
1930 return(status != MagickFalse ? MagickFalse : MagickTrue);
1931#endif
1932}
1933
1934/*
1935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1936% %
1937% %
1938% %
1939% I s I m a g e O b j e c t %
1940% %
1941% %
1942% %
1943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944%
1945% IsImageObject() returns MagickTrue if the image sequence contains a valid
1946% set of image objects.
1947%
1948% The format of the IsImageObject method is:
1949%
1950% MagickBooleanType IsImageObject(const Image *image)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956*/
1957MagickExport MagickBooleanType IsImageObject(const Image *image)
1958{
1959 register const Image
1960 *p;
1961
1962 assert(image != (Image *) NULL);
1963 if (image->debug != MagickFalse)
1964 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1965 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1966 if (p->signature != MagickSignature)
1967 return(MagickFalse);
1968 return(MagickTrue);
1969}
1970
1971/*
1972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973% %
1974% %
1975% %
1976% I s T a i n t I m a g e %
1977% %
1978% %
1979% %
1980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981%
1982% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1983% since it was first constituted.
1984%
1985% The format of the IsTaintImage method is:
1986%
1987% MagickBooleanType IsTaintImage(const Image *image)
1988%
1989% A description of each parameter follows:
1990%
1991% o image: the image.
1992%
1993*/
1994MagickExport MagickBooleanType IsTaintImage(const Image *image)
1995{
1996 char
1997 magick[MaxTextExtent],
1998 filename[MaxTextExtent];
1999
2000 register const Image
2001 *p;
2002
2003 assert(image != (Image *) NULL);
2004 if (image->debug != MagickFalse)
2005 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2006 assert(image->signature == MagickSignature);
2007 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2008 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2009 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2010 {
2011 if (p->taint != MagickFalse)
2012 return(MagickTrue);
2013 if (LocaleCompare(p->magick,magick) != 0)
2014 return(MagickTrue);
2015 if (LocaleCompare(p->filename,filename) != 0)
2016 return(MagickTrue);
2017 }
2018 return(MagickFalse);
2019}
2020
2021/*
2022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023% %
2024% %
2025% %
2026% M o d i f y I m a g e %
2027% %
2028% %
2029% %
2030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2031%
2032% ModifyImage() ensures that there is only a single reference to the image
2033% to be modified, updating the provided image pointer to point to a clone of
2034% the original image if necessary.
2035%
2036% The format of the ModifyImage method is:
2037%
2038% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2039%
2040% A description of each parameter follows:
2041%
2042% o image: the image.
2043%
2044% o exception: return any errors or warnings in this structure.
2045%
2046*/
2047MagickExport MagickBooleanType ModifyImage(Image **image,
2048 ExceptionInfo *exception)
2049{
2050 Image
2051 *clone_image;
2052
2053 assert(image != (Image **) NULL);
2054 assert(*image != (Image *) NULL);
2055 assert((*image)->signature == MagickSignature);
2056 if ((*image)->debug != MagickFalse)
2057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2058 if (GetImageReferenceCount(*image) <= 1)
2059 return(MagickTrue);
2060 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002061 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002062 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002063 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002064 *image=clone_image;
2065 return(MagickTrue);
2066}
2067
2068/*
2069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2070% %
2071% %
2072% %
2073% N e w M a g i c k I m a g e %
2074% %
2075% %
2076% %
2077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078%
2079% NewMagickImage() creates a blank image canvas of the specified size and
2080% background color.
2081%
2082% The format of the NewMagickImage method is:
2083%
2084% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002085% const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002086% const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002087%
2088% A description of each parameter follows:
2089%
2090% o image: the image.
2091%
2092% o width: the image width.
2093%
2094% o height: the image height.
2095%
2096% o background: the image color.
2097%
2098*/
2099MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002100 const size_t width,const size_t height,
cristy4c08aed2011-07-01 19:47:50 +00002101 const PixelInfo *background)
cristy3ed852e2009-09-05 21:47:34 +00002102{
2103 CacheView
2104 *image_view;
2105
2106 ExceptionInfo
2107 *exception;
2108
2109 Image
2110 *image;
2111
cristybb503372010-05-27 20:51:26 +00002112 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002113 y;
2114
2115 MagickBooleanType
2116 status;
2117
2118 assert(image_info != (const ImageInfo *) NULL);
2119 if (image_info->debug != MagickFalse)
2120 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2121 assert(image_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002122 assert(background != (const PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002123 image=AcquireImage(image_info);
2124 image->columns=width;
2125 image->rows=height;
2126 image->colorspace=background->colorspace;
2127 image->matte=background->matte;
2128 image->fuzz=background->fuzz;
2129 image->depth=background->depth;
2130 status=MagickTrue;
2131 exception=(&image->exception);
2132 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002133#if defined(MAGICKCORE_OPENMP_SUPPORT)
2134 #pragma omp parallel for schedule(dynamic,4) shared(status)
2135#endif
cristybb503372010-05-27 20:51:26 +00002136 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002137 {
cristy4c08aed2011-07-01 19:47:50 +00002138 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002139 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002140
cristycb6d09b2010-06-19 01:59:36 +00002141 register ssize_t
2142 x;
2143
cristy48974b92009-12-19 02:36:06 +00002144 if (status == MagickFalse)
2145 continue;
cristy3ed852e2009-09-05 21:47:34 +00002146 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002147 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002148 {
2149 status=MagickFalse;
2150 continue;
2151 }
cristybb503372010-05-27 20:51:26 +00002152 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002153 {
cristy4c08aed2011-07-01 19:47:50 +00002154 SetPixelPixelInfo(image,background,q);
cristydcfc1ad2011-07-07 16:25:41 +00002155 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002156 }
2157 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2158 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002159 }
2160 image_view=DestroyCacheView(image_view);
2161 if (status == MagickFalse)
2162 image=DestroyImage(image);
2163 return(image);
2164}
2165
2166/*
2167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2168% %
2169% %
2170% %
2171% R e f e r e n c e I m a g e %
2172% %
2173% %
2174% %
2175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176%
2177% ReferenceImage() increments the reference count associated with an image
2178% returning a pointer to the image.
2179%
2180% The format of the ReferenceImage method is:
2181%
2182% Image *ReferenceImage(Image *image)
2183%
2184% A description of each parameter follows:
2185%
2186% o image: the image.
2187%
2188*/
2189MagickExport Image *ReferenceImage(Image *image)
2190{
2191 assert(image != (Image *) NULL);
2192 if (image->debug != MagickFalse)
2193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2194 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002195 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002196 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002197 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002198 return(image);
2199}
2200
2201/*
2202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203% %
2204% %
2205% %
2206% R e s e t I m a g e P a g e %
2207% %
2208% %
2209% %
2210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211%
2212% ResetImagePage() resets the image page canvas and position.
2213%
2214% The format of the ResetImagePage method is:
2215%
2216% MagickBooleanType ResetImagePage(Image *image,const char *page)
2217%
2218% A description of each parameter follows:
2219%
2220% o image: the image.
2221%
2222% o page: the relative page specification.
2223%
2224*/
2225MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2226{
2227 MagickStatusType
2228 flags;
2229
2230 RectangleInfo
2231 geometry;
2232
2233 assert(image != (Image *) NULL);
2234 assert(image->signature == MagickSignature);
2235 if (image->debug != MagickFalse)
2236 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2237 flags=ParseAbsoluteGeometry(page,&geometry);
2238 if ((flags & WidthValue) != 0)
2239 {
2240 if ((flags & HeightValue) == 0)
2241 geometry.height=geometry.width;
2242 image->page.width=geometry.width;
2243 image->page.height=geometry.height;
2244 }
2245 if ((flags & AspectValue) != 0)
2246 {
2247 if ((flags & XValue) != 0)
2248 image->page.x+=geometry.x;
2249 if ((flags & YValue) != 0)
2250 image->page.y+=geometry.y;
2251 }
2252 else
2253 {
2254 if ((flags & XValue) != 0)
2255 {
2256 image->page.x=geometry.x;
2257 if ((image->page.width == 0) && (geometry.x > 0))
2258 image->page.width=image->columns+geometry.x;
2259 }
2260 if ((flags & YValue) != 0)
2261 {
2262 image->page.y=geometry.y;
2263 if ((image->page.height == 0) && (geometry.y > 0))
2264 image->page.height=image->rows+geometry.y;
2265 }
2266 }
2267 return(MagickTrue);
2268}
2269
2270/*
2271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272% %
2273% %
2274% %
2275% S e p a r a t e I m a g e C h a n n e l %
2276% %
2277% %
2278% %
2279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280%
cristy3139dc22011-07-08 00:11:42 +00002281% SeparateImage() separates a channel from the image and returns it as
cristy3ed852e2009-09-05 21:47:34 +00002282% a grayscale image. A channel is a particular color component of each pixel
2283% in the image.
2284%
cristy3139dc22011-07-08 00:11:42 +00002285% The format of the SeparateImage method is:
cristy3ed852e2009-09-05 21:47:34 +00002286%
cristy3139dc22011-07-08 00:11:42 +00002287% MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002288%
2289% A description of each parameter follows:
2290%
2291% o image: the image.
2292%
cristy3ed852e2009-09-05 21:47:34 +00002293*/
cristy3139dc22011-07-08 00:11:42 +00002294MagickExport MagickBooleanType SeparateImage(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002295{
2296#define SeparateImageTag "Separate/Image"
2297
2298 CacheView
2299 *image_view;
2300
2301 ExceptionInfo
2302 *exception;
2303
cristy3ed852e2009-09-05 21:47:34 +00002304 MagickBooleanType
2305 status;
2306
cristybb503372010-05-27 20:51:26 +00002307 MagickOffsetType
2308 progress;
2309
2310 ssize_t
2311 y;
2312
cristy3ed852e2009-09-05 21:47:34 +00002313 assert(image != (Image *) NULL);
2314 assert(image->signature == MagickSignature);
2315 if (image->debug != MagickFalse)
2316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2317 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2318 return(MagickFalse);
2319 /*
2320 Separate image channels.
2321 */
2322 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002323 progress=0;
2324 exception=(&image->exception);
2325 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002326#if defined(MAGICKCORE_OPENMP_SUPPORT)
2327 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002328#endif
cristybb503372010-05-27 20:51:26 +00002329 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002330 {
cristy4c08aed2011-07-01 19:47:50 +00002331 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002332 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002333
cristycb6d09b2010-06-19 01:59:36 +00002334 register ssize_t
2335 x;
2336
cristy3ed852e2009-09-05 21:47:34 +00002337 if (status == MagickFalse)
2338 continue;
2339 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002340 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002341 {
2342 status=MagickFalse;
2343 continue;
2344 }
cristy3139dc22011-07-08 00:11:42 +00002345 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002346 {
cristy3139dc22011-07-08 00:11:42 +00002347 if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002348 {
cristy4c08aed2011-07-01 19:47:50 +00002349 SetPixelGreen(image,GetPixelRed(image,q),q);
2350 SetPixelBlue(image,GetPixelRed(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002351 }
cristy3139dc22011-07-08 00:11:42 +00002352 if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002353 {
cristy4c08aed2011-07-01 19:47:50 +00002354 SetPixelRed(image,GetPixelGreen(image,q),q);
2355 SetPixelBlue(image,GetPixelGreen(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002356 }
cristy3139dc22011-07-08 00:11:42 +00002357 if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002358 {
cristy4c08aed2011-07-01 19:47:50 +00002359 SetPixelRed(image,GetPixelBlue(image,q),q);
2360 SetPixelGreen(image,GetPixelBlue(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002361 }
cristy3139dc22011-07-08 00:11:42 +00002362 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
2363 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002364 {
cristy4c08aed2011-07-01 19:47:50 +00002365 SetPixelRed(image,GetPixelBlack(image,q),q);
2366 SetPixelGreen(image,GetPixelBlack(image,q),q);
2367 SetPixelBlue(image,GetPixelBlack(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002368 }
cristy3139dc22011-07-08 00:11:42 +00002369 if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
2370 (image->matte != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002371 {
cristy4c08aed2011-07-01 19:47:50 +00002372 SetPixelRed(image,GetPixelAlpha(image,q),q);
2373 SetPixelGreen(image,GetPixelAlpha(image,q),q);
2374 SetPixelBlue(image,GetPixelAlpha(image,q),q);
cristy3ed852e2009-09-05 21:47:34 +00002375 }
cristy3139dc22011-07-08 00:11:42 +00002376 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002377 }
2378 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2379 status=MagickFalse;
2380 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2381 {
2382 MagickBooleanType
2383 proceed;
2384
cristyb5d5f722009-11-04 03:03:49 +00002385#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3139dc22011-07-08 00:11:42 +00002386 #pragma omp critical (MagickCore_SeparateImage)
cristy3ed852e2009-09-05 21:47:34 +00002387#endif
2388 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2389 if (proceed == MagickFalse)
2390 status=MagickFalse;
2391 }
2392 }
2393 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00002394 (void) SetImageColorspace(image,RGBColorspace);
2395 return(status);
2396}
2397
2398/*
2399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400% %
2401% %
2402% %
2403% S e p a r a t e I m a g e s %
2404% %
2405% %
2406% %
2407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408%
2409% SeparateImages() returns a separate grayscale image for each channel
2410% specified.
2411%
2412% The format of the SeparateImages method is:
2413%
2414% MagickBooleanType SeparateImages(const Image *image,
cristy3139dc22011-07-08 00:11:42 +00002415% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002416%
2417% A description of each parameter follows:
2418%
2419% o image: the image.
2420%
cristy3ed852e2009-09-05 21:47:34 +00002421% o exception: return any errors or warnings in this structure.
2422%
2423*/
cristy3139dc22011-07-08 00:11:42 +00002424MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002425{
2426 Image
2427 *images,
2428 *separate_image;
2429
2430 assert(image != (Image *) NULL);
2431 assert(image->signature == MagickSignature);
2432 if (image->debug != MagickFalse)
2433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2434 images=NewImageList();
cristy2b9582a2011-07-04 17:38:56 +00002435 if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002436 {
2437 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3139dc22011-07-08 00:11:42 +00002438 PushPixelComponentMap(separate_image,RedChannel);
2439 (void) SeparateImage(separate_image);
2440 PopPixelComponentMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002441 AppendImageToList(&images,separate_image);
2442 }
cristy2b9582a2011-07-04 17:38:56 +00002443 if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002444 {
2445 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3139dc22011-07-08 00:11:42 +00002446 PushPixelComponentMap(separate_image,GreenChannel);
2447 (void) SeparateImage(separate_image);
2448 PopPixelComponentMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002449 AppendImageToList(&images,separate_image);
2450 }
cristy2b9582a2011-07-04 17:38:56 +00002451 if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002452 {
2453 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3139dc22011-07-08 00:11:42 +00002454 PushPixelComponentMap(separate_image,BlueChannel);
2455 (void) SeparateImage(separate_image);
2456 PopPixelComponentMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002457 AppendImageToList(&images,separate_image);
2458 }
cristy3139dc22011-07-08 00:11:42 +00002459 if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
2460 (image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +00002461 {
2462 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3139dc22011-07-08 00:11:42 +00002463 PushPixelComponentMap(separate_image,BlackChannel);
2464 (void) SeparateImage(separate_image);
2465 PopPixelComponentMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002466 AppendImageToList(&images,separate_image);
2467 }
cristy2b9582a2011-07-04 17:38:56 +00002468 if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
cristy3ed852e2009-09-05 21:47:34 +00002469 {
2470 separate_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3139dc22011-07-08 00:11:42 +00002471 PushPixelComponentMap(separate_image,AlphaChannel);
2472 (void) SeparateImage(separate_image);
2473 PopPixelComponentMap(separate_image);
cristy3ed852e2009-09-05 21:47:34 +00002474 AppendImageToList(&images,separate_image);
2475 }
2476 return(images);
2477}
2478
2479/*
2480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2481% %
2482% %
2483% %
2484% S e t I m a g e A l p h a C h a n n e l %
2485% %
2486% %
2487% %
2488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2489%
2490% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2491% channel.
2492%
2493% The format of the SetImageAlphaChannel method is:
2494%
2495% MagickBooleanType SetImageAlphaChannel(Image *image,
2496% const AlphaChannelType alpha_type)
2497%
2498% A description of each parameter follows:
2499%
2500% o image: the image.
2501%
2502% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2503% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
cristy4c08aed2011-07-01 19:47:50 +00002504% OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
2505% TransparentAlphaChannel.
cristy3ed852e2009-09-05 21:47:34 +00002506%
2507*/
2508MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2509 const AlphaChannelType alpha_type)
2510{
2511 MagickBooleanType
2512 status;
2513
2514 assert(image != (Image *) NULL);
2515 if (image->debug != MagickFalse)
2516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2517 assert(image->signature == MagickSignature);
2518 status=MagickFalse;
2519 switch (alpha_type)
2520 {
2521 case ActivateAlphaChannel:
2522 {
2523 image->matte=MagickTrue;
2524 break;
2525 }
2526 case BackgroundAlphaChannel:
2527 {
2528 CacheView
2529 *image_view;
2530
2531 ExceptionInfo
2532 *exception;
2533
cristy3ed852e2009-09-05 21:47:34 +00002534 MagickBooleanType
2535 status;
2536
cristy4c08aed2011-07-01 19:47:50 +00002537 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002538 background;
2539
2540 PixelPacket
2541 pixel;
2542
cristycb6d09b2010-06-19 01:59:36 +00002543 ssize_t
2544 y;
2545
cristy3ed852e2009-09-05 21:47:34 +00002546 /*
2547 Set transparent pixels to background color.
2548 */
2549 if (image->matte == MagickFalse)
2550 break;
2551 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2552 break;
cristy4c08aed2011-07-01 19:47:50 +00002553 GetPixelInfo(image,&background);
2554 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002555 if (image->colorspace == CMYKColorspace)
2556 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002557 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002558 status=MagickTrue;
2559 exception=(&image->exception);
2560 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002561 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2562 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002563 #endif
cristybb503372010-05-27 20:51:26 +00002564 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002565 {
cristy4c08aed2011-07-01 19:47:50 +00002566 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002567 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002568
cristycb6d09b2010-06-19 01:59:36 +00002569 register ssize_t
2570 x;
2571
cristy3ed852e2009-09-05 21:47:34 +00002572 if (status == MagickFalse)
2573 continue;
2574 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2575 exception);
cristy4c08aed2011-07-01 19:47:50 +00002576 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002577 {
2578 status=MagickFalse;
2579 continue;
2580 }
cristybb503372010-05-27 20:51:26 +00002581 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002582 {
cristy4c08aed2011-07-01 19:47:50 +00002583 if (GetPixelAlpha(image,q) == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002584 {
cristy4c08aed2011-07-01 19:47:50 +00002585 SetPixelRed(image,pixel.red,q);
2586 SetPixelGreen(image,pixel.green,q);
2587 SetPixelBlue(image,pixel.blue,q);
2588 if (image->colorspace == CMYKColorspace)
2589 SetPixelBlack(image,pixel.black,q);
cristy3ed852e2009-09-05 21:47:34 +00002590 }
cristydcfc1ad2011-07-07 16:25:41 +00002591 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00002592 }
cristy3ed852e2009-09-05 21:47:34 +00002593 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2594 status=MagickFalse;
2595 }
2596 image_view=DestroyCacheView(image_view);
2597 return(status);
2598 }
2599 case DeactivateAlphaChannel:
2600 {
2601 image->matte=MagickFalse;
2602 break;
2603 }
2604 case ShapeAlphaChannel:
2605 case CopyAlphaChannel:
2606 {
2607 /*
cristy3139dc22011-07-08 00:11:42 +00002608 Special usage case for SeparateImage(): copy grayscale color to
cristy3ed852e2009-09-05 21:47:34 +00002609 the alpha channel.
2610 */
cristy3139dc22011-07-08 00:11:42 +00002611 PushPixelComponentMap(image,GrayChannel);
2612 status=SeparateImage(image);
2613 PopPixelComponentMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002614 image->matte=MagickTrue; /* make sure transparency is now on! */
2615 if (alpha_type == ShapeAlphaChannel)
2616 {
cristy4c08aed2011-07-01 19:47:50 +00002617 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002618 background;
2619
2620 /*
2621 Reset all color channels to background color.
2622 */
cristy4c08aed2011-07-01 19:47:50 +00002623 GetPixelInfo(image,&background);
2624 SetPixelInfoPacket(image,&(image->background_color),&background);
cristy490408a2011-07-07 14:42:05 +00002625 (void) LevelImageColors(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002626 }
2627 break;
2628 }
2629 case ExtractAlphaChannel:
2630 {
cristy3139dc22011-07-08 00:11:42 +00002631 PushPixelComponentMap(image,AlphaChannel);
2632 status=SeparateImage(image);
2633 PopPixelComponentMap(image);
cristy3ed852e2009-09-05 21:47:34 +00002634 image->matte=MagickFalse;
2635 break;
2636 }
cristy3ed852e2009-09-05 21:47:34 +00002637 case OpaqueAlphaChannel:
2638 {
cristy4c08aed2011-07-01 19:47:50 +00002639 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002640 image->matte=MagickTrue;
2641 break;
2642 }
2643 case TransparentAlphaChannel:
2644 {
cristy4c08aed2011-07-01 19:47:50 +00002645 status=SetImageOpacity(image,TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002646 image->matte=MagickTrue;
2647 break;
2648 }
2649 case SetAlphaChannel:
2650 {
2651 if (image->matte == MagickFalse)
2652 {
cristy4c08aed2011-07-01 19:47:50 +00002653 status=SetImageOpacity(image,OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00002654 image->matte=MagickTrue;
2655 }
2656 break;
2657 }
2658 case UndefinedAlphaChannel:
2659 break;
2660 }
2661 return(status);
2662}
2663
2664/*
2665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2666% %
2667% %
2668% %
2669% S e t I m a g e B a c k g r o u n d C o l o r %
2670% %
2671% %
2672% %
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674%
2675% SetImageBackgroundColor() initializes the image pixels to the image
2676% background color. The background color is defined by the background_color
2677% member of the image structure.
2678%
2679% The format of the SetImage method is:
2680%
2681% MagickBooleanType SetImageBackgroundColor(Image *image)
2682%
2683% A description of each parameter follows:
2684%
2685% o image: the image.
2686%
2687*/
2688MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2689{
2690 CacheView
2691 *image_view;
2692
2693 ExceptionInfo
2694 *exception;
2695
cristy3ed852e2009-09-05 21:47:34 +00002696 MagickBooleanType
2697 status;
2698
cristy4c08aed2011-07-01 19:47:50 +00002699 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00002700 background;
2701
2702 PixelPacket
2703 pixel;
2704
cristycb6d09b2010-06-19 01:59:36 +00002705 ssize_t
2706 y;
2707
cristy3ed852e2009-09-05 21:47:34 +00002708 assert(image != (Image *) NULL);
2709 if (image->debug != MagickFalse)
2710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2711 assert(image->signature == MagickSignature);
2712 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2713 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002714 if (image->background_color.alpha != OpaqueAlpha)
cristy3ed852e2009-09-05 21:47:34 +00002715 image->matte=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002716 GetPixelInfo(image,&background);
2717 SetPixelInfoPacket(image,&image->background_color,&background);
cristy3ed852e2009-09-05 21:47:34 +00002718 if (image->colorspace == CMYKColorspace)
2719 ConvertRGBToCMYK(&background);
cristy4c08aed2011-07-01 19:47:50 +00002720 SetPacketPixelInfo(image,&background,&pixel);
cristy3ed852e2009-09-05 21:47:34 +00002721 /*
2722 Set image background color.
2723 */
2724 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00002725 pixel.black=0;
cristy3ed852e2009-09-05 21:47:34 +00002726 exception=(&image->exception);
2727 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002728 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002729 {
cristy4c08aed2011-07-01 19:47:50 +00002730 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00002731 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002732
cristycb6d09b2010-06-19 01:59:36 +00002733 register ssize_t
2734 x;
2735
cristy3ed852e2009-09-05 21:47:34 +00002736 if (status == MagickFalse)
2737 continue;
2738 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002739 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002740 {
2741 status=MagickFalse;
2742 continue;
2743 }
cristybb503372010-05-27 20:51:26 +00002744 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002745 {
2746 SetPixelPacket(image,&pixel,q);
2747 if (image->colorspace == CMYKColorspace)
2748 SetPixelBlack(image,pixel.black,q);
cristydcfc1ad2011-07-07 16:25:41 +00002749 q+=GetPixelComponents(image);
cristy4c08aed2011-07-01 19:47:50 +00002750 }
cristy3ed852e2009-09-05 21:47:34 +00002751 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2752 status=MagickFalse;
2753 }
2754 image_view=DestroyCacheView(image_view);
2755 return(status);
2756}
2757
2758/*
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760% %
2761% %
2762% %
cristya5b77cb2010-05-07 19:34:48 +00002763% S e t I m a g e C o l o r %
2764% %
2765% %
2766% %
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768%
2769% SetImageColor() set the entire image canvas to the specified color.
2770%
2771% The format of the SetImageColor method is:
2772%
2773% MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002774% const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002775%
2776% A description of each parameter follows:
2777%
2778% o image: the image.
2779%
2780% o background: the image color.
2781%
2782*/
2783MagickExport MagickBooleanType SetImageColor(Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002784 const PixelInfo *color)
cristya5b77cb2010-05-07 19:34:48 +00002785{
2786 CacheView
2787 *image_view;
2788
2789 ExceptionInfo
2790 *exception;
2791
cristya5b77cb2010-05-07 19:34:48 +00002792 MagickBooleanType
2793 status;
2794
cristycb6d09b2010-06-19 01:59:36 +00002795 ssize_t
2796 y;
2797
cristya5b77cb2010-05-07 19:34:48 +00002798 assert(image != (Image *) NULL);
2799 if (image->debug != MagickFalse)
2800 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2801 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002802 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002803 image->colorspace=color->colorspace;
2804 image->matte=color->matte;
2805 image->fuzz=color->fuzz;
2806 image->depth=color->depth;
2807 status=MagickTrue;
2808 exception=(&image->exception);
2809 image_view=AcquireCacheView(image);
2810#if defined(MAGICKCORE_OPENMP_SUPPORT)
2811 #pragma omp parallel for schedule(dynamic,4) shared(status)
2812#endif
cristybb503372010-05-27 20:51:26 +00002813 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002814 {
cristy4c08aed2011-07-01 19:47:50 +00002815 register Quantum
cristya5b77cb2010-05-07 19:34:48 +00002816 *restrict q;
2817
cristycb6d09b2010-06-19 01:59:36 +00002818 register ssize_t
2819 x;
2820
cristya5b77cb2010-05-07 19:34:48 +00002821 if (status == MagickFalse)
2822 continue;
2823 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002824 if (q == (const Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002825 {
2826 status=MagickFalse;
2827 continue;
2828 }
cristybb503372010-05-27 20:51:26 +00002829 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002830 {
cristy4c08aed2011-07-01 19:47:50 +00002831 SetPixelPixelInfo(image,color,q);
cristydcfc1ad2011-07-07 16:25:41 +00002832 q+=GetPixelComponents(image);
cristya5b77cb2010-05-07 19:34:48 +00002833 }
2834 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2835 status=MagickFalse;
2836 }
2837 image_view=DestroyCacheView(image_view);
2838 return(status);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristy3ed852e2009-09-05 21:47:34 +00002846% S e t I m a g e S t o r a g e C l a s s %
2847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% SetImageStorageClass() sets the image class: DirectClass for true color
2853% images or PseudoClass for colormapped images.
2854%
2855% The format of the SetImageStorageClass method is:
2856%
2857% MagickBooleanType SetImageStorageClass(Image *image,
2858% const ClassType storage_class)
2859%
2860% A description of each parameter follows:
2861%
2862% o image: the image.
2863%
2864% o storage_class: The image class.
2865%
2866*/
2867MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2868 const ClassType storage_class)
2869{
cristy3ed852e2009-09-05 21:47:34 +00002870 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00002871 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002872}
2873
2874/*
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876% %
2877% %
2878% %
2879% S e t I m a g e C l i p M a s k %
2880% %
2881% %
2882% %
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884%
2885% SetImageClipMask() associates a clip path with the image. The clip path
2886% must be the same dimensions as the image. Set any pixel component of
cristy4c08aed2011-07-01 19:47:50 +00002887% the clip path to TransparentAlpha to prevent that corresponding image
cristy3ed852e2009-09-05 21:47:34 +00002888% pixel component from being updated when SyncAuthenticPixels() is applied.
2889%
2890% The format of the SetImageClipMask method is:
2891%
2892% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2893%
2894% A description of each parameter follows:
2895%
2896% o image: the image.
2897%
2898% o clip_mask: the image clip path.
2899%
2900*/
2901MagickExport MagickBooleanType SetImageClipMask(Image *image,
2902 const Image *clip_mask)
2903{
2904 assert(image != (Image *) NULL);
2905 if (image->debug != MagickFalse)
2906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2907 assert(image->signature == MagickSignature);
2908 if (clip_mask != (const Image *) NULL)
2909 if ((clip_mask->columns != image->columns) ||
2910 (clip_mask->rows != image->rows))
2911 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2912 if (image->clip_mask != (Image *) NULL)
2913 image->clip_mask=DestroyImage(image->clip_mask);
2914 image->clip_mask=NewImageList();
2915 if (clip_mask == (Image *) NULL)
2916 return(MagickTrue);
2917 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2918 return(MagickFalse);
2919 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2920 if (image->clip_mask == (Image *) NULL)
2921 return(MagickFalse);
2922 return(MagickTrue);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930% S e t I m a g e E x t e n t %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% SetImageExtent() sets the image size (i.e. columns & rows).
2937%
2938% The format of the SetImageExtent method is:
2939%
2940% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00002941% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947% o columns: The image width in pixels.
2948%
2949% o rows: The image height in pixels.
2950%
2951*/
2952MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00002953 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002954{
cristy537e2722010-09-21 15:30:59 +00002955 if ((columns == 0) || (rows == 0))
2956 return(MagickFalse);
2957 image->columns=columns;
2958 image->rows=rows;
2959 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002960}
2961
2962/*
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964% %
2965% %
2966% %
2967+ S e t I m a g e I n f o %
2968% %
2969% %
2970% %
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972%
2973% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
2974% It is set to a type of image format based on the prefix or suffix of the
2975% filename. For example, `ps:image' returns PS indicating a Postscript image.
2976% JPEG is returned for this filename: `image.jpg'. The filename prefix has
2977% precendence over the suffix. Use an optional index enclosed in brackets
2978% after a file name to specify a desired scene of a multi-resolution image
2979% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2980% indicates success.
2981%
2982% The format of the SetImageInfo method is:
2983%
2984% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002985% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002986%
2987% A description of each parameter follows:
2988%
cristyd965a422010-03-03 17:47:35 +00002989% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002990%
cristyd965a422010-03-03 17:47:35 +00002991% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002992%
2993% o exception: return any errors or warnings in this structure.
2994%
2995*/
2996MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002997 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002998{
2999 char
3000 extension[MaxTextExtent],
3001 filename[MaxTextExtent],
3002 magic[MaxTextExtent],
3003 *q,
3004 subimage[MaxTextExtent];
3005
3006 const MagicInfo
3007 *magic_info;
3008
3009 const MagickInfo
3010 *magick_info;
3011
3012 ExceptionInfo
3013 *sans_exception;
3014
3015 Image
3016 *image;
3017
3018 MagickBooleanType
3019 status;
3020
3021 register const char
3022 *p;
3023
3024 ssize_t
3025 count;
3026
3027 unsigned char
3028 magick[2*MaxTextExtent];
3029
3030 /*
3031 Look for 'image.format' in filename.
3032 */
3033 assert(image_info != (ImageInfo *) NULL);
3034 assert(image_info->signature == MagickSignature);
3035 if (image_info->debug != MagickFalse)
3036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3037 image_info->filename);
3038 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003039 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003040 {
cristyd965a422010-03-03 17:47:35 +00003041 GetPathComponent(image_info->filename,SubimagePath,subimage);
3042 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003043 {
cristyd965a422010-03-03 17:47:35 +00003044 /*
3045 Look for scene specification (e.g. img0001.pcd[4]).
3046 */
3047 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3048 {
3049 if (IsGeometry(subimage) != MagickFalse)
3050 (void) CloneString(&image_info->extract,subimage);
3051 }
3052 else
3053 {
cristybb503372010-05-27 20:51:26 +00003054 size_t
cristyd965a422010-03-03 17:47:35 +00003055 first,
3056 last;
cristy3ed852e2009-09-05 21:47:34 +00003057
cristyd965a422010-03-03 17:47:35 +00003058 (void) CloneString(&image_info->scenes,subimage);
3059 image_info->scene=StringToUnsignedLong(image_info->scenes);
3060 image_info->number_scenes=image_info->scene;
3061 p=image_info->scenes;
3062 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3063 {
3064 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3065 (*p == ','))
3066 p++;
cristybb503372010-05-27 20:51:26 +00003067 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003068 last=first;
3069 while (isspace((int) ((unsigned char) *q)) != 0)
3070 q++;
3071 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003072 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003073 if (first > last)
3074 Swap(first,last);
3075 if (first < image_info->scene)
3076 image_info->scene=first;
3077 if (last > image_info->number_scenes)
3078 image_info->number_scenes=last;
3079 p=q;
3080 }
3081 image_info->number_scenes-=image_info->scene-1;
cristyd965a422010-03-03 17:47:35 +00003082 }
cristy3ed852e2009-09-05 21:47:34 +00003083 }
3084 }
3085 *extension='\0';
3086 GetPathComponent(image_info->filename,ExtensionPath,extension);
3087#if defined(MAGICKCORE_ZLIB_DELEGATE)
3088 if (*extension != '\0')
3089 if ((LocaleCompare(extension,"gz") == 0) ||
3090 (LocaleCompare(extension,"Z") == 0) ||
3091 (LocaleCompare(extension,"wmz") == 0))
3092 {
3093 char
3094 path[MaxTextExtent];
3095
3096 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3097 path[strlen(path)-strlen(extension)-1]='\0';
3098 GetPathComponent(path,ExtensionPath,extension);
3099 }
3100#endif
3101#if defined(MAGICKCORE_BZLIB_DELEGATE)
3102 if (*extension != '\0')
3103 if (LocaleCompare(extension,"bz2") == 0)
3104 {
3105 char
3106 path[MaxTextExtent];
3107
3108 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3109 path[strlen(path)-strlen(extension)-1]='\0';
3110 GetPathComponent(path,ExtensionPath,extension);
3111 }
3112#endif
3113 image_info->affirm=MagickFalse;
3114 sans_exception=AcquireExceptionInfo();
3115 if (*extension != '\0')
3116 {
3117 MagickFormatType
3118 format_type;
3119
cristybb503372010-05-27 20:51:26 +00003120 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003121 i;
3122
3123 static const char
3124 *format_type_formats[] =
3125 {
3126 "AUTOTRACE",
3127 "BROWSE",
3128 "DCRAW",
3129 "EDIT",
3130 "EPHEMERAL",
3131 "LAUNCH",
3132 "MPEG:DECODE",
3133 "MPEG:ENCODE",
3134 "PRINT",
3135 "PS:ALPHA",
3136 "PS:CMYK",
3137 "PS:COLOR",
3138 "PS:GRAY",
3139 "PS:MONO",
3140 "SCAN",
3141 "SHOW",
3142 "WIN",
3143 (char *) NULL
3144 };
3145
3146 /*
3147 User specified image format.
3148 */
3149 (void) CopyMagickString(magic,extension,MaxTextExtent);
3150 LocaleUpper(magic);
3151 /*
3152 Look for explicit image formats.
3153 */
3154 format_type=UndefinedFormatType;
3155 i=0;
cristydd9a2532010-02-20 19:26:46 +00003156 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003157 (format_type_formats[i] != (char *) NULL))
3158 {
3159 if ((*magic == *format_type_formats[i]) &&
3160 (LocaleCompare(magic,format_type_formats[i]) == 0))
3161 format_type=ExplicitFormatType;
3162 i++;
3163 }
3164 magick_info=GetMagickInfo(magic,sans_exception);
3165 if ((magick_info != (const MagickInfo *) NULL) &&
3166 (magick_info->format_type != UndefinedFormatType))
3167 format_type=magick_info->format_type;
3168 if (format_type == UndefinedFormatType)
3169 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3170 else
3171 if (format_type == ExplicitFormatType)
3172 {
3173 image_info->affirm=MagickTrue;
3174 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3175 }
3176 if (LocaleCompare(magic,"RGB") == 0)
3177 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3178 }
3179 /*
3180 Look for explicit 'format:image' in filename.
3181 */
3182 *magic='\0';
3183 GetPathComponent(image_info->filename,MagickPath,magic);
3184 if (*magic == '\0')
3185 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3186 else
3187 {
3188 /*
3189 User specified image format.
3190 */
3191 LocaleUpper(magic);
3192 if (IsMagickConflict(magic) == MagickFalse)
3193 {
3194 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3195 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3196 image_info->affirm=MagickTrue;
3197 else
3198 image_info->temporary=MagickTrue;
3199 }
3200 }
3201 magick_info=GetMagickInfo(magic,sans_exception);
3202 sans_exception=DestroyExceptionInfo(sans_exception);
3203 if ((magick_info == (const MagickInfo *) NULL) ||
3204 (GetMagickEndianSupport(magick_info) == MagickFalse))
3205 image_info->endian=UndefinedEndian;
3206 GetPathComponent(image_info->filename,CanonicalPath,filename);
3207 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003208 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003209 {
3210 /*
cristyd965a422010-03-03 17:47:35 +00003211 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003212 */
cristyd965a422010-03-03 17:47:35 +00003213 (void) InterpretImageFilename(image_info,(Image *) NULL,
3214 image_info->filename,(int) image_info->scene,filename);
3215 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3216 (strchr(filename,'%') == (char *) NULL))
3217 image_info->adjoin=MagickFalse;
3218 }
3219 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3220 {
3221 /*
3222 Some image formats do not support multiple frames per file.
3223 */
cristy3ed852e2009-09-05 21:47:34 +00003224 magick_info=GetMagickInfo(magic,exception);
3225 if (magick_info != (const MagickInfo *) NULL)
3226 if (GetMagickAdjoin(magick_info) == MagickFalse)
3227 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003228 }
3229 if (image_info->affirm != MagickFalse)
3230 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003231 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003232 {
3233 /*
cristyd965a422010-03-03 17:47:35 +00003234 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003235 */
cristyd965a422010-03-03 17:47:35 +00003236 image=AcquireImage(image_info);
3237 (void) CopyMagickString(image->filename,image_info->filename,
3238 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003239 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3240 if (status == MagickFalse)
3241 {
3242 image=DestroyImage(image);
3243 return(MagickFalse);
3244 }
cristyd965a422010-03-03 17:47:35 +00003245 if ((IsBlobSeekable(image) == MagickFalse) ||
3246 (IsBlobExempt(image) != MagickFalse))
3247 {
3248 /*
3249 Copy standard input or pipe to temporary file.
3250 */
3251 *filename='\0';
3252 status=ImageToFile(image,filename,exception);
3253 (void) CloseBlob(image);
3254 if (status == MagickFalse)
3255 {
3256 image=DestroyImage(image);
3257 return(MagickFalse);
3258 }
3259 SetImageInfoFile(image_info,(FILE *) NULL);
3260 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3261 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3262 if (status == MagickFalse)
3263 {
3264 image=DestroyImage(image);
3265 return(MagickFalse);
3266 }
3267 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3268 image_info->temporary=MagickTrue;
3269 }
3270 (void) ResetMagickMemory(magick,0,sizeof(magick));
3271 count=ReadBlob(image,2*MaxTextExtent,magick);
3272 (void) CloseBlob(image);
3273 image=DestroyImage(image);
3274 /*
3275 Check magic.xml configuration file.
3276 */
3277 sans_exception=AcquireExceptionInfo();
3278 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3279 if ((magic_info != (const MagicInfo *) NULL) &&
3280 (GetMagicName(magic_info) != (char *) NULL))
3281 {
3282 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3283 MaxTextExtent);
3284 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3285 if ((magick_info == (const MagickInfo *) NULL) ||
3286 (GetMagickEndianSupport(magick_info) == MagickFalse))
3287 image_info->endian=UndefinedEndian;
3288 sans_exception=DestroyExceptionInfo(sans_exception);
3289 return(MagickTrue);
3290 }
cristy3ed852e2009-09-05 21:47:34 +00003291 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3292 if ((magick_info == (const MagickInfo *) NULL) ||
3293 (GetMagickEndianSupport(magick_info) == MagickFalse))
3294 image_info->endian=UndefinedEndian;
3295 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003296 }
cristy3ed852e2009-09-05 21:47:34 +00003297 return(MagickTrue);
3298}
3299
3300/*
3301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3302% %
3303% %
3304% %
3305% S e t I m a g e I n f o B l o b %
3306% %
3307% %
3308% %
3309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3310%
3311% SetImageInfoBlob() sets the image info blob member.
3312%
3313% The format of the SetImageInfoBlob method is:
3314%
3315% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3316% const size_t length)
3317%
3318% A description of each parameter follows:
3319%
3320% o image_info: the image info.
3321%
3322% o blob: the blob.
3323%
3324% o length: the blob length.
3325%
3326*/
3327MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3328 const size_t length)
3329{
3330 assert(image_info != (ImageInfo *) NULL);
3331 assert(image_info->signature == MagickSignature);
3332 if (image_info->debug != MagickFalse)
3333 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3334 image_info->filename);
3335 image_info->blob=(void *) blob;
3336 image_info->length=length;
3337}
3338
3339/*
3340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3341% %
3342% %
3343% %
3344% S e t I m a g e I n f o F i l e %
3345% %
3346% %
3347% %
3348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3349%
3350% SetImageInfoFile() sets the image info file member.
3351%
3352% The format of the SetImageInfoFile method is:
3353%
3354% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3355%
3356% A description of each parameter follows:
3357%
3358% o image_info: the image info.
3359%
3360% o file: the file.
3361%
3362*/
3363MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3364{
3365 assert(image_info != (ImageInfo *) NULL);
3366 assert(image_info->signature == MagickSignature);
3367 if (image_info->debug != MagickFalse)
3368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3369 image_info->filename);
3370 image_info->file=file;
3371}
3372
3373/*
3374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3375% %
3376% %
3377% %
3378% S e t I m a g e M a s k %
3379% %
3380% %
3381% %
3382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3383%
3384% SetImageMask() associates a mask with the image. The mask must be the same
3385% dimensions as the image.
3386%
3387% The format of the SetImageMask method is:
3388%
3389% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3390%
3391% A description of each parameter follows:
3392%
3393% o image: the image.
3394%
3395% o mask: the image mask.
3396%
3397*/
3398MagickExport MagickBooleanType SetImageMask(Image *image,
3399 const Image *mask)
3400{
3401 assert(image != (Image *) NULL);
3402 if (image->debug != MagickFalse)
3403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3404 assert(image->signature == MagickSignature);
3405 if (mask != (const Image *) NULL)
3406 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3407 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3408 if (image->mask != (Image *) NULL)
3409 image->mask=DestroyImage(image->mask);
3410 image->mask=NewImageList();
3411 if (mask == (Image *) NULL)
3412 return(MagickTrue);
3413 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3414 return(MagickFalse);
3415 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3416 if (image->mask == (Image *) NULL)
3417 return(MagickFalse);
3418 return(MagickTrue);
3419}
3420
3421/*
3422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3423% %
3424% %
3425% %
3426% S e t I m a g e O p a c i t y %
3427% %
3428% %
3429% %
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431%
3432% SetImageOpacity() sets the opacity levels of the image.
3433%
3434% The format of the SetImageOpacity method is:
3435%
3436% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3437%
3438% A description of each parameter follows:
3439%
3440% o image: the image.
3441%
3442% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3443% fully transparent.
3444%
3445*/
3446MagickExport MagickBooleanType SetImageOpacity(Image *image,
3447 const Quantum opacity)
3448{
3449 CacheView
3450 *image_view;
3451
3452 ExceptionInfo
3453 *exception;
3454
cristy3ed852e2009-09-05 21:47:34 +00003455 MagickBooleanType
3456 status;
3457
cristycb6d09b2010-06-19 01:59:36 +00003458 ssize_t
3459 y;
3460
cristy3ed852e2009-09-05 21:47:34 +00003461 assert(image != (Image *) NULL);
3462 if (image->debug != MagickFalse)
3463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3464 assert(image->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003465 image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003466 status=MagickTrue;
3467 exception=(&image->exception);
3468 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003469#if defined(MAGICKCORE_OPENMP_SUPPORT)
3470 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003471#endif
cristybb503372010-05-27 20:51:26 +00003472 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003473 {
cristy4c08aed2011-07-01 19:47:50 +00003474 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003475 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003476
cristycb6d09b2010-06-19 01:59:36 +00003477 register ssize_t
3478 x;
3479
cristy3ed852e2009-09-05 21:47:34 +00003480 if (status == MagickFalse)
3481 continue;
3482 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003483 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003484 {
3485 status=MagickFalse;
3486 continue;
3487 }
cristybb503372010-05-27 20:51:26 +00003488 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003489 {
cristy4c08aed2011-07-01 19:47:50 +00003490 SetPixelAlpha(image,opacity,q);
cristydcfc1ad2011-07-07 16:25:41 +00003491 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00003492 }
3493 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3494 status=MagickFalse;
3495 }
3496 image_view=DestroyCacheView(image_view);
3497 return(status);
3498}
3499
3500/*
3501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3502% %
3503% %
3504% %
3505% S e t I m a g e T y p e %
3506% %
3507% %
3508% %
3509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3510%
3511% SetImageType() sets the type of image. Choose from these types:
3512%
3513% Bilevel Grayscale GrayscaleMatte
3514% Palette PaletteMatte TrueColor
3515% TrueColorMatte ColorSeparation ColorSeparationMatte
3516% OptimizeType
3517%
3518% The format of the SetImageType method is:
3519%
3520% MagickBooleanType SetImageType(Image *image,const ImageType type)
3521%
3522% A description of each parameter follows:
3523%
3524% o image: the image.
3525%
3526% o type: Image type.
3527%
3528*/
3529MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3530{
3531 const char
3532 *artifact;
3533
3534 ImageInfo
3535 *image_info;
3536
3537 MagickBooleanType
3538 status;
3539
3540 QuantizeInfo
3541 *quantize_info;
3542
3543 assert(image != (Image *) NULL);
3544 if (image->debug != MagickFalse)
3545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3546 assert(image->signature == MagickSignature);
3547 status=MagickTrue;
3548 image_info=AcquireImageInfo();
3549 image_info->dither=image->dither;
3550 artifact=GetImageArtifact(image,"dither");
3551 if (artifact != (const char *) NULL)
3552 (void) SetImageOption(image_info,"dither",artifact);
3553 switch (type)
3554 {
3555 case BilevelType:
3556 {
cristy4c08aed2011-07-01 19:47:50 +00003557 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003558 status=TransformImageColorspace(image,GRAYColorspace);
cristy4c08aed2011-07-01 19:47:50 +00003559 if (IsImageMonochrome(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003560 {
3561 quantize_info=AcquireQuantizeInfo(image_info);
3562 quantize_info->number_colors=2;
3563 quantize_info->colorspace=GRAYColorspace;
3564 status=QuantizeImage(quantize_info,image);
3565 quantize_info=DestroyQuantizeInfo(quantize_info);
3566 }
3567 image->matte=MagickFalse;
3568 break;
3569 }
3570 case GrayscaleType:
3571 {
cristy4c08aed2011-07-01 19:47:50 +00003572 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003573 status=TransformImageColorspace(image,GRAYColorspace);
3574 image->matte=MagickFalse;
3575 break;
3576 }
3577 case GrayscaleMatteType:
3578 {
cristy4c08aed2011-07-01 19:47:50 +00003579 if (IsImageGray(image,&image->exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003580 status=TransformImageColorspace(image,GRAYColorspace);
3581 if (image->matte == MagickFalse)
3582 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3583 break;
3584 }
3585 case PaletteType:
3586 {
cristy510d06a2011-07-06 23:43:54 +00003587 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003588 status=TransformImageColorspace(image,RGBColorspace);
3589 if ((image->storage_class == DirectClass) || (image->colors > 256))
3590 {
3591 quantize_info=AcquireQuantizeInfo(image_info);
3592 quantize_info->number_colors=256;
3593 status=QuantizeImage(quantize_info,image);
3594 quantize_info=DestroyQuantizeInfo(quantize_info);
3595 }
3596 image->matte=MagickFalse;
3597 break;
3598 }
3599 case PaletteBilevelMatteType:
3600 {
cristy510d06a2011-07-06 23:43:54 +00003601 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003602 status=TransformImageColorspace(image,RGBColorspace);
3603 if (image->matte == MagickFalse)
3604 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3605 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3606 quantize_info=AcquireQuantizeInfo(image_info);
3607 status=QuantizeImage(quantize_info,image);
3608 quantize_info=DestroyQuantizeInfo(quantize_info);
3609 break;
3610 }
3611 case PaletteMatteType:
3612 {
cristy510d06a2011-07-06 23:43:54 +00003613 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003614 status=TransformImageColorspace(image,RGBColorspace);
3615 if (image->matte == MagickFalse)
3616 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3617 quantize_info=AcquireQuantizeInfo(image_info);
3618 quantize_info->colorspace=TransparentColorspace;
3619 status=QuantizeImage(quantize_info,image);
3620 quantize_info=DestroyQuantizeInfo(quantize_info);
3621 break;
3622 }
3623 case TrueColorType:
3624 {
cristy510d06a2011-07-06 23:43:54 +00003625 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003626 status=TransformImageColorspace(image,RGBColorspace);
3627 if (image->storage_class != DirectClass)
3628 status=SetImageStorageClass(image,DirectClass);
3629 image->matte=MagickFalse;
3630 break;
3631 }
3632 case TrueColorMatteType:
3633 {
cristy510d06a2011-07-06 23:43:54 +00003634 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003635 status=TransformImageColorspace(image,RGBColorspace);
3636 if (image->storage_class != DirectClass)
3637 status=SetImageStorageClass(image,DirectClass);
3638 if (image->matte == MagickFalse)
3639 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3640 break;
3641 }
3642 case ColorSeparationType:
3643 {
3644 if (image->colorspace != CMYKColorspace)
3645 {
cristy510d06a2011-07-06 23:43:54 +00003646 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003647 status=TransformImageColorspace(image,RGBColorspace);
3648 status=TransformImageColorspace(image,CMYKColorspace);
3649 }
3650 if (image->storage_class != DirectClass)
3651 status=SetImageStorageClass(image,DirectClass);
3652 image->matte=MagickFalse;
3653 break;
3654 }
3655 case ColorSeparationMatteType:
3656 {
3657 if (image->colorspace != CMYKColorspace)
3658 {
cristy510d06a2011-07-06 23:43:54 +00003659 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003660 status=TransformImageColorspace(image,RGBColorspace);
3661 status=TransformImageColorspace(image,CMYKColorspace);
3662 }
3663 if (image->storage_class != DirectClass)
3664 status=SetImageStorageClass(image,DirectClass);
3665 if (image->matte == MagickFalse)
3666 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3667 break;
3668 }
3669 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003670 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003671 break;
3672 }
3673 image->type=type;
3674 image_info=DestroyImageInfo(image_info);
3675 return(status);
3676}
3677
3678/*
3679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3680% %
3681% %
3682% %
3683% 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 %
3684% %
3685% %
3686% %
3687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3688%
3689% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3690% image and returns the previous setting. A virtual pixel is any pixel access
3691% that is outside the boundaries of the image cache.
3692%
3693% The format of the SetImageVirtualPixelMethod() method is:
3694%
3695% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3696% const VirtualPixelMethod virtual_pixel_method)
3697%
3698% A description of each parameter follows:
3699%
3700% o image: the image.
3701%
3702% o virtual_pixel_method: choose the type of virtual pixel.
3703%
3704*/
3705MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3706 const VirtualPixelMethod virtual_pixel_method)
3707{
3708 assert(image != (const Image *) NULL);
3709 assert(image->signature == MagickSignature);
3710 if (image->debug != MagickFalse)
3711 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3712 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3713}
3714
3715/*
3716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717% %
3718% %
3719% %
cristy4285d782011-02-09 20:12:28 +00003720% S m u s h I m a g e s %
3721% %
3722% %
3723% %
3724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3725%
3726% SmushImages() takes all images from the current image pointer to the end
3727% of the image list and smushes them to each other top-to-bottom if the
3728% stack parameter is true, otherwise left-to-right.
3729%
3730% The current gravity setting now effects how the image is justified in the
3731% final image.
3732%
3733% The format of the SmushImages method is:
3734%
cristy4ca38e22011-02-10 02:57:49 +00003735% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003736% ExceptionInfo *exception)
3737%
3738% A description of each parameter follows:
3739%
cristy4ca38e22011-02-10 02:57:49 +00003740% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003741%
3742% o stack: A value other than 0 stacks the images top-to-bottom.
3743%
3744% o offset: minimum distance in pixels between images.
3745%
3746% o exception: return any errors or warnings in this structure.
3747%
3748*/
cristy4ca38e22011-02-10 02:57:49 +00003749
cristy7c6dc152011-02-11 14:10:55 +00003750static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003751 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003752{
cristy4d727152011-02-10 19:57:21 +00003753 CacheView
3754 *left_view,
3755 *right_view;
3756
3757 const Image
3758 *left_image,
3759 *right_image;
3760
cristy4d727152011-02-10 19:57:21 +00003761 RectangleInfo
3762 left_geometry,
3763 right_geometry;
3764
cristy4c08aed2011-07-01 19:47:50 +00003765 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003766 *p;
3767
cristy4d727152011-02-10 19:57:21 +00003768 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003769 i,
cristy4d727152011-02-10 19:57:21 +00003770 y;
3771
cristy7c6dc152011-02-11 14:10:55 +00003772 size_t
3773 gap;
3774
cristy4d727152011-02-10 19:57:21 +00003775 ssize_t
cristy4d727152011-02-10 19:57:21 +00003776 x;
3777
3778 if (images->previous == (Image *) NULL)
3779 return(0);
3780 right_image=images;
3781 SetGeometry(smush_image,&right_geometry);
3782 GravityAdjustGeometry(right_image->columns,right_image->rows,
3783 right_image->gravity,&right_geometry);
3784 left_image=images->previous;
3785 SetGeometry(smush_image,&left_geometry);
3786 GravityAdjustGeometry(left_image->columns,left_image->rows,
3787 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003788 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003789 left_view=AcquireCacheView(left_image);
3790 right_view=AcquireCacheView(right_image);
3791 for (y=0; y < (ssize_t) smush_image->rows; y++)
3792 {
3793 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3794 {
cristydab7e912011-02-11 18:19:24 +00003795 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003796 if ((p == (const Quantum *) NULL) ||
3797 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003798 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003799 break;
3800 }
cristy4ef6f062011-02-10 20:30:22 +00003801 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003802 for (x=0; x < (ssize_t) right_image->columns; x++)
3803 {
cristydab7e912011-02-11 18:19:24 +00003804 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003805 exception);
cristy4c08aed2011-07-01 19:47:50 +00003806 if ((p == (const Quantum *) NULL) ||
3807 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3808 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003809 break;
3810 }
cristy7c6dc152011-02-11 14:10:55 +00003811 if ((x+i) < (ssize_t) gap)
3812 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003813 }
3814 right_view=DestroyCacheView(right_view);
3815 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003816 if (y < (ssize_t) smush_image->rows)
3817 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003818 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003819}
3820
cristy7c6dc152011-02-11 14:10:55 +00003821static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003822 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003823{
cristy4d727152011-02-10 19:57:21 +00003824 CacheView
3825 *bottom_view,
3826 *top_view;
3827
3828 const Image
3829 *bottom_image,
3830 *top_image;
3831
cristy4d727152011-02-10 19:57:21 +00003832 RectangleInfo
3833 bottom_geometry,
3834 top_geometry;
3835
cristy4c08aed2011-07-01 19:47:50 +00003836 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003837 *p;
3838
cristy4d727152011-02-10 19:57:21 +00003839 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003840 i,
cristy4d727152011-02-10 19:57:21 +00003841 x;
3842
cristy7c6dc152011-02-11 14:10:55 +00003843 size_t
3844 gap;
3845
cristy4d727152011-02-10 19:57:21 +00003846 ssize_t
cristy4d727152011-02-10 19:57:21 +00003847 y;
3848
3849 if (images->previous == (Image *) NULL)
3850 return(0);
3851 bottom_image=images;
3852 SetGeometry(smush_image,&bottom_geometry);
3853 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3854 bottom_image->gravity,&bottom_geometry);
3855 top_image=images->previous;
3856 SetGeometry(smush_image,&top_geometry);
3857 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3858 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003859 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003860 top_view=AcquireCacheView(top_image);
3861 bottom_view=AcquireCacheView(bottom_image);
3862 for (x=0; x < (ssize_t) smush_image->columns; x++)
3863 {
3864 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3865 {
cristydab7e912011-02-11 18:19:24 +00003866 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003867 if ((p == (const Quantum *) NULL) ||
3868 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3869 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003870 break;
3871 }
cristy4ef6f062011-02-10 20:30:22 +00003872 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003873 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3874 {
cristydab7e912011-02-11 18:19:24 +00003875 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3876 exception);
cristy4c08aed2011-07-01 19:47:50 +00003877 if ((p == (const Quantum *) NULL) ||
3878 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3879 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003880 break;
3881 }
cristy7c6dc152011-02-11 14:10:55 +00003882 if ((y+i) < (ssize_t) gap)
3883 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003884 }
3885 bottom_view=DestroyCacheView(bottom_view);
3886 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003887 if (x < (ssize_t) smush_image->columns)
3888 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003889 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003890}
3891
3892MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003893 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3894{
3895#define SmushImageTag "Smush/Image"
3896
3897 CacheView
cristybb5dced2011-02-10 02:17:16 +00003898 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003899
cristy4ca38e22011-02-10 02:57:49 +00003900 const Image
3901 *image;
3902
cristy4285d782011-02-09 20:12:28 +00003903 Image
3904 *smush_image;
3905
3906 MagickBooleanType
3907 matte,
3908 proceed,
3909 status;
3910
3911 MagickOffsetType
3912 n;
3913
3914 RectangleInfo
3915 geometry;
3916
3917 register const Image
3918 *next;
3919
3920 size_t
3921 height,
3922 number_images,
3923 width;
3924
3925 ssize_t
3926 x_offset,
cristy4285d782011-02-09 20:12:28 +00003927 y_offset;
3928
3929 /*
cristy7c6dc152011-02-11 14:10:55 +00003930 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003931 */
cristy4ca38e22011-02-10 02:57:49 +00003932 assert(images != (Image *) NULL);
3933 assert(images->signature == MagickSignature);
3934 if (images->debug != MagickFalse)
3935 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003936 assert(exception != (ExceptionInfo *) NULL);
3937 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00003938 image=images;
cristy4285d782011-02-09 20:12:28 +00003939 matte=image->matte;
3940 number_images=1;
3941 width=image->columns;
3942 height=image->rows;
3943 next=GetNextImageInList(image);
3944 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3945 {
3946 if (next->matte != MagickFalse)
3947 matte=MagickTrue;
3948 number_images++;
3949 if (stack != MagickFalse)
3950 {
3951 if (next->columns > width)
3952 width=next->columns;
3953 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003954 if (next->previous != (Image *) NULL)
3955 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003956 continue;
3957 }
3958 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003959 if (next->previous != (Image *) NULL)
3960 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003961 if (next->rows > height)
3962 height=next->rows;
3963 }
3964 /*
cristy7c6dc152011-02-11 14:10:55 +00003965 Smush images.
cristy4285d782011-02-09 20:12:28 +00003966 */
3967 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3968 if (smush_image == (Image *) NULL)
3969 return((Image *) NULL);
3970 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
3971 {
3972 InheritException(exception,&smush_image->exception);
3973 smush_image=DestroyImage(smush_image);
3974 return((Image *) NULL);
3975 }
3976 smush_image->matte=matte;
3977 (void) SetImageBackgroundColor(smush_image);
3978 status=MagickTrue;
3979 x_offset=0;
3980 y_offset=0;
3981 smush_view=AcquireCacheView(smush_image);
3982 for (n=0; n < (MagickOffsetType) number_images; n++)
3983 {
3984 SetGeometry(smush_image,&geometry);
3985 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3986 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003987 {
3988 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003989 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003990 }
cristy4285d782011-02-09 20:12:28 +00003991 else
cristy4ca38e22011-02-10 02:57:49 +00003992 {
cristy7c6dc152011-02-11 14:10:55 +00003993 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003994 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00003995 }
cristybb5dced2011-02-10 02:17:16 +00003996 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00003997 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3998 if (proceed == MagickFalse)
3999 break;
4000 if (stack == MagickFalse)
4001 {
4002 x_offset+=(ssize_t) image->columns;
4003 y_offset=0;
4004 }
4005 else
4006 {
4007 x_offset=0;
4008 y_offset+=(ssize_t) image->rows;
4009 }
4010 image=GetNextImageInList(image);
4011 }
cristy4ef6f062011-02-10 20:30:22 +00004012 if (stack == MagickFalse)
4013 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004014 else
cristy4ef6f062011-02-10 20:30:22 +00004015 smush_image->rows=(size_t) y_offset;
4016 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004017 if (status == MagickFalse)
4018 smush_image=DestroyImage(smush_image);
4019 return(smush_image);
4020}
4021
4022/*
4023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4024% %
4025% %
4026% %
cristy3ed852e2009-09-05 21:47:34 +00004027% S t r i p I m a g e %
4028% %
4029% %
4030% %
4031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4032%
cristy376bda92009-12-22 21:15:23 +00004033% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004034%
4035% The format of the StripImage method is:
4036%
4037% MagickBooleanType StripImage(Image *image)
4038%
4039% A description of each parameter follows:
4040%
4041% o image: the image.
4042%
4043*/
4044MagickExport MagickBooleanType StripImage(Image *image)
4045{
4046 assert(image != (Image *) NULL);
4047 if (image->debug != MagickFalse)
4048 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4049 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004050 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004051 (void) DeleteImageProperty(image,"date:create");
4052 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004053 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004054 return(MagickTrue);
4055}
4056
4057/*
4058%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4059% %
4060% %
4061% %
4062+ S y n c I m a g e %
4063% %
4064% %
4065% %
4066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4067%
4068% SyncImage() initializes the red, green, and blue intensities of each pixel
4069% as defined by the colormap index.
4070%
4071% The format of the SyncImage method is:
4072%
4073% MagickBooleanType SyncImage(Image *image)
4074%
4075% A description of each parameter follows:
4076%
4077% o image: the image.
4078%
4079*/
4080
cristy4c08aed2011-07-01 19:47:50 +00004081static inline Quantum PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004082 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004083{
4084 if (index < image->colors)
cristy4c08aed2011-07-01 19:47:50 +00004085 return((Quantum) index);
cristy3ed852e2009-09-05 21:47:34 +00004086 *range_exception=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004087 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00004088}
4089
4090MagickExport MagickBooleanType SyncImage(Image *image)
4091{
4092 CacheView
4093 *image_view;
4094
4095 ExceptionInfo
4096 *exception;
4097
cristy3ed852e2009-09-05 21:47:34 +00004098 MagickBooleanType
4099 range_exception,
4100 status;
4101
cristycb6d09b2010-06-19 01:59:36 +00004102 ssize_t
4103 y;
4104
cristy3ed852e2009-09-05 21:47:34 +00004105 assert(image != (Image *) NULL);
4106 if (image->debug != MagickFalse)
4107 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4108 assert(image->signature == MagickSignature);
4109 if (image->storage_class == DirectClass)
4110 return(MagickFalse);
4111 range_exception=MagickFalse;
4112 status=MagickTrue;
4113 exception=(&image->exception);
4114 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004115#if defined(MAGICKCORE_OPENMP_SUPPORT)
4116 #pragma omp parallel for schedule(dynamic,4) shared(status)
4117#endif
cristybb503372010-05-27 20:51:26 +00004118 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004119 {
cristy4c08aed2011-07-01 19:47:50 +00004120 Quantum
cristy3ed852e2009-09-05 21:47:34 +00004121 index;
4122
cristy4c08aed2011-07-01 19:47:50 +00004123 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004124 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004125
cristycb6d09b2010-06-19 01:59:36 +00004126 register ssize_t
4127 x;
4128
cristy48974b92009-12-19 02:36:06 +00004129 if (status == MagickFalse)
4130 continue;
cristy3ed852e2009-09-05 21:47:34 +00004131 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00004132 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004133 {
4134 status=MagickFalse;
4135 continue;
4136 }
cristybb503372010-05-27 20:51:26 +00004137 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004138 {
cristy4c08aed2011-07-01 19:47:50 +00004139 index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
cristyc8d25bc2011-04-29 02:19:30 +00004140 &range_exception);
cristy4c08aed2011-07-01 19:47:50 +00004141 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
cristydcfc1ad2011-07-07 16:25:41 +00004142 q+=GetPixelComponents(image);
cristy3ed852e2009-09-05 21:47:34 +00004143 }
4144 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4145 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004146 }
4147 image_view=DestroyCacheView(image_view);
4148 if (range_exception != MagickFalse)
4149 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4150 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4151 return(status);
4152}
cristy1626d332009-11-10 16:58:17 +00004153
4154/*
4155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4156% %
4157% %
4158% %
4159% S y n c I m a g e S e t t i n g s %
4160% %
4161% %
4162% %
4163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4164%
4165% SyncImageSettings() sync the image info options to the image.
4166%
4167% The format of the SyncImageSettings method is:
4168%
4169% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4170% Image *image)
4171% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4172% Image *image)
4173%
4174% A description of each parameter follows:
4175%
4176% o image_info: the image info.
4177%
4178% o image: the image.
4179%
4180*/
4181
4182MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4183 Image *images)
4184{
4185 Image
4186 *image;
4187
4188 assert(image_info != (const ImageInfo *) NULL);
4189 assert(image_info->signature == MagickSignature);
4190 assert(images != (Image *) NULL);
4191 assert(images->signature == MagickSignature);
4192 if (images->debug != MagickFalse)
4193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4194 image=images;
4195 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4196 (void) SyncImageSettings(image_info,image);
4197 (void) DeleteImageOption(image_info,"page");
4198 return(MagickTrue);
4199}
4200
4201MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4202 Image *image)
4203{
4204 char
4205 property[MaxTextExtent];
4206
4207 const char
cristy9a703812010-07-26 14:50:29 +00004208 *option,
4209 *value;
cristy1626d332009-11-10 16:58:17 +00004210
4211 GeometryInfo
4212 geometry_info;
4213
4214 MagickStatusType
4215 flags;
4216
cristy19eb6412010-04-23 14:42:29 +00004217 ResolutionType
4218 units;
4219
cristy1626d332009-11-10 16:58:17 +00004220 /*
4221 Sync image options.
4222 */
4223 assert(image_info != (const ImageInfo *) NULL);
4224 assert(image_info->signature == MagickSignature);
4225 assert(image != (Image *) NULL);
4226 assert(image->signature == MagickSignature);
4227 if (image->debug != MagickFalse)
4228 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4229 option=GetImageOption(image_info,"background");
4230 if (option != (const char *) NULL)
4231 (void) QueryColorDatabase(option,&image->background_color,
4232 &image->exception);
4233 option=GetImageOption(image_info,"bias");
4234 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004235 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004236 option=GetImageOption(image_info,"black-point-compensation");
4237 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004238 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004239 MagickBooleanOptions,MagickFalse,option);
4240 option=GetImageOption(image_info,"blue-primary");
4241 if (option != (const char *) NULL)
4242 {
4243 flags=ParseGeometry(option,&geometry_info);
4244 image->chromaticity.blue_primary.x=geometry_info.rho;
4245 image->chromaticity.blue_primary.y=geometry_info.sigma;
4246 if ((flags & SigmaValue) == 0)
4247 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4248 }
4249 option=GetImageOption(image_info,"bordercolor");
4250 if (option != (const char *) NULL)
4251 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4252 option=GetImageOption(image_info,"colors");
4253 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004254 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004255 option=GetImageOption(image_info,"compose");
4256 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004257 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00004258 MagickFalse,option);
4259 option=GetImageOption(image_info,"compress");
4260 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004261 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004262 MagickCompressOptions,MagickFalse,option);
4263 option=GetImageOption(image_info,"debug");
4264 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004265 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004266 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004267 option=GetImageOption(image_info,"density");
4268 if (option != (const char *) NULL)
4269 {
4270 GeometryInfo
4271 geometry_info;
4272
4273 /*
4274 Set image density.
4275 */
4276 flags=ParseGeometry(option,&geometry_info);
4277 image->x_resolution=geometry_info.rho;
4278 image->y_resolution=geometry_info.sigma;
4279 if ((flags & SigmaValue) == 0)
4280 image->y_resolution=image->x_resolution;
4281 }
cristy1626d332009-11-10 16:58:17 +00004282 option=GetImageOption(image_info,"depth");
4283 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004284 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004285 option=GetImageOption(image_info,"endian");
4286 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004287 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00004288 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004289 option=GetImageOption(image_info,"filter");
4290 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004291 image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00004292 MagickFalse,option);
4293 option=GetImageOption(image_info,"fuzz");
4294 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004295 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004296 option=GetImageOption(image_info,"gravity");
4297 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004298 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00004299 MagickFalse,option);
4300 option=GetImageOption(image_info,"green-primary");
4301 if (option != (const char *) NULL)
4302 {
4303 flags=ParseGeometry(option,&geometry_info);
4304 image->chromaticity.green_primary.x=geometry_info.rho;
4305 image->chromaticity.green_primary.y=geometry_info.sigma;
4306 if ((flags & SigmaValue) == 0)
4307 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4308 }
4309 option=GetImageOption(image_info,"intent");
4310 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004311 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004312 MagickIntentOptions,MagickFalse,option);
4313 option=GetImageOption(image_info,"interlace");
4314 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004315 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00004316 MagickFalse,option);
4317 option=GetImageOption(image_info,"interpolate");
4318 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004319 image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004320 MagickInterpolateOptions,MagickFalse,option);
4321 option=GetImageOption(image_info,"loop");
4322 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004323 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004324 option=GetImageOption(image_info,"mattecolor");
4325 if (option != (const char *) NULL)
4326 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4327 option=GetImageOption(image_info,"orient");
4328 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004329 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00004330 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004331 option=GetImageOption(image_info,"page");
4332 if (option != (const char *) NULL)
4333 {
4334 char
4335 *geometry;
4336
4337 geometry=GetPageGeometry(option);
4338 flags=ParseAbsoluteGeometry(geometry,&image->page);
4339 geometry=DestroyString(geometry);
4340 }
cristy1626d332009-11-10 16:58:17 +00004341 option=GetImageOption(image_info,"quality");
4342 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004343 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004344 option=GetImageOption(image_info,"red-primary");
4345 if (option != (const char *) NULL)
4346 {
4347 flags=ParseGeometry(option,&geometry_info);
4348 image->chromaticity.red_primary.x=geometry_info.rho;
4349 image->chromaticity.red_primary.y=geometry_info.sigma;
4350 if ((flags & SigmaValue) == 0)
4351 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4352 }
4353 if (image_info->quality != UndefinedCompressionQuality)
4354 image->quality=image_info->quality;
4355 option=GetImageOption(image_info,"scene");
4356 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004357 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004358 option=GetImageOption(image_info,"taint");
4359 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004360 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00004361 MagickFalse,option);
4362 option=GetImageOption(image_info,"tile-offset");
4363 if (option != (const char *) NULL)
4364 {
4365 char
4366 *geometry;
4367
4368 geometry=GetPageGeometry(option);
4369 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4370 geometry=DestroyString(geometry);
4371 }
4372 option=GetImageOption(image_info,"transparent-color");
4373 if (option != (const char *) NULL)
4374 (void) QueryColorDatabase(option,&image->transparent_color,
4375 &image->exception);
4376 option=GetImageOption(image_info,"type");
4377 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004378 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004379 option);
4380 option=GetImageOption(image_info,"units");
4381 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004382 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004383 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004384 else
4385 units = image_info->units;
4386 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004387 {
cristy19eb6412010-04-23 14:42:29 +00004388 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004389 switch (image->units)
4390 {
4391 case PixelsPerInchResolution:
4392 {
cristy19eb6412010-04-23 14:42:29 +00004393 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004394 {
4395 image->x_resolution/=2.54;
4396 image->y_resolution/=2.54;
4397 }
4398 break;
4399 }
4400 case PixelsPerCentimeterResolution:
4401 {
cristy19eb6412010-04-23 14:42:29 +00004402 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004403 {
cristybb503372010-05-27 20:51:26 +00004404 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004405 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004406 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004407 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004408 }
4409 break;
4410 }
4411 default:
4412 break;
4413 }
cristy19eb6412010-04-23 14:42:29 +00004414 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004415 }
4416 option=GetImageOption(image_info,"white-point");
4417 if (option != (const char *) NULL)
4418 {
4419 flags=ParseGeometry(option,&geometry_info);
4420 image->chromaticity.white_point.x=geometry_info.rho;
4421 image->chromaticity.white_point.y=geometry_info.sigma;
4422 if ((flags & SigmaValue) == 0)
4423 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4424 }
4425 ResetImageOptionIterator(image_info);
4426 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4427 {
4428 value=GetImageOption(image_info,option);
4429 if (value != (const char *) NULL)
4430 {
cristyb51dff52011-05-19 16:55:47 +00004431 (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004432 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004433 }
4434 option=GetNextImageOption(image_info);
4435 }
4436 return(MagickTrue);
4437}