blob: 5e26c06932e6d0cedd52e00a734d6dfcd956ce58 [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% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/animate.h"
45#include "magick/artifact.h"
46#include "magick/blob.h"
47#include "magick/blob-private.h"
48#include "magick/cache.h"
49#include "magick/cache-private.h"
50#include "magick/cache-view.h"
51#include "magick/client.h"
52#include "magick/color.h"
53#include "magick/color-private.h"
cristy316d5172009-09-17 19:31:25 +000054#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000055#include "magick/colorspace.h"
56#include "magick/colorspace-private.h"
57#include "magick/composite.h"
58#include "magick/composite-private.h"
59#include "magick/compress.h"
60#include "magick/constitute.h"
61#include "magick/deprecate.h"
62#include "magick/display.h"
63#include "magick/draw.h"
64#include "magick/enhance.h"
65#include "magick/exception.h"
66#include "magick/exception-private.h"
67#include "magick/gem.h"
68#include "magick/geometry.h"
cristyf2e11662009-10-14 01:24:43 +000069#include "magick/histogram.h"
cristy3ed852e2009-09-05 21:47:34 +000070#include "magick/image-private.h"
cristyf2e11662009-10-14 01:24:43 +000071#include "magick/list.h"
cristy3ed852e2009-09-05 21:47:34 +000072#include "magick/magic.h"
73#include "magick/magick.h"
74#include "magick/memory_.h"
75#include "magick/module.h"
76#include "magick/monitor.h"
77#include "magick/monitor-private.h"
78#include "magick/option.h"
79#include "magick/paint.h"
80#include "magick/pixel-private.h"
81#include "magick/profile.h"
82#include "magick/property.h"
83#include "magick/quantize.h"
84#include "magick/random_.h"
85#include "magick/segment.h"
86#include "magick/semaphore.h"
87#include "magick/signature-private.h"
88#include "magick/statistic.h"
89#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000090#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000091#include "magick/thread-private.h"
92#include "magick/threshold.h"
93#include "magick/timer.h"
94#include "magick/utility.h"
95#include "magick/version.h"
96#include "magick/xwindow-private.h"
97
98/*
99 Constant declaration.
100*/
101const char
cristy7138c592009-09-08 13:58:52 +0000102 BackgroundColor[] = "#ffffff", /* white */
103 BorderColor[] = "#dfdfdf", /* gray */
104 DefaultTileFrame[] = "15x15+3+3",
105 DefaultTileGeometry[] = "120x120+4+3>",
106 DefaultTileLabel[] = "%f\n%G\n%b",
107 ForegroundColor[] = "#000", /* black */
108 LoadImageTag[] = "Load/Image",
109 LoadImagesTag[] = "Load/Images",
110 MatteColor[] = "#bdbdbd", /* gray */
111 PSDensityGeometry[] = "72.0x72.0",
112 PSPageGeometry[] = "612x792",
113 SaveImageTag[] = "Save/Image",
114 SaveImagesTag[] = "Save/Images",
115 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000116
117const double
118 DefaultResolution = 72.0;
119
120/*
121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122% %
123% %
124% %
125% A c q u i r e I m a g e %
126% %
127% %
128% %
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%
131% AcquireImage() returns a pointer to an image structure initialized to
132% default values.
133%
134% The format of the AcquireImage method is:
135%
136% Image *AcquireImage(const ImageInfo *image_info)
137%
138% A description of each parameter follows:
139%
140% o image_info: Many of the image default values are set from this
141% structure. For example, filename, compression, depth, background color,
142% and others.
143%
144*/
145MagickExport Image *AcquireImage(const ImageInfo *image_info)
146{
147 Image
148 *image;
149
150 MagickStatusType
151 flags;
152
153 /*
154 Allocate image structure.
155 */
156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy90823212009-12-12 20:48:33 +0000157 image=(Image *) AcquireAlignedMemory(1,sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000158 if (image == (Image *) NULL)
159 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
160 (void) ResetMagickMemory(image,0,sizeof(*image));
161 /*
162 Initialize Image structure.
163 */
164 (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
165 image->storage_class=DirectClass;
166 image->depth=MAGICKCORE_QUANTUM_DEPTH;
167 image->colorspace=RGBColorspace;
168 image->interlace=NoInterlace;
169 image->ticks_per_second=UndefinedTicksPerSecond;
170 image->compose=OverCompositeOp;
171 image->blur=1.0;
172 GetExceptionInfo(&image->exception);
173 (void) QueryColorDatabase(BackgroundColor,&image->background_color,
174 &image->exception);
175 (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
176 (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
177 (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
178 &image->exception);
179 image->x_resolution=DefaultResolution;
180 image->y_resolution=DefaultResolution;
181 image->units=PixelsPerInchResolution;
182 GetTimerInfo(&image->timer);
cristy73724512010-04-12 14:43:14 +0000183 image->ping=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000184 image->cache=AcquirePixelCache(0);
185 image->blob=CloneBlobInfo((BlobInfo *) NULL);
186 image->debug=IsEventLogging();
187 image->reference_count=1;
188 image->semaphore=AllocateSemaphoreInfo();
189 image->signature=MagickSignature;
190 if (image_info == (ImageInfo *) NULL)
191 return(image);
192 /*
193 Transfer image info.
194 */
195 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
196 MagickFalse);
197 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
198 (void) CopyMagickString(image->magick_filename,image_info->filename,
199 MaxTextExtent);
200 (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
201 if (image_info->size != (char *) NULL)
202 {
203 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
204 image->columns=image->extract_info.width;
205 image->rows=image->extract_info.height;
206 image->offset=image->extract_info.x;
207 image->extract_info.x=0;
208 image->extract_info.y=0;
209 }
210 if (image_info->extract != (char *) NULL)
211 {
212 RectangleInfo
213 geometry;
214
215 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
216 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
217 {
218 image->extract_info=geometry;
219 Swap(image->columns,image->extract_info.width);
220 Swap(image->rows,image->extract_info.height);
221 }
222 }
223 image->compression=image_info->compression;
224 image->quality=image_info->quality;
225 image->endian=image_info->endian;
226 image->interlace=image_info->interlace;
227 image->units=image_info->units;
228 if (image_info->density != (char *) NULL)
229 {
230 GeometryInfo
231 geometry_info;
232
233 flags=ParseGeometry(image_info->density,&geometry_info);
234 image->x_resolution=geometry_info.rho;
235 image->y_resolution=geometry_info.sigma;
236 if ((flags & SigmaValue) == 0)
237 image->y_resolution=image->x_resolution;
238 }
239 if (image_info->page != (char *) NULL)
240 {
241 char
242 *geometry;
243
244 image->page=image->extract_info;
245 geometry=GetPageGeometry(image_info->page);
246 (void) ParseAbsoluteGeometry(geometry,&image->page);
247 geometry=DestroyString(geometry);
248 }
249 if (image_info->depth != 0)
250 image->depth=image_info->depth;
251 image->dither=image_info->dither;
252 image->background_color=image_info->background_color;
253 image->border_color=image_info->border_color;
254 image->matte_color=image_info->matte_color;
255 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000256 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000257 image->progress_monitor=image_info->progress_monitor;
258 image->client_data=image_info->client_data;
259 if (image_info->cache != (void *) NULL)
260 ClonePixelCacheMethods(image->cache,image_info->cache);
261 (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
cristy6b9aca12010-02-21 01:50:11 +0000262 (void) SyncImageSettings(image_info,image);
cristy3ed852e2009-09-05 21:47:34 +0000263 return(image);
264}
265
266/*
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268% %
269% %
270% %
271% A c q u i r e I m a g e C o l o r m a p %
272% %
273% %
274% %
275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276%
277% AcquireImageColormap() allocates an image colormap and initializes
278% it to a linear gray colorspace. If the image already has a colormap,
279% it is replaced. AcquireImageColormap() returns MagickTrue if successful,
280% otherwise MagickFalse if there is not enough memory.
281%
282% The format of the AcquireImageColormap method is:
283%
284% MagickBooleanType AcquireImageColormap(Image *image,
285% const unsigned long colors)
286%
287% A description of each parameter follows:
288%
289% o image: the image.
290%
291% o colors: the number of colors in the image colormap.
292%
293*/
294
295static inline unsigned long MagickMax(const unsigned long x,
296 const unsigned long y)
297{
298 if (x > y)
299 return(x);
300 return(y);
301}
302
303static inline unsigned long MagickMin(const unsigned long x,
304 const unsigned long y)
305{
306 if (x < y)
307 return(x);
308 return(y);
309}
310
311MagickExport MagickBooleanType AcquireImageColormap(Image *image,
312 const unsigned long colors)
313{
314 register long
315 i;
316
317 size_t
318 length;
319
320 /*
321 Allocate image colormap.
322 */
323 assert(image != (Image *) NULL);
324 assert(image->signature == MagickSignature);
325 if (image->debug != MagickFalse)
326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy386ad9b2010-03-19 23:46:32 +0000327 image->colors=colors;
cristy3ed852e2009-09-05 21:47:34 +0000328 length=(size_t) colors;
329 if (image->colormap == (PixelPacket *) NULL)
330 image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
331 sizeof(*image->colormap));
332 else
333 image->colormap=(PixelPacket *) ResizeQuantumMemory(image->colormap,length,
334 sizeof(*image->colormap));
335 if (image->colormap == (PixelPacket *) NULL)
336 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
337 image->filename);
338 for (i=0; i < (long) image->colors; i++)
339 {
340 unsigned long
341 pixel;
342
343 pixel=(unsigned long) (i*(QuantumRange/MagickMax(colors-1,1)));
344 image->colormap[i].red=(Quantum) pixel;
345 image->colormap[i].green=(Quantum) pixel;
346 image->colormap[i].blue=(Quantum) pixel;
347 image->colormap[i].opacity=OpaqueOpacity;
348 }
cristy73724512010-04-12 14:43:14 +0000349 return(SetImageStorageClass(image,PseudoClass));
cristy3ed852e2009-09-05 21:47:34 +0000350}
351
352/*
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354% %
355% %
356% %
357% A c q u i r e I m a g e I n f o %
358% %
359% %
360% %
361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362%
363% AcquireImageInfo() allocates the ImageInfo structure.
364%
365% The format of the AcquireImageInfo method is:
366%
367% ImageInfo *AcquireImageInfo(void)
368%
369*/
370MagickExport ImageInfo *AcquireImageInfo(void)
371{
372 ImageInfo
373 *image_info;
374
cristy90823212009-12-12 20:48:33 +0000375 image_info=(ImageInfo *) AcquireAlignedMemory(1,sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000376 if (image_info == (ImageInfo *) NULL)
377 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
378 GetImageInfo(image_info);
379 return(image_info);
380}
381
382/*
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384% %
385% %
386% %
387% A c q u i r e N e x t I m a g e %
388% %
389% %
390% %
391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392%
393% AcquireNextImage() initializes the next image in a sequence to
394% default values. The next member of image points to the newly allocated
395% image. If there is a memory shortage, next is assigned NULL.
396%
397% The format of the AcquireNextImage method is:
398%
399% void AcquireNextImage(const ImageInfo *image_info,Image *image)
400%
401% A description of each parameter follows:
402%
403% o image_info: Many of the image default values are set from this
404% structure. For example, filename, compression, depth, background color,
405% and others.
406%
407% o image: the image.
408%
409*/
410MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
411{
412 /*
413 Allocate image structure.
414 */
415 assert(image != (Image *) NULL);
416 assert(image->signature == MagickSignature);
417 if (image->debug != MagickFalse)
418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
419 image->next=AcquireImage(image_info);
420 if (GetNextImageInList(image) == (Image *) NULL)
421 return;
422 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
423 MaxTextExtent);
424 if (image_info != (ImageInfo *) NULL)
425 (void) CopyMagickString(GetNextImageInList(image)->filename,
426 image_info->filename,MaxTextExtent);
427 DestroyBlob(GetNextImageInList(image));
428 image->next->blob=ReferenceBlob(image->blob);
429 image->next->endian=image->endian;
430 image->next->scene=image->scene+1;
431 image->next->previous=image;
432}
433
434/*
435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436% %
437% %
438% %
439% A p p e n d I m a g e s %
440% %
441% %
442% %
443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444%
445% AppendImages() takes all images from the current image pointer to the end
446% of the image list and appends them to each other top-to-bottom if the
447% stack parameter is true, otherwise left-to-right.
448%
449% The current gravity setting now effects how the image is justified in the
450% final image.
451%
452% The format of the AppendImages method is:
453%
454% Image *AppendImages(const Image *image,const MagickBooleanType stack,
455% ExceptionInfo *exception)
456%
457% A description of each parameter follows:
458%
459% o image: the image sequence.
460%
461% o stack: A value other than 0 stacks the images top-to-bottom.
462%
463% o exception: return any errors or warnings in this structure.
464%
465*/
466MagickExport Image *AppendImages(const Image *image,
467 const MagickBooleanType stack,ExceptionInfo *exception)
468{
469#define AppendImageTag "Append/Image"
470
471 CacheView
472 *append_view,
473 *image_view;
474
475 Image
476 *append_image;
477
478 long
479 n,
480 x_offset,
481 y,
482 y_offset;
483
484 MagickBooleanType
485 matte,
486 proceed,
487 status;
488
489 RectangleInfo
490 geometry;
491
492 register const Image
493 *next;
494
495 unsigned long
496 height,
497 number_images,
498 width;
499
500 /*
501 Ensure the image have the same column width.
502 */
503 assert(image != (Image *) NULL);
504 assert(image->signature == MagickSignature);
505 if (image->debug != MagickFalse)
506 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
507 assert(exception != (ExceptionInfo *) NULL);
508 assert(exception->signature == MagickSignature);
509 matte=image->matte;
510 number_images=1;
511 width=image->columns;
512 height=image->rows;
513 next=GetNextImageInList(image);
514 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
515 {
516 if (next->matte != MagickFalse)
517 matte=MagickTrue;
518 number_images++;
519 if (stack != MagickFalse)
520 {
521 if (next->columns > width)
522 width=next->columns;
523 height+=next->rows;
524 continue;
525 }
526 width+=next->columns;
527 if (next->rows > height)
528 height=next->rows;
529 }
530 /*
531 Initialize append next attributes.
532 */
533 append_image=CloneImage(image,width,height,MagickTrue,exception);
534 if (append_image == (Image *) NULL)
535 return((Image *) NULL);
536 if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
537 {
538 InheritException(exception,&append_image->exception);
539 append_image=DestroyImage(append_image);
540 return((Image *) NULL);
541 }
542 append_image->matte=matte;
543 (void) SetImageBackgroundColor(append_image);
544 status=MagickTrue;
545 x_offset=0;
546 y_offset=0;
547 append_view=AcquireCacheView(append_image);
548 for (n=0; n < (long) number_images; n++)
549 {
550 SetGeometry(append_image,&geometry);
551 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
552 if (stack != MagickFalse)
553 x_offset-=geometry.x;
554 else
555 y_offset-=geometry.y;
556 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +0000557#if defined(MAGICKCORE_OPENMP_SUPPORT)
558 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +0000559#endif
560 for (y=0; y < (long) image->rows; y++)
561 {
562 MagickBooleanType
563 sync;
564
565 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000566 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000567
568 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000569 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000570
571 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000572 *restrict append_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000573
574 register long
575 x;
576
577 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000578 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000579
580 if (status == MagickFalse)
581 continue;
582 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
583 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
584 image->columns,1,exception);
585 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
586 {
587 status=MagickFalse;
588 continue;
589 }
590 indexes=GetCacheViewVirtualIndexQueue(image_view);
591 append_indexes=GetCacheViewAuthenticIndexQueue(append_view);
592 for (x=0; x < (long) image->columns; x++)
593 {
cristyce70c172010-01-07 17:15:30 +0000594 SetRedPixelComponent(q,GetRedPixelComponent(p));
595 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
596 SetBluePixelComponent(q,GetBluePixelComponent(p));
597 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +0000598 if (image->matte != MagickFalse)
cristyce70c172010-01-07 17:15:30 +0000599 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000600 if (image->colorspace == CMYKColorspace)
601 append_indexes[x]=indexes[x];
602 p++;
603 q++;
604 }
605 sync=SyncCacheViewAuthenticPixels(append_view,exception);
606 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000607 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000608 }
609 image_view=DestroyCacheView(image_view);
610 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
611 if (proceed == MagickFalse)
612 break;
613 if (stack == MagickFalse)
614 {
615 x_offset+=image->columns;
616 y_offset=0;
617 }
618 else
619 {
620 x_offset=0;
621 y_offset+=image->rows;
622 }
623 image=GetNextImageInList(image);
624 }
625 append_view=DestroyCacheView(append_view);
626 if (status == MagickFalse)
627 append_image=DestroyImage(append_image);
628 return(append_image);
629}
630
631/*
632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633% %
634% %
635% %
cristy3ed852e2009-09-05 21:47:34 +0000636% C a t c h I m a g e E x c e p t i o n %
637% %
638% %
639% %
640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641%
642% CatchImageException() returns if no exceptions are found in the image
643% sequence, otherwise it determines the most severe exception and reports
644% it as a warning or error depending on the severity.
645%
646% The format of the CatchImageException method is:
647%
648% ExceptionType CatchImageException(Image *image)
649%
650% A description of each parameter follows:
651%
652% o image: An image sequence.
653%
654*/
655MagickExport ExceptionType CatchImageException(Image *image)
656{
657 ExceptionInfo
658 *exception;
659
660 ExceptionType
661 severity;
662
663 assert(image != (const Image *) NULL);
664 assert(image->signature == MagickSignature);
665 if (image->debug != MagickFalse)
666 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
667 exception=AcquireExceptionInfo();
668 GetImageException(image,exception);
669 CatchException(exception);
670 severity=exception->severity;
671 exception=DestroyExceptionInfo(exception);
672 return(severity);
673}
674
675/*
676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677% %
678% %
679% %
680% C l i p I m a g e P a t h %
681% %
682% %
683% %
684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685%
686% ClipImagePath() sets the image clip mask based any clipping path information
687% if it exists.
688%
689% The format of the ClipImagePath method is:
690%
691% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
692% const MagickBooleanType inside)
693%
694% A description of each parameter follows:
695%
696% o image: the image.
697%
698% o pathname: name of clipping path resource. If name is preceded by #, use
699% clipping path numbered by name.
700%
701% o inside: if non-zero, later operations take effect inside clipping path.
702% Otherwise later operations take effect outside clipping path.
703%
704*/
705
706MagickExport MagickBooleanType ClipImage(Image *image)
707{
708 return(ClipImagePath(image,"#1",MagickTrue));
709}
710
711MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
712 const MagickBooleanType inside)
713{
714#define ClipImagePathTag "ClipPath/Image"
715
716 char
717 *property;
718
719 const char
720 *value;
721
722 Image
723 *clip_mask;
724
725 ImageInfo
726 *image_info;
727
728 assert(image != (const Image *) NULL);
729 assert(image->signature == MagickSignature);
730 if (image->debug != MagickFalse)
731 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
732 assert(pathname != NULL);
733 property=AcquireString(pathname);
734 (void) FormatMagickString(property,MaxTextExtent,"8BIM:1999,2998:%s",
735 pathname);
736 value=GetImageProperty(image,property);
737 property=DestroyString(property);
738 if (value == (const char *) NULL)
739 {
740 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
741 image->filename);
742 return(MagickFalse);
743 }
744 image_info=AcquireImageInfo();
745 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
746 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
747 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
748 image_info=DestroyImageInfo(image_info);
749 if (clip_mask == (Image *) NULL)
750 return(MagickFalse);
751 if (clip_mask->storage_class == PseudoClass)
752 {
753 (void) SyncImage(clip_mask);
754 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
755 return(MagickFalse);
756 }
757 if (inside == MagickFalse)
758 (void) NegateImage(clip_mask,MagickFalse);
759 (void) FormatMagickString(clip_mask->magick_filename,MaxTextExtent,
760 "8BIM:1999,2998:%s\nPS",pathname);
761 (void) SetImageClipMask(image,clip_mask);
762 clip_mask=DestroyImage(clip_mask);
763 return(MagickTrue);
764}
765
766/*
767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768% %
769% %
770% %
771% C l o n e I m a g e %
772% %
773% %
774% %
775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776%
777% CloneImage() copies an image and returns the copy as a new image object.
778% If the specified columns and rows is 0, an exact copy of the image is
779% returned, otherwise the pixel data is undefined and must be initialized
780% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
781% failure, a NULL image is returned and exception describes the reason for the
782% failure.
783%
784% The format of the CloneImage method is:
785%
786% Image *CloneImage(const Image *image,const unsigned long columns,
787% const unsigned long rows,const MagickBooleanType orphan,
788% ExceptionInfo *exception)
789%
790% A description of each parameter follows:
791%
792% o image: the image.
793%
794% o columns: the number of columns in the cloned image.
795%
796% o rows: the number of rows in the cloned image.
797%
798% o detach: With a value other than 0, the cloned image is detached from
799% its parent I/O stream.
800%
801% o exception: return any errors or warnings in this structure.
802%
803*/
804MagickExport Image *CloneImage(const Image *image,const unsigned long columns,
805 const unsigned long rows,const MagickBooleanType detach,
806 ExceptionInfo *exception)
807{
808 Image
809 *clone_image;
810
811 MagickRealType
812 scale;
813
814 size_t
815 length;
816
817 /*
818 Clone the image.
819 */
820 assert(image != (const Image *) NULL);
821 assert(image->signature == MagickSignature);
822 if (image->debug != MagickFalse)
823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
824 assert(exception != (ExceptionInfo *) NULL);
825 assert(exception->signature == MagickSignature);
cristy90823212009-12-12 20:48:33 +0000826 clone_image=(Image *) AcquireAlignedMemory(1,sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000827 if (clone_image == (Image *) NULL)
828 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
829 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
830 clone_image->signature=MagickSignature;
831 clone_image->storage_class=image->storage_class;
832 clone_image->colorspace=image->colorspace;
833 clone_image->matte=image->matte;
834 clone_image->columns=image->columns;
835 clone_image->rows=image->rows;
836 clone_image->dither=image->dither;
837 if (image->colormap != (PixelPacket *) NULL)
838 {
839 /*
840 Allocate and copy the image colormap.
841 */
842 clone_image->colors=image->colors;
843 length=(size_t) image->colors;
844 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
845 sizeof(*clone_image->colormap));
846 if (clone_image->colormap == (PixelPacket *) NULL)
847 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
848 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
849 sizeof(*clone_image->colormap));
850 }
851 (void) CloneImageProfiles(clone_image,image);
852 (void) CloneImageProperties(clone_image,image);
853 (void) CloneImageArtifacts(clone_image,image);
854 GetTimerInfo(&clone_image->timer);
855 GetExceptionInfo(&clone_image->exception);
856 InheritException(&clone_image->exception,&image->exception);
857 if (image->ascii85 != (void *) NULL)
858 Ascii85Initialize(clone_image);
859 clone_image->magick_columns=image->magick_columns;
860 clone_image->magick_rows=image->magick_rows;
861 clone_image->type=image->type;
862 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
863 MaxTextExtent);
864 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
865 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
866 clone_image->progress_monitor=image->progress_monitor;
867 clone_image->client_data=image->client_data;
868 clone_image->reference_count=1;
869 clone_image->next=NewImageList();
870 clone_image->previous=NewImageList();
871 clone_image->list=NewImageList();
872 clone_image->clip_mask=NewImageList();
873 clone_image->mask=NewImageList();
874 if (detach == MagickFalse)
875 clone_image->blob=ReferenceBlob(image->blob);
876 else
877 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
cristy73724512010-04-12 14:43:14 +0000878 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000879 clone_image->debug=IsEventLogging();
880 clone_image->semaphore=AllocateSemaphoreInfo();
881 if ((columns == 0) && (rows == 0))
882 {
883 if (image->montage != (char *) NULL)
884 (void) CloneString(&clone_image->montage,image->montage);
885 if (image->directory != (char *) NULL)
886 (void) CloneString(&clone_image->directory,image->directory);
887 if (image->clip_mask != (Image *) NULL)
888 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
889 exception);
890 if (image->mask != (Image *) NULL)
891 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
892 clone_image->cache=ReferencePixelCache(image->cache);
893 return(clone_image);
894 }
895 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristy06609ee2010-03-17 20:21:27 +0000896 clone_image->page.width=(unsigned long) floor(scale*image->page.width+0.5);
897 clone_image->page.x=(long) ceil(scale*image->page.x-0.5);
898 clone_image->tile_offset.x=(long) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000899 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristy06609ee2010-03-17 20:21:27 +0000900 clone_image->page.height=(unsigned long) floor(scale*image->page.height+0.5);
cristy342de4c2010-03-26 19:17:25 +0000901 clone_image->page.y=(long) ceil(scale*image->page.y-0.5);
cristy06609ee2010-03-17 20:21:27 +0000902 clone_image->tile_offset.y=(long) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000903 clone_image->columns=columns;
904 clone_image->rows=rows;
905 clone_image->cache=ClonePixelCache(image->cache);
906 return(clone_image);
907}
908
909/*
910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911% %
912% %
913% %
914% C l o n e I m a g e I n f o %
915% %
916% %
917% %
918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919%
920% CloneImageInfo() makes a copy of the given image info structure. If
921% NULL is specified, a new image info structure is created initialized to
922% default values.
923%
924% The format of the CloneImageInfo method is:
925%
926% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
927%
928% A description of each parameter follows:
929%
930% o image_info: the image info.
931%
932*/
933MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
934{
935 ImageInfo
936 *clone_info;
937
938 clone_info=AcquireImageInfo();
939 if (image_info == (ImageInfo *) NULL)
940 return(clone_info);
941 clone_info->compression=image_info->compression;
942 clone_info->temporary=image_info->temporary;
943 clone_info->adjoin=image_info->adjoin;
944 clone_info->antialias=image_info->antialias;
945 clone_info->scene=image_info->scene;
946 clone_info->number_scenes=image_info->number_scenes;
947 clone_info->depth=image_info->depth;
948 if (image_info->size != (char *) NULL)
949 (void) CloneString(&clone_info->size,image_info->size);
950 if (image_info->extract != (char *) NULL)
951 (void) CloneString(&clone_info->extract,image_info->extract);
952 if (image_info->scenes != (char *) NULL)
953 (void) CloneString(&clone_info->scenes,image_info->scenes);
954 if (image_info->page != (char *) NULL)
955 (void) CloneString(&clone_info->page,image_info->page);
956 clone_info->interlace=image_info->interlace;
957 clone_info->endian=image_info->endian;
958 clone_info->units=image_info->units;
959 clone_info->quality=image_info->quality;
960 if (image_info->sampling_factor != (char *) NULL)
961 (void) CloneString(&clone_info->sampling_factor,
962 image_info->sampling_factor);
963 if (image_info->server_name != (char *) NULL)
964 (void) CloneString(&clone_info->server_name,image_info->server_name);
965 if (image_info->font != (char *) NULL)
966 (void) CloneString(&clone_info->font,image_info->font);
967 if (image_info->texture != (char *) NULL)
968 (void) CloneString(&clone_info->texture,image_info->texture);
969 if (image_info->density != (char *) NULL)
970 (void) CloneString(&clone_info->density,image_info->density);
971 clone_info->pointsize=image_info->pointsize;
972 clone_info->fuzz=image_info->fuzz;
973 clone_info->pen=image_info->pen;
974 clone_info->background_color=image_info->background_color;
975 clone_info->border_color=image_info->border_color;
976 clone_info->matte_color=image_info->matte_color;
977 clone_info->transparent_color=image_info->transparent_color;
978 clone_info->dither=image_info->dither;
979 clone_info->monochrome=image_info->monochrome;
980 clone_info->colors=image_info->colors;
981 clone_info->colorspace=image_info->colorspace;
982 clone_info->type=image_info->type;
983 clone_info->orientation=image_info->orientation;
984 clone_info->preview_type=image_info->preview_type;
985 clone_info->group=image_info->group;
986 clone_info->ping=image_info->ping;
987 clone_info->verbose=image_info->verbose;
988 if (image_info->view != (char *) NULL)
989 (void) CloneString(&clone_info->view,image_info->view);
990 if (image_info->authenticate != (char *) NULL)
991 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
992 (void) CloneImageOptions(clone_info,image_info);
993 clone_info->progress_monitor=image_info->progress_monitor;
994 clone_info->client_data=image_info->client_data;
995 clone_info->cache=image_info->cache;
996 if (image_info->cache != (void *) NULL)
997 clone_info->cache=ReferencePixelCache(image_info->cache);
998 if (image_info->profile != (void *) NULL)
999 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
1000 image_info->profile);
1001 SetImageInfoFile(clone_info,image_info->file);
1002 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
1003 clone_info->stream=image_info->stream;
1004 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
1005 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
1006 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
1007 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
1008 (void) CopyMagickString(clone_info->filename,image_info->filename,
1009 MaxTextExtent);
1010 clone_info->subimage=image_info->scene; /* deprecated */
1011 clone_info->subrange=image_info->number_scenes; /* deprecated */
1012 clone_info->channel=image_info->channel;
1013 clone_info->debug=IsEventLogging();
1014 clone_info->signature=image_info->signature;
1015 return(clone_info);
1016}
1017
1018/*
1019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020% %
1021% %
1022% %
1023% C o m b i n e I m a g e s %
1024% %
1025% %
1026% %
1027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028%
1029% CombineImages() combines one or more images into a single image. The
1030% grayscale value of the pixels of each image in the sequence is assigned in
1031% order to the specified channels of the combined image. The typical
1032% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
1033%
1034% The format of the CombineImages method is:
1035%
1036% Image *CombineImages(const Image *image,const ChannelType channel,
1037% ExceptionInfo *exception)
1038%
1039% A description of each parameter follows:
1040%
1041% o image: the image.
1042%
1043% o exception: return any errors or warnings in this structure.
1044%
1045*/
1046MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1047 ExceptionInfo *exception)
1048{
1049#define CombineImageTag "Combine/Image"
1050
1051 CacheView
1052 *combine_view;
1053
1054 const Image
1055 *next;
1056
1057 Image
1058 *combine_image;
1059
1060 long
1061 progress,
1062 y;
1063
1064 MagickBooleanType
1065 status;
1066
1067 /*
1068 Ensure the image are the same size.
1069 */
1070 assert(image != (const Image *) NULL);
1071 assert(image->signature == MagickSignature);
1072 if (image->debug != MagickFalse)
1073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1074 assert(exception != (ExceptionInfo *) NULL);
1075 assert(exception->signature == MagickSignature);
1076 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1077 {
1078 if ((next->columns != image->columns) || (next->rows != image->rows))
1079 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1080 }
1081 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1082 if (combine_image == (Image *) NULL)
1083 return((Image *) NULL);
1084 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1085 {
1086 InheritException(exception,&combine_image->exception);
1087 combine_image=DestroyImage(combine_image);
1088 return((Image *) NULL);
1089 }
1090 if ((channel & OpacityChannel) != 0)
1091 combine_image->matte=MagickTrue;
1092 (void) SetImageBackgroundColor(combine_image);
1093 /*
1094 Combine images.
1095 */
1096 status=MagickTrue;
1097 progress=0;
1098 combine_view=AcquireCacheView(combine_image);
cristyb5d5f722009-11-04 03:03:49 +00001099#if defined(MAGICKCORE_OPENMP_SUPPORT)
1100 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00001101#endif
1102 for (y=0; y < (long) combine_image->rows; y++)
1103 {
1104 CacheView
1105 *image_view;
1106
1107 const Image
1108 *next;
1109
1110 PixelPacket
1111 *pixels;
1112
1113 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001114 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001115
1116 register long
1117 x;
1118
1119 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001120 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001121
1122 if (status == MagickFalse)
1123 continue;
1124 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1125 1,exception);
1126 if (pixels == (PixelPacket *) NULL)
1127 {
1128 status=MagickFalse;
1129 continue;
1130 }
1131 next=image;
1132 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
1133 {
1134 image_view=AcquireCacheView(next);
1135 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1136 if (p == (const PixelPacket *) NULL)
1137 continue;
1138 q=pixels;
1139 for (x=0; x < (long) combine_image->columns; x++)
1140 {
cristyce70c172010-01-07 17:15:30 +00001141 SetRedPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001142 p++;
1143 q++;
1144 }
1145 image_view=DestroyCacheView(image_view);
1146 next=GetNextImageInList(next);
1147 }
1148 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
1149 {
1150 image_view=AcquireCacheView(next);
1151 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1152 if (p == (const PixelPacket *) NULL)
1153 continue;
1154 q=pixels;
1155 for (x=0; x < (long) combine_image->columns; x++)
1156 {
cristyce70c172010-01-07 17:15:30 +00001157 SetGreenPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001158 p++;
1159 q++;
1160 }
1161 image_view=DestroyCacheView(image_view);
1162 next=GetNextImageInList(next);
1163 }
1164 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
1165 {
1166 image_view=AcquireCacheView(next);
1167 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1168 if (p == (const PixelPacket *) NULL)
1169 continue;
1170 q=pixels;
1171 for (x=0; x < (long) combine_image->columns; x++)
1172 {
cristyce70c172010-01-07 17:15:30 +00001173 SetBluePixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001174 p++;
1175 q++;
1176 }
1177 image_view=DestroyCacheView(image_view);
1178 next=GetNextImageInList(next);
1179 }
1180 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
1181 {
1182 image_view=AcquireCacheView(next);
1183 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1184 if (p == (const PixelPacket *) NULL)
1185 continue;
1186 q=pixels;
1187 for (x=0; x < (long) combine_image->columns; x++)
1188 {
cristyce70c172010-01-07 17:15:30 +00001189 SetOpacityPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001190 p++;
1191 q++;
1192 }
1193 image_view=DestroyCacheView(image_view);
1194 next=GetNextImageInList(next);
1195 }
1196 if (((channel & IndexChannel) != 0) &&
1197 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1198 {
1199 IndexPacket
1200 *indexes;
1201
1202 image_view=AcquireCacheView(next);
1203 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1204 if (p == (const PixelPacket *) NULL)
1205 continue;
1206 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
1207 for (x=0; x < (long) combine_image->columns; x++)
1208 {
1209 indexes[x]=PixelIntensityToQuantum(p);
1210 p++;
1211 }
1212 image_view=DestroyCacheView(image_view);
1213 next=GetNextImageInList(next);
1214 }
1215 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1216 status=MagickFalse;
1217 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1218 {
1219 MagickBooleanType
1220 proceed;
1221
cristyb5d5f722009-11-04 03:03:49 +00001222#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001223 #pragma omp critical (MagickCore_CombineImages)
1224#endif
1225 proceed=SetImageProgress(image,CombineImageTag,progress++,
1226 combine_image->rows);
1227 if (proceed == MagickFalse)
1228 status=MagickFalse;
1229 }
1230 }
1231 combine_view=DestroyCacheView(combine_view);
1232 if (status == MagickFalse)
1233 combine_image=DestroyImage(combine_image);
1234 return(combine_image);
1235}
1236
1237/*
1238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239% %
1240% %
1241% %
cristy3ed852e2009-09-05 21:47:34 +00001242% D e s t r o y I m a g e %
1243% %
1244% %
1245% %
1246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247%
1248% DestroyImage() dereferences an image, deallocating memory associated with
1249% the image if the reference count becomes zero.
1250%
1251% The format of the DestroyImage method is:
1252%
1253% Image *DestroyImage(Image *image)
1254%
1255% A description of each parameter follows:
1256%
1257% o image: the image.
1258%
1259*/
1260MagickExport Image *DestroyImage(Image *image)
1261{
1262 MagickBooleanType
1263 destroy;
1264
1265 /*
1266 Dereference image.
1267 */
1268 assert(image != (Image *) NULL);
1269 assert(image->signature == MagickSignature);
1270 if (image->debug != MagickFalse)
1271 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1272 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001273 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001274 image->reference_count--;
1275 if (image->reference_count == 0)
1276 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001277 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001278 if (destroy == MagickFalse)
1279 return((Image *) NULL);
1280 /*
1281 Destroy image.
1282 */
1283 DestroyImagePixels(image);
1284 if (image->clip_mask != (Image *) NULL)
1285 image->clip_mask=DestroyImage(image->clip_mask);
1286 if (image->mask != (Image *) NULL)
1287 image->mask=DestroyImage(image->mask);
1288 if (image->montage != (char *) NULL)
1289 image->montage=DestroyString(image->montage);
1290 if (image->directory != (char *) NULL)
1291 image->directory=DestroyString(image->directory);
1292 if (image->colormap != (PixelPacket *) NULL)
1293 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1294 if (image->geometry != (char *) NULL)
1295 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001296 DestroyImageProfiles(image);
1297 DestroyImageProperties(image);
1298 DestroyImageArtifacts(image);
1299 if (image->ascii85 != (Ascii85Info*) NULL)
1300 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1301 DestroyBlob(image);
1302 (void) DestroyExceptionInfo(&image->exception);
1303 if (image->semaphore != (SemaphoreInfo *) NULL)
1304 DestroySemaphoreInfo(&image->semaphore);
1305 image->signature=(~MagickSignature);
1306 image=(Image *) RelinquishMagickMemory(image);
1307 return(image);
1308}
1309
1310/*
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312% %
1313% %
1314% %
1315% D e s t r o y I m a g e I n f o %
1316% %
1317% %
1318% %
1319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320%
1321% DestroyImageInfo() deallocates memory associated with an ImageInfo
1322% structure.
1323%
1324% The format of the DestroyImageInfo method is:
1325%
1326% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1327%
1328% A description of each parameter follows:
1329%
1330% o image_info: the image info.
1331%
1332*/
1333MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1334{
1335 assert(image_info != (ImageInfo *) NULL);
1336 assert(image_info->signature == MagickSignature);
1337 if (image_info->debug != MagickFalse)
1338 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1339 image_info->filename);
1340 if (image_info->size != (char *) NULL)
1341 image_info->size=DestroyString(image_info->size);
1342 if (image_info->extract != (char *) NULL)
1343 image_info->extract=DestroyString(image_info->extract);
1344 if (image_info->scenes != (char *) NULL)
1345 image_info->scenes=DestroyString(image_info->scenes);
1346 if (image_info->page != (char *) NULL)
1347 image_info->page=DestroyString(image_info->page);
1348 if (image_info->sampling_factor != (char *) NULL)
1349 image_info->sampling_factor=DestroyString(
1350 image_info->sampling_factor);
1351 if (image_info->server_name != (char *) NULL)
1352 image_info->server_name=DestroyString(
1353 image_info->server_name);
1354 if (image_info->font != (char *) NULL)
1355 image_info->font=DestroyString(image_info->font);
1356 if (image_info->texture != (char *) NULL)
1357 image_info->texture=DestroyString(image_info->texture);
1358 if (image_info->density != (char *) NULL)
1359 image_info->density=DestroyString(image_info->density);
1360 if (image_info->view != (char *) NULL)
1361 image_info->view=DestroyString(image_info->view);
1362 if (image_info->authenticate != (char *) NULL)
1363 image_info->authenticate=DestroyString(
1364 image_info->authenticate);
1365 DestroyImageOptions(image_info);
1366 if (image_info->cache != (void *) NULL)
1367 image_info->cache=DestroyPixelCache(image_info->cache);
1368 if (image_info->profile != (StringInfo *) NULL)
1369 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1370 image_info->profile);
1371 image_info->signature=(~MagickSignature);
1372 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1373 return(image_info);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D i s a s s o c i a t e I m a g e S t r e a m %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DisassociateImageStream() disassociates the image stream.
1388%
1389% The format of the DisassociateImageStream method is:
1390%
1391% MagickBooleanType DisassociateImageStream(const Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DisassociateImageStream(Image *image)
1399{
1400 assert(image != (const Image *) NULL);
1401 assert(image->signature == MagickSignature);
1402 if (image->debug != MagickFalse)
1403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1404 (void) DetachBlob(image->blob);
1405}
1406
1407/*
1408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409% %
1410% %
1411% %
1412% G e t I m a g e A l p h a C h a n n e l %
1413% %
1414% %
1415% %
1416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417%
1418% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1419% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1420% than CMYKA.
1421%
1422% The format of the GetImageAlphaChannel method is:
1423%
1424% MagickBooleanType GetImageAlphaChannel(const Image *image)
1425%
1426% A description of each parameter follows:
1427%
1428% o image: the image.
1429%
1430*/
1431MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1432{
1433 assert(image != (const Image *) NULL);
1434 if (image->debug != MagickFalse)
1435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1436 assert(image->signature == MagickSignature);
1437 return(image->matte);
1438}
1439
1440/*
1441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1442% %
1443% %
1444% %
1445% G e t I m a g e C l i p M a s k %
1446% %
1447% %
1448% %
1449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1450%
1451% GetImageClipMask() returns the clip path associated with the image.
1452%
1453% The format of the GetImageClipMask method is:
1454%
1455% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1456%
1457% A description of each parameter follows:
1458%
1459% o image: the image.
1460%
1461*/
1462MagickExport Image *GetImageClipMask(const Image *image,
1463 ExceptionInfo *exception)
1464{
1465 assert(image != (const Image *) NULL);
1466 if (image->debug != MagickFalse)
1467 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1468 assert(image->signature == MagickSignature);
1469 if (image->clip_mask == (Image *) NULL)
1470 return((Image *) NULL);
1471 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1472}
1473
1474/*
1475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476% %
1477% %
1478% %
1479% G e t I m a g e E x c e p t i o n %
1480% %
1481% %
1482% %
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484%
1485% GetImageException() traverses an image sequence and returns any
1486% error more severe than noted by the exception parameter.
1487%
1488% The format of the GetImageException method is:
1489%
1490% void GetImageException(Image *image,ExceptionInfo *exception)
1491%
1492% A description of each parameter follows:
1493%
1494% o image: Specifies a pointer to a list of one or more images.
1495%
1496% o exception: return the highest severity exception.
1497%
1498*/
1499MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1500{
1501 register Image
1502 *next;
1503
1504 assert(image != (Image *) NULL);
1505 assert(image->signature == MagickSignature);
1506 if (image->debug != MagickFalse)
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1508 assert(exception != (ExceptionInfo *) NULL);
1509 assert(exception->signature == MagickSignature);
1510 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1511 {
1512 if (next->exception.severity == UndefinedException)
1513 continue;
1514 if (next->exception.severity > exception->severity)
1515 InheritException(exception,&next->exception);
1516 next->exception.severity=UndefinedException;
1517 }
1518}
1519
1520/*
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522% %
1523% %
1524% %
1525% G e t I m a g e I n f o %
1526% %
1527% %
1528% %
1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530%
1531% GetImageInfo() initializes image_info to default values.
1532%
1533% The format of the GetImageInfo method is:
1534%
1535% void GetImageInfo(ImageInfo *image_info)
1536%
1537% A description of each parameter follows:
1538%
1539% o image_info: the image info.
1540%
1541*/
1542MagickExport void GetImageInfo(ImageInfo *image_info)
1543{
1544 ExceptionInfo
1545 *exception;
1546
1547 /*
1548 File and image dimension members.
1549 */
1550 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1551 assert(image_info != (ImageInfo *) NULL);
1552 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1553 image_info->adjoin=MagickTrue;
1554 image_info->interlace=NoInterlace;
1555 image_info->channel=DefaultChannels;
1556 image_info->quality=UndefinedCompressionQuality;
1557 image_info->antialias=MagickTrue;
1558 image_info->dither=MagickTrue;
1559 exception=AcquireExceptionInfo();
1560 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1561 exception);
1562 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1563 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1564 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1565 exception);
1566 exception=DestroyExceptionInfo(exception);
1567 image_info->debug=IsEventLogging();
1568 image_info->signature=MagickSignature;
1569}
1570
1571/*
1572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573% %
1574% %
1575% %
cristy15781e52009-12-05 23:05:27 +00001576% G e t I m a g e I n f o F i l e %
1577% %
1578% %
1579% %
1580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581%
1582% GetImageInfoFile() returns the image info file member.
1583%
1584% The format of the GetImageInfoFile method is:
1585%
1586% FILE *GetImageInfoFile(const ImageInfo *image_info)
1587%
1588% A description of each parameter follows:
1589%
1590% o image_info: the image info.
1591%
1592*/
1593MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1594{
1595 return(image_info->file);
1596}
1597
1598/*
1599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600% %
1601% %
1602% %
cristy3ed852e2009-09-05 21:47:34 +00001603% G e t I m a g e M a s k %
1604% %
1605% %
1606% %
1607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608%
1609% GetImageMask() returns the mask associated with the image.
1610%
1611% The format of the GetImageMask method is:
1612%
1613% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1614%
1615% A description of each parameter follows:
1616%
1617% o image: the image.
1618%
1619*/
1620MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1621{
1622 assert(image != (const Image *) NULL);
1623 if (image->debug != MagickFalse)
1624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1625 assert(image->signature == MagickSignature);
1626 if (image->mask == (Image *) NULL)
1627 return((Image *) NULL);
1628 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1629}
1630
1631/*
1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633% %
1634% %
1635% %
1636+ G e t I m a g e R e f e r e n c e C o u n t %
1637% %
1638% %
1639% %
1640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641%
1642% GetImageReferenceCount() returns the image reference count.
1643%
1644% The format of the GetReferenceCount method is:
1645%
1646% long GetImageReferenceCount(Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport long GetImageReferenceCount(Image *image)
1654{
1655 long
1656 reference_count;
1657
1658 assert(image != (Image *) NULL);
1659 assert(image->signature == MagickSignature);
1660 if (image->debug != MagickFalse)
1661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001662 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001663 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001664 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001665 return(reference_count);
1666}
1667
1668/*
1669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1670% %
1671% %
1672% %
cristy3ed852e2009-09-05 21:47:34 +00001673% 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 %
1674% %
1675% %
1676% %
1677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678%
1679% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1680% image. A virtual pixel is any pixel access that is outside the boundaries
1681% of the image cache.
1682%
1683% The format of the GetImageVirtualPixelMethod() method is:
1684%
1685% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1686%
1687% A description of each parameter follows:
1688%
1689% o image: the image.
1690%
1691*/
1692MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1693{
1694 assert(image != (Image *) NULL);
1695 assert(image->signature == MagickSignature);
1696 if (image->debug != MagickFalse)
1697 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1698 return(GetPixelCacheVirtualMethod(image));
1699}
1700
1701/*
1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703% %
1704% %
1705% %
1706% I n t e r p r e t I m a g e F i l e n a m e %
1707% %
1708% %
1709% %
1710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711%
1712% InterpretImageFilename() interprets embedded characters in an image filename.
1713% The filename length is returned.
1714%
1715% The format of the InterpretImageFilename method is:
1716%
1717% size_t InterpretImageFilename(const ImageInfo *image_info,
1718% Image *image,const char *format,int value,char *filename)
1719%
1720% A description of each parameter follows.
1721%
1722% o image_info: the image info..
1723%
1724% o image: the image.
1725%
1726% o format: A filename describing the format to use to write the numeric
1727% argument. Only the first numeric format identifier is replaced.
1728%
1729% o value: Numeric value to substitute into format filename.
1730%
1731% o filename: return the formatted filename in this character buffer.
1732%
1733*/
1734MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1735 Image *image,const char *format,int value,char *filename)
1736{
1737 char
1738 *q;
1739
1740 int
1741 c;
1742
1743 MagickBooleanType
1744 canonical;
1745
1746 register const char
1747 *p;
1748
1749 canonical=MagickFalse;
1750 (void) CopyMagickString(filename,format,MaxTextExtent);
1751 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1752 {
1753 q=(char *) p+1;
1754 if (*q == '%')
1755 {
1756 p=q+1;
1757 continue;
1758 }
1759 if (*q == '0')
1760 {
1761 long
1762 value;
1763
1764 value=strtol(q,&q,10);
1765 }
1766 switch (*q)
1767 {
1768 case 'd':
1769 case 'o':
1770 case 'x':
1771 {
1772 q++;
1773 c=(*q);
1774 *q='\0';
1775 (void) FormatMagickString(filename+(p-format),(size_t) (MaxTextExtent-
1776 (p-format)),p,value);
1777 *q=c;
1778 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1779 canonical=MagickTrue;
1780 if (*(q-1) != '%')
1781 break;
1782 p++;
1783 break;
1784 }
1785 case '[':
1786 {
1787 char
1788 pattern[MaxTextExtent];
1789
1790 const char
1791 *value;
1792
1793 long
1794 depth;
1795
1796 register char
1797 *r;
1798
1799 register long
1800 i;
1801
1802 /*
1803 Image option.
1804 */
1805 if (strchr(p,']') == (char *) NULL)
1806 break;
1807 depth=1;
1808 r=q+1;
1809 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1810 {
1811 if (*r == '[')
1812 depth++;
1813 if (*r == ']')
1814 depth--;
1815 if (depth <= 0)
1816 break;
1817 pattern[i]=(*r++);
1818 }
1819 pattern[i]='\0';
1820 if (LocaleNCompare(pattern,"filename:",9) != 0)
1821 break;
1822 value=(const char *) NULL;
1823 if ((image_info != (const ImageInfo *) NULL) &&
1824 (image != (const Image *) NULL))
1825 value=GetMagickProperty(image_info,image,pattern);
1826 else
1827 if (image != (Image *) NULL)
1828 value=GetImageProperty(image,pattern);
1829 else
1830 if (image_info != (ImageInfo *) NULL)
1831 value=GetImageOption(image_info,pattern);
1832 if (value == (const char *) NULL)
1833 break;
1834 q--;
1835 c=(*q);
1836 *q='\0';
1837 (void) CopyMagickString(filename+(p-format),value,(size_t)
1838 (MaxTextExtent-(p-format)));
1839 *q=c;
1840 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1841 canonical=MagickTrue;
1842 if (*(q-1) != '%')
1843 break;
1844 p++;
1845 break;
1846 }
1847 default:
1848 break;
1849 }
1850 }
1851 for (q=filename; *q != '\0'; q++)
1852 if ((*q == '%') && (*(q+1) == '%'))
1853 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1854 if (canonical == MagickFalse)
1855 (void) CopyMagickString(filename,format,MaxTextExtent);
1856 return(strlen(filename));
1857}
1858
1859/*
1860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861% %
1862% %
1863% %
1864% I s H i g h D y n a m i c R a n g e I m a g e %
1865% %
1866% %
1867% %
1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869%
1870% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1871% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1872% 0..65535.
1873%
1874% The format of the IsHighDynamicRangeImage method is:
1875%
1876% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1877% ExceptionInfo *exception)
1878%
1879% A description of each parameter follows:
1880%
1881% o image: the image.
1882%
1883% o exception: return any errors or warnings in this structure.
1884%
1885*/
1886MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1887 ExceptionInfo *exception)
1888{
1889#if !defined(MAGICKCORE_HDRI_SUPPORT)
1890 (void) image;
1891 (void) exception;
1892 return(MagickFalse);
1893#else
1894 CacheView
1895 *image_view;
1896
1897 long
1898 y;
1899
1900 MagickBooleanType
1901 status;
1902
1903 MagickPixelPacket
1904 zero;
1905
1906 assert(image != (Image *) NULL);
1907 assert(image->signature == MagickSignature);
1908 if (image->debug != MagickFalse)
1909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1910 status=MagickTrue;
1911 GetMagickPixelPacket(image,&zero);
1912 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001913#if defined(MAGICKCORE_OPENMP_SUPPORT)
1914 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001915#endif
1916 for (y=0; y < (long) image->rows; y++)
1917 {
1918 MagickPixelPacket
1919 pixel;
1920
1921 register const IndexPacket
1922 *indexes;
1923
1924 register const PixelPacket
1925 *p;
1926
1927 register long
1928 x;
1929
1930 if (status == MagickFalse)
1931 continue;
1932 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1933 if (p == (const PixelPacket *) NULL)
1934 {
1935 status=MagickFalse;
1936 continue;
1937 }
1938 indexes=GetCacheViewVirtualIndexQueue(image_view);
1939 pixel=zero;
1940 for (x=0; x < (long) image->columns; x++)
1941 {
1942 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1943 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1944 (pixel.red != (QuantumAny) pixel.red))
1945 break;
1946 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1947 (pixel.green != (QuantumAny) pixel.green))
1948 break;
1949 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1950 (pixel.blue != (QuantumAny) pixel.blue))
1951 break;
1952 if (pixel.matte != MagickFalse)
1953 {
1954 if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
1955 (pixel.opacity != (QuantumAny) pixel.opacity))
1956 break;
1957 }
1958 if (pixel.colorspace == CMYKColorspace)
1959 {
1960 if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
1961 (pixel.index != (QuantumAny) pixel.index))
1962 break;
1963 }
1964 p++;
1965 }
1966 if (x < (long) image->columns)
1967 status=MagickFalse;
1968 }
1969 image_view=DestroyCacheView(image_view);
1970 return(status != MagickFalse ? MagickFalse : MagickTrue);
1971#endif
1972}
1973
1974/*
1975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976% %
1977% %
1978% %
1979% I s I m a g e O b j e c t %
1980% %
1981% %
1982% %
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984%
1985% IsImageObject() returns MagickTrue if the image sequence contains a valid
1986% set of image objects.
1987%
1988% The format of the IsImageObject method is:
1989%
1990% MagickBooleanType IsImageObject(const Image *image)
1991%
1992% A description of each parameter follows:
1993%
1994% o image: the image.
1995%
1996*/
1997MagickExport MagickBooleanType IsImageObject(const Image *image)
1998{
1999 register const Image
2000 *p;
2001
2002 assert(image != (Image *) NULL);
2003 if (image->debug != MagickFalse)
2004 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2005 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2006 if (p->signature != MagickSignature)
2007 return(MagickFalse);
2008 return(MagickTrue);
2009}
2010
2011/*
2012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013% %
2014% %
2015% %
2016% I s T a i n t I m a g e %
2017% %
2018% %
2019% %
2020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2021%
2022% IsTaintImage() returns MagickTrue any pixel in the image has been altered
2023% since it was first constituted.
2024%
2025% The format of the IsTaintImage method is:
2026%
2027% MagickBooleanType IsTaintImage(const Image *image)
2028%
2029% A description of each parameter follows:
2030%
2031% o image: the image.
2032%
2033*/
2034MagickExport MagickBooleanType IsTaintImage(const Image *image)
2035{
2036 char
2037 magick[MaxTextExtent],
2038 filename[MaxTextExtent];
2039
2040 register const Image
2041 *p;
2042
2043 assert(image != (Image *) NULL);
2044 if (image->debug != MagickFalse)
2045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2046 assert(image->signature == MagickSignature);
2047 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2048 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2049 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2050 {
2051 if (p->taint != MagickFalse)
2052 return(MagickTrue);
2053 if (LocaleCompare(p->magick,magick) != 0)
2054 return(MagickTrue);
2055 if (LocaleCompare(p->filename,filename) != 0)
2056 return(MagickTrue);
2057 }
2058 return(MagickFalse);
2059}
2060
2061/*
2062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063% %
2064% %
2065% %
2066% M o d i f y I m a g e %
2067% %
2068% %
2069% %
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071%
2072% ModifyImage() ensures that there is only a single reference to the image
2073% to be modified, updating the provided image pointer to point to a clone of
2074% the original image if necessary.
2075%
2076% The format of the ModifyImage method is:
2077%
2078% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2079%
2080% A description of each parameter follows:
2081%
2082% o image: the image.
2083%
2084% o exception: return any errors or warnings in this structure.
2085%
2086*/
2087MagickExport MagickBooleanType ModifyImage(Image **image,
2088 ExceptionInfo *exception)
2089{
2090 Image
2091 *clone_image;
2092
2093 assert(image != (Image **) NULL);
2094 assert(*image != (Image *) NULL);
2095 assert((*image)->signature == MagickSignature);
2096 if ((*image)->debug != MagickFalse)
2097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2098 if (GetImageReferenceCount(*image) <= 1)
2099 return(MagickTrue);
2100 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002101 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002102 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002103 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002104 *image=clone_image;
2105 return(MagickTrue);
2106}
2107
2108/*
2109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110% %
2111% %
2112% %
2113% N e w M a g i c k I m a g e %
2114% %
2115% %
2116% %
2117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118%
2119% NewMagickImage() creates a blank image canvas of the specified size and
2120% background color.
2121%
2122% The format of the NewMagickImage method is:
2123%
2124% Image *NewMagickImage(const ImageInfo *image_info,
2125% const unsigned long width,const unsigned long height,
2126% const MagickPixelPacket *background)
2127%
2128% A description of each parameter follows:
2129%
2130% o image: the image.
2131%
2132% o width: the image width.
2133%
2134% o height: the image height.
2135%
2136% o background: the image color.
2137%
2138*/
2139MagickExport Image *NewMagickImage(const ImageInfo *image_info,
2140 const unsigned long width,const unsigned long height,
2141 const MagickPixelPacket *background)
2142{
2143 CacheView
2144 *image_view;
2145
2146 ExceptionInfo
2147 *exception;
2148
2149 Image
2150 *image;
2151
2152 long
2153 y;
2154
2155 MagickBooleanType
2156 status;
2157
2158 assert(image_info != (const ImageInfo *) NULL);
2159 if (image_info->debug != MagickFalse)
2160 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2161 assert(image_info->signature == MagickSignature);
2162 assert(background != (const MagickPixelPacket *) NULL);
2163 image=AcquireImage(image_info);
2164 image->columns=width;
2165 image->rows=height;
2166 image->colorspace=background->colorspace;
2167 image->matte=background->matte;
2168 image->fuzz=background->fuzz;
2169 image->depth=background->depth;
2170 status=MagickTrue;
2171 exception=(&image->exception);
2172 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002173#if defined(MAGICKCORE_OPENMP_SUPPORT)
2174 #pragma omp parallel for schedule(dynamic,4) shared(status)
2175#endif
cristy3ed852e2009-09-05 21:47:34 +00002176 for (y=0; y < (long) image->rows; y++)
2177 {
2178 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002179 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002180
2181 register long
2182 x;
2183
2184 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002185 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002186
cristy48974b92009-12-19 02:36:06 +00002187 if (status == MagickFalse)
2188 continue;
cristy3ed852e2009-09-05 21:47:34 +00002189 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2190 if (q == (PixelPacket *) NULL)
2191 {
2192 status=MagickFalse;
2193 continue;
2194 }
2195 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2196 for (x=0; x < (long) image->columns; x++)
2197 {
2198 SetPixelPacket(image,background,q,indexes+x);
2199 q++;
2200 }
2201 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2202 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002203 }
2204 image_view=DestroyCacheView(image_view);
2205 if (status == MagickFalse)
2206 image=DestroyImage(image);
2207 return(image);
2208}
2209
2210/*
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212% %
2213% %
2214% %
2215% R e f e r e n c e I m a g e %
2216% %
2217% %
2218% %
2219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220%
2221% ReferenceImage() increments the reference count associated with an image
2222% returning a pointer to the image.
2223%
2224% The format of the ReferenceImage method is:
2225%
2226% Image *ReferenceImage(Image *image)
2227%
2228% A description of each parameter follows:
2229%
2230% o image: the image.
2231%
2232*/
2233MagickExport Image *ReferenceImage(Image *image)
2234{
2235 assert(image != (Image *) NULL);
2236 if (image->debug != MagickFalse)
2237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2238 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002239 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002240 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002241 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002242 return(image);
2243}
2244
2245/*
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247% %
2248% %
2249% %
2250% R e s e t I m a g e P a g e %
2251% %
2252% %
2253% %
2254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255%
2256% ResetImagePage() resets the image page canvas and position.
2257%
2258% The format of the ResetImagePage method is:
2259%
2260% MagickBooleanType ResetImagePage(Image *image,const char *page)
2261%
2262% A description of each parameter follows:
2263%
2264% o image: the image.
2265%
2266% o page: the relative page specification.
2267%
2268*/
2269MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2270{
2271 MagickStatusType
2272 flags;
2273
2274 RectangleInfo
2275 geometry;
2276
2277 assert(image != (Image *) NULL);
2278 assert(image->signature == MagickSignature);
2279 if (image->debug != MagickFalse)
2280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2281 flags=ParseAbsoluteGeometry(page,&geometry);
2282 if ((flags & WidthValue) != 0)
2283 {
2284 if ((flags & HeightValue) == 0)
2285 geometry.height=geometry.width;
2286 image->page.width=geometry.width;
2287 image->page.height=geometry.height;
2288 }
2289 if ((flags & AspectValue) != 0)
2290 {
2291 if ((flags & XValue) != 0)
2292 image->page.x+=geometry.x;
2293 if ((flags & YValue) != 0)
2294 image->page.y+=geometry.y;
2295 }
2296 else
2297 {
2298 if ((flags & XValue) != 0)
2299 {
2300 image->page.x=geometry.x;
2301 if ((image->page.width == 0) && (geometry.x > 0))
2302 image->page.width=image->columns+geometry.x;
2303 }
2304 if ((flags & YValue) != 0)
2305 {
2306 image->page.y=geometry.y;
2307 if ((image->page.height == 0) && (geometry.y > 0))
2308 image->page.height=image->rows+geometry.y;
2309 }
2310 }
2311 return(MagickTrue);
2312}
2313
2314/*
2315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316% %
2317% %
2318% %
2319% S e p a r a t e I m a g e C h a n n e l %
2320% %
2321% %
2322% %
2323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2324%
2325% SeparateImageChannel() separates a channel from the image and returns it as
2326% a grayscale image. A channel is a particular color component of each pixel
2327% in the image.
2328%
2329% The format of the SeparateImageChannel method is:
2330%
2331% MagickBooleanType SeparateImageChannel(Image *image,
2332% const ChannelType channel)
2333%
2334% A description of each parameter follows:
2335%
2336% o image: the image.
2337%
2338% o channel: Identify which channel to extract: RedChannel, GreenChannel,
2339% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2340% YellowChannel, or BlackChannel.
2341%
2342*/
2343MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2344 const ChannelType channel)
2345{
2346#define SeparateImageTag "Separate/Image"
2347
2348 CacheView
2349 *image_view;
2350
2351 ExceptionInfo
2352 *exception;
2353
2354 long
2355 progress,
2356 y;
2357
2358 MagickBooleanType
2359 status;
2360
2361 assert(image != (Image *) NULL);
2362 assert(image->signature == MagickSignature);
2363 if (image->debug != MagickFalse)
2364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2365 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2366 return(MagickFalse);
2367 /*
2368 Separate image channels.
2369 */
2370 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002371 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002372 image->matte=MagickTrue;
2373 progress=0;
2374 exception=(&image->exception);
2375 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002376#if defined(MAGICKCORE_OPENMP_SUPPORT)
2377 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002378#endif
2379 for (y=0; y < (long) image->rows; y++)
2380 {
2381 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002382 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002383
2384 register long
2385 x;
2386
2387 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002388 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002389
2390 if (status == MagickFalse)
2391 continue;
2392 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2393 if (q == (PixelPacket *) NULL)
2394 {
2395 status=MagickFalse;
2396 continue;
2397 }
2398 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2399 switch (channel)
2400 {
2401 case RedChannel:
2402 {
2403 for (x=0; x < (long) image->columns; x++)
2404 {
2405 q->green=q->red;
2406 q->blue=q->red;
2407 q++;
2408 }
2409 break;
2410 }
2411 case GreenChannel:
2412 {
2413 for (x=0; x < (long) image->columns; x++)
2414 {
2415 q->red=q->green;
2416 q->blue=q->green;
2417 q++;
2418 }
2419 break;
2420 }
2421 case BlueChannel:
2422 {
2423 for (x=0; x < (long) image->columns; x++)
2424 {
2425 q->red=q->blue;
2426 q->green=q->blue;
2427 q++;
2428 }
2429 break;
2430 }
2431 case OpacityChannel:
2432 {
2433 for (x=0; x < (long) image->columns; x++)
2434 {
2435 q->red=q->opacity;
2436 q->green=q->opacity;
2437 q->blue=q->opacity;
2438 q++;
2439 }
2440 break;
2441 }
2442 case BlackChannel:
2443 {
2444 if ((image->storage_class != PseudoClass) &&
2445 (image->colorspace != CMYKColorspace))
2446 break;
2447 for (x=0; x < (long) image->columns; x++)
2448 {
2449 q->red=indexes[x];
2450 q->green=indexes[x];
2451 q->blue=indexes[x];
2452 q++;
2453 }
2454 break;
2455 }
2456 case TrueAlphaChannel:
2457 {
2458 for (x=0; x < (long) image->columns; x++)
2459 {
cristy46f08202010-01-10 04:04:21 +00002460 q->red=(Quantum) GetAlphaPixelComponent(q);
2461 q->green=(Quantum) GetAlphaPixelComponent(q);
2462 q->blue=(Quantum) GetAlphaPixelComponent(q);
cristy3ed852e2009-09-05 21:47:34 +00002463 q++;
2464 }
2465 break;
2466 }
2467 case GrayChannels:
2468 {
2469 for (x=0; x < (long) image->columns; x++)
2470 {
2471 q->opacity=(Quantum) (QuantumRange-PixelIntensityToQuantum(q));
2472 q++;
2473 }
2474 break;
2475 }
2476 default:
2477 break;
2478 }
2479 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2480 status=MagickFalse;
2481 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2482 {
2483 MagickBooleanType
2484 proceed;
2485
cristyb5d5f722009-11-04 03:03:49 +00002486#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002487 #pragma omp critical (MagickCore_SeparateImageChannel)
2488#endif
2489 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2490 if (proceed == MagickFalse)
2491 status=MagickFalse;
2492 }
2493 }
2494 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002495 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002496 image->matte=MagickFalse;
2497 (void) SetImageColorspace(image,RGBColorspace);
2498 return(status);
2499}
2500
2501/*
2502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503% %
2504% %
2505% %
2506% S e p a r a t e I m a g e s %
2507% %
2508% %
2509% %
2510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511%
2512% SeparateImages() returns a separate grayscale image for each channel
2513% specified.
2514%
2515% The format of the SeparateImages method is:
2516%
2517% MagickBooleanType SeparateImages(const Image *image,
2518% const ChannelType channel,ExceptionInfo *exception)
2519%
2520% A description of each parameter follows:
2521%
2522% o image: the image.
2523%
2524% o channel: Identify which channels to extract: RedChannel, GreenChannel,
2525% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2526% YellowChannel, or BlackChannel.
2527%
2528% o exception: return any errors or warnings in this structure.
2529%
2530*/
2531MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2532 ExceptionInfo *exception)
2533{
2534 Image
2535 *images,
2536 *separate_image;
2537
2538 assert(image != (Image *) NULL);
2539 assert(image->signature == MagickSignature);
2540 if (image->debug != MagickFalse)
2541 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2542 images=NewImageList();
2543 if ((channel & RedChannel) != 0)
2544 {
2545 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2546 (void) SeparateImageChannel(separate_image,RedChannel);
2547 AppendImageToList(&images,separate_image);
2548 }
2549 if ((channel & GreenChannel) != 0)
2550 {
2551 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2552 (void) SeparateImageChannel(separate_image,GreenChannel);
2553 AppendImageToList(&images,separate_image);
2554 }
2555 if ((channel & BlueChannel) != 0)
2556 {
2557 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2558 (void) SeparateImageChannel(separate_image,BlueChannel);
2559 AppendImageToList(&images,separate_image);
2560 }
2561 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
2562 {
2563 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2564 (void) SeparateImageChannel(separate_image,BlackChannel);
2565 AppendImageToList(&images,separate_image);
2566 }
2567 if ((channel & OpacityChannel) != 0)
2568 {
2569 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2570 (void) SeparateImageChannel(separate_image,OpacityChannel);
2571 AppendImageToList(&images,separate_image);
2572 }
2573 return(images);
2574}
2575
2576/*
2577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578% %
2579% %
2580% %
2581% S e t I m a g e A l p h a C h a n n e l %
2582% %
2583% %
2584% %
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586%
2587% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2588% channel.
2589%
2590% The format of the SetImageAlphaChannel method is:
2591%
2592% MagickBooleanType SetImageAlphaChannel(Image *image,
2593% const AlphaChannelType alpha_type)
2594%
2595% A description of each parameter follows:
2596%
2597% o image: the image.
2598%
2599% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2600% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
2601% OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
2602% ShapeAlphaChannel, and TransparentAlphaChannel.
2603%
2604*/
2605MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2606 const AlphaChannelType alpha_type)
2607{
2608 MagickBooleanType
2609 status;
2610
2611 assert(image != (Image *) NULL);
2612 if (image->debug != MagickFalse)
2613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2614 assert(image->signature == MagickSignature);
2615 status=MagickFalse;
2616 switch (alpha_type)
2617 {
2618 case ActivateAlphaChannel:
2619 {
2620 image->matte=MagickTrue;
2621 break;
2622 }
2623 case BackgroundAlphaChannel:
2624 {
2625 CacheView
2626 *image_view;
2627
2628 ExceptionInfo
2629 *exception;
2630
2631 IndexPacket
2632 index;
2633
2634 long
2635 y;
2636
2637 MagickBooleanType
2638 status;
2639
2640 MagickPixelPacket
2641 background;
2642
2643 PixelPacket
2644 pixel;
2645
2646 /*
2647 Set transparent pixels to background color.
2648 */
2649 if (image->matte == MagickFalse)
2650 break;
2651 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2652 break;
2653 GetMagickPixelPacket(image,&background);
2654 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2655 NULL,&background);
2656 if (image->colorspace == CMYKColorspace)
2657 ConvertRGBToCMYK(&background);
2658 index=0;
2659 SetPixelPacket(image,&background,&pixel,&index);
2660 status=MagickTrue;
2661 exception=(&image->exception);
2662 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002663 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2664 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002665 #endif
2666 for (y=0; y < (long) image->rows; y++)
2667 {
2668 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002669 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002670
2671 register long
2672 x;
2673
2674 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002675 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002676
2677 if (status == MagickFalse)
2678 continue;
2679 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2680 exception);
2681 if (q == (PixelPacket *) NULL)
2682 {
2683 status=MagickFalse;
2684 continue;
2685 }
2686 for (x=0; x < (long) image->columns; x++)
2687 {
2688 if (q->opacity == TransparentOpacity)
2689 {
2690 q->red=pixel.red;
2691 q->green=pixel.green;
2692 q->blue=pixel.blue;
2693 }
2694 q++;
2695 }
2696 if (image->colorspace == CMYKColorspace)
2697 {
2698 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2699 for (x=0; x < (long) image->columns; x++)
2700 indexes[x]=index;
2701 }
2702 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2703 status=MagickFalse;
2704 }
2705 image_view=DestroyCacheView(image_view);
2706 return(status);
2707 }
2708 case DeactivateAlphaChannel:
2709 {
2710 image->matte=MagickFalse;
2711 break;
2712 }
2713 case ShapeAlphaChannel:
2714 case CopyAlphaChannel:
2715 {
2716 /*
2717 Special usage case for SeparateImageChannel(): copy grayscale color to
2718 the alpha channel.
2719 */
2720 status=SeparateImageChannel(image,GrayChannels);
2721 image->matte=MagickTrue; /* make sure transparency is now on! */
2722 if (alpha_type == ShapeAlphaChannel)
2723 {
2724 MagickPixelPacket
2725 background;
2726
2727 /*
2728 Reset all color channels to background color.
2729 */
2730 GetMagickPixelPacket(image,&background);
2731 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
2732 NULL,&background);
cristy308b4e62009-09-21 14:40:44 +00002733 (void) LevelColorsImage(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002734 }
2735 break;
2736 }
2737 case ExtractAlphaChannel:
2738 {
2739 status=SeparateImageChannel(image,TrueAlphaChannel);
2740 image->matte=MagickFalse;
2741 break;
2742 }
2743 case ResetAlphaChannel:
2744 case OpaqueAlphaChannel:
2745 {
2746 status=SetImageOpacity(image,OpaqueOpacity);
2747 image->matte=MagickTrue;
2748 break;
2749 }
2750 case TransparentAlphaChannel:
2751 {
2752 status=SetImageOpacity(image,TransparentOpacity);
2753 image->matte=MagickTrue;
2754 break;
2755 }
2756 case SetAlphaChannel:
2757 {
2758 if (image->matte == MagickFalse)
2759 {
2760 status=SetImageOpacity(image,OpaqueOpacity);
2761 image->matte=MagickTrue;
2762 }
2763 break;
2764 }
2765 case UndefinedAlphaChannel:
2766 break;
2767 }
2768 return(status);
2769}
2770
2771/*
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773% %
2774% %
2775% %
2776% S e t I m a g e B a c k g r o u n d C o l o r %
2777% %
2778% %
2779% %
2780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781%
2782% SetImageBackgroundColor() initializes the image pixels to the image
2783% background color. The background color is defined by the background_color
2784% member of the image structure.
2785%
2786% The format of the SetImage method is:
2787%
2788% MagickBooleanType SetImageBackgroundColor(Image *image)
2789%
2790% A description of each parameter follows:
2791%
2792% o image: the image.
2793%
2794*/
2795MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2796{
2797 CacheView
2798 *image_view;
2799
2800 ExceptionInfo
2801 *exception;
2802
2803 IndexPacket
2804 index;
2805
2806 long
2807 y;
2808
2809 MagickBooleanType
2810 status;
2811
2812 MagickPixelPacket
2813 background;
2814
2815 PixelPacket
2816 pixel;
2817
2818 assert(image != (Image *) NULL);
2819 if (image->debug != MagickFalse)
2820 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2821 assert(image->signature == MagickSignature);
2822 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2823 return(MagickFalse);
2824 if (image->background_color.opacity != OpaqueOpacity)
2825 image->matte=MagickTrue;
2826 GetMagickPixelPacket(image,&background);
2827 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2828 NULL,&background);
2829 if (image->colorspace == CMYKColorspace)
2830 ConvertRGBToCMYK(&background);
2831 index=0;
2832 SetPixelPacket(image,&background,&pixel,&index);
2833 /*
2834 Set image background color.
2835 */
2836 status=MagickTrue;
2837 exception=(&image->exception);
2838 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002839#if defined(MAGICKCORE_OPENMP_SUPPORT)
2840 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002841#endif
2842 for (y=0; y < (long) image->rows; y++)
2843 {
2844 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002845 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002846
2847 register long
2848 x;
2849
2850 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002851 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002852
2853 if (status == MagickFalse)
2854 continue;
2855 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2856 if (q == (PixelPacket *) NULL)
2857 {
2858 status=MagickFalse;
2859 continue;
2860 }
2861 for (x=0; x < (long) image->columns; x++)
2862 *q++=pixel;
2863 if (image->colorspace == CMYKColorspace)
2864 {
2865 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2866 for (x=0; x < (long) image->columns; x++)
2867 indexes[x]=index;
2868 }
2869 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2870 status=MagickFalse;
2871 }
2872 image_view=DestroyCacheView(image_view);
2873 return(status);
2874}
2875
2876/*
2877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878% %
2879% %
2880% %
2881% S e t I m a g e S t o r a g e C l a s s %
2882% %
2883% %
2884% %
2885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886%
2887% SetImageStorageClass() sets the image class: DirectClass for true color
2888% images or PseudoClass for colormapped images.
2889%
2890% The format of the SetImageStorageClass method is:
2891%
2892% MagickBooleanType SetImageStorageClass(Image *image,
2893% const ClassType storage_class)
2894%
2895% A description of each parameter follows:
2896%
2897% o image: the image.
2898%
2899% o storage_class: The image class.
2900%
2901*/
2902MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2903 const ClassType storage_class)
2904{
2905 Cache
2906 cache;
2907
2908 if (image->storage_class == storage_class)
2909 return(MagickTrue);
2910 image->storage_class=storage_class;
2911 cache=GetImagePixelCache(image,MagickTrue,&image->exception);
2912 return(cache == (Cache) NULL ? MagickFalse : MagickTrue);
2913}
2914
2915/*
2916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2917% %
2918% %
2919% %
2920% S e t I m a g e C l i p M a s k %
2921% %
2922% %
2923% %
2924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925%
2926% SetImageClipMask() associates a clip path with the image. The clip path
2927% must be the same dimensions as the image. Set any pixel component of
2928% the clip path to TransparentOpacity to prevent that corresponding image
2929% pixel component from being updated when SyncAuthenticPixels() is applied.
2930%
2931% The format of the SetImageClipMask method is:
2932%
2933% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2934%
2935% A description of each parameter follows:
2936%
2937% o image: the image.
2938%
2939% o clip_mask: the image clip path.
2940%
2941*/
2942MagickExport MagickBooleanType SetImageClipMask(Image *image,
2943 const Image *clip_mask)
2944{
2945 assert(image != (Image *) NULL);
2946 if (image->debug != MagickFalse)
2947 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2948 assert(image->signature == MagickSignature);
2949 if (clip_mask != (const Image *) NULL)
2950 if ((clip_mask->columns != image->columns) ||
2951 (clip_mask->rows != image->rows))
2952 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2953 if (image->clip_mask != (Image *) NULL)
2954 image->clip_mask=DestroyImage(image->clip_mask);
2955 image->clip_mask=NewImageList();
2956 if (clip_mask == (Image *) NULL)
2957 return(MagickTrue);
2958 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2959 return(MagickFalse);
2960 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
2961 if (image->clip_mask == (Image *) NULL)
2962 return(MagickFalse);
2963 return(MagickTrue);
2964}
2965
2966/*
2967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2968% %
2969% %
2970% %
2971% S e t I m a g e E x t e n t %
2972% %
2973% %
2974% %
2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976%
2977% SetImageExtent() sets the image size (i.e. columns & rows).
2978%
2979% The format of the SetImageExtent method is:
2980%
2981% MagickBooleanType SetImageExtent(Image *image,
2982% const unsigned long columns,const unsigned long rows)
2983%
2984% A description of each parameter follows:
2985%
2986% o image: the image.
2987%
2988% o columns: The image width in pixels.
2989%
2990% o rows: The image height in pixels.
2991%
2992*/
2993MagickExport MagickBooleanType SetImageExtent(Image *image,
2994 const unsigned long columns,const unsigned long rows)
2995{
2996 Cache
2997 cache;
2998
2999 if ((columns != 0) && (rows != 0))
3000 {
3001 image->columns=columns;
3002 image->rows=rows;
3003 }
3004 cache=GetImagePixelCache(image,MagickTrue,&image->exception);
3005 return(cache == (Cache) NULL ? MagickFalse : MagickTrue);
3006}
3007
3008/*
3009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010% %
3011% %
3012% %
3013+ S e t I m a g e I n f o %
3014% %
3015% %
3016% %
3017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018%
3019% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3020% It is set to a type of image format based on the prefix or suffix of the
3021% filename. For example, `ps:image' returns PS indicating a Postscript image.
3022% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3023% precendence over the suffix. Use an optional index enclosed in brackets
3024% after a file name to specify a desired scene of a multi-resolution image
3025% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3026% indicates success.
3027%
3028% The format of the SetImageInfo method is:
3029%
3030% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003031% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003032%
3033% A description of each parameter follows:
3034%
cristyd965a422010-03-03 17:47:35 +00003035% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003036%
cristyd965a422010-03-03 17:47:35 +00003037% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003038%
3039% o exception: return any errors or warnings in this structure.
3040%
3041*/
3042MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003043 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003044{
3045 char
3046 extension[MaxTextExtent],
3047 filename[MaxTextExtent],
3048 magic[MaxTextExtent],
3049 *q,
3050 subimage[MaxTextExtent];
3051
3052 const MagicInfo
3053 *magic_info;
3054
3055 const MagickInfo
3056 *magick_info;
3057
3058 ExceptionInfo
3059 *sans_exception;
3060
3061 Image
3062 *image;
3063
3064 MagickBooleanType
3065 status;
3066
3067 register const char
3068 *p;
3069
3070 ssize_t
3071 count;
3072
3073 unsigned char
3074 magick[2*MaxTextExtent];
3075
3076 /*
3077 Look for 'image.format' in filename.
3078 */
3079 assert(image_info != (ImageInfo *) NULL);
3080 assert(image_info->signature == MagickSignature);
3081 if (image_info->debug != MagickFalse)
3082 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3083 image_info->filename);
3084 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003085 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003086 {
cristyd965a422010-03-03 17:47:35 +00003087 GetPathComponent(image_info->filename,SubimagePath,subimage);
3088 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003089 {
cristyd965a422010-03-03 17:47:35 +00003090 /*
3091 Look for scene specification (e.g. img0001.pcd[4]).
3092 */
3093 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3094 {
3095 if (IsGeometry(subimage) != MagickFalse)
3096 (void) CloneString(&image_info->extract,subimage);
3097 }
3098 else
3099 {
3100 unsigned long
3101 first,
3102 last;
cristy3ed852e2009-09-05 21:47:34 +00003103
cristyd965a422010-03-03 17:47:35 +00003104 (void) CloneString(&image_info->scenes,subimage);
3105 image_info->scene=StringToUnsignedLong(image_info->scenes);
3106 image_info->number_scenes=image_info->scene;
3107 p=image_info->scenes;
3108 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3109 {
3110 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3111 (*p == ','))
3112 p++;
3113 first=(unsigned long) strtol(p,&q,10);
3114 last=first;
3115 while (isspace((int) ((unsigned char) *q)) != 0)
3116 q++;
3117 if (*q == '-')
3118 last=(unsigned long) strtol(q+1,&q,10);
3119 if (first > last)
3120 Swap(first,last);
3121 if (first < image_info->scene)
3122 image_info->scene=first;
3123 if (last > image_info->number_scenes)
3124 image_info->number_scenes=last;
3125 p=q;
3126 }
3127 image_info->number_scenes-=image_info->scene-1;
3128 image_info->subimage=image_info->scene;
3129 image_info->subrange=image_info->number_scenes;
3130 }
cristy3ed852e2009-09-05 21:47:34 +00003131 }
3132 }
3133 *extension='\0';
3134 GetPathComponent(image_info->filename,ExtensionPath,extension);
3135#if defined(MAGICKCORE_ZLIB_DELEGATE)
3136 if (*extension != '\0')
3137 if ((LocaleCompare(extension,"gz") == 0) ||
3138 (LocaleCompare(extension,"Z") == 0) ||
3139 (LocaleCompare(extension,"wmz") == 0))
3140 {
3141 char
3142 path[MaxTextExtent];
3143
3144 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3145 path[strlen(path)-strlen(extension)-1]='\0';
3146 GetPathComponent(path,ExtensionPath,extension);
3147 }
3148#endif
3149#if defined(MAGICKCORE_BZLIB_DELEGATE)
3150 if (*extension != '\0')
3151 if (LocaleCompare(extension,"bz2") == 0)
3152 {
3153 char
3154 path[MaxTextExtent];
3155
3156 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3157 path[strlen(path)-strlen(extension)-1]='\0';
3158 GetPathComponent(path,ExtensionPath,extension);
3159 }
3160#endif
3161 image_info->affirm=MagickFalse;
3162 sans_exception=AcquireExceptionInfo();
3163 if (*extension != '\0')
3164 {
3165 MagickFormatType
3166 format_type;
3167
3168 register long
3169 i;
3170
3171 static const char
3172 *format_type_formats[] =
3173 {
3174 "AUTOTRACE",
3175 "BROWSE",
3176 "DCRAW",
3177 "EDIT",
3178 "EPHEMERAL",
3179 "LAUNCH",
3180 "MPEG:DECODE",
3181 "MPEG:ENCODE",
3182 "PRINT",
3183 "PS:ALPHA",
3184 "PS:CMYK",
3185 "PS:COLOR",
3186 "PS:GRAY",
3187 "PS:MONO",
3188 "SCAN",
3189 "SHOW",
3190 "WIN",
3191 (char *) NULL
3192 };
3193
3194 /*
3195 User specified image format.
3196 */
3197 (void) CopyMagickString(magic,extension,MaxTextExtent);
3198 LocaleUpper(magic);
3199 /*
3200 Look for explicit image formats.
3201 */
3202 format_type=UndefinedFormatType;
3203 i=0;
cristydd9a2532010-02-20 19:26:46 +00003204 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003205 (format_type_formats[i] != (char *) NULL))
3206 {
3207 if ((*magic == *format_type_formats[i]) &&
3208 (LocaleCompare(magic,format_type_formats[i]) == 0))
3209 format_type=ExplicitFormatType;
3210 i++;
3211 }
3212 magick_info=GetMagickInfo(magic,sans_exception);
3213 if ((magick_info != (const MagickInfo *) NULL) &&
3214 (magick_info->format_type != UndefinedFormatType))
3215 format_type=magick_info->format_type;
3216 if (format_type == UndefinedFormatType)
3217 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3218 else
3219 if (format_type == ExplicitFormatType)
3220 {
3221 image_info->affirm=MagickTrue;
3222 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3223 }
3224 if (LocaleCompare(magic,"RGB") == 0)
3225 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3226 }
3227 /*
3228 Look for explicit 'format:image' in filename.
3229 */
3230 *magic='\0';
3231 GetPathComponent(image_info->filename,MagickPath,magic);
3232 if (*magic == '\0')
3233 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3234 else
3235 {
3236 /*
3237 User specified image format.
3238 */
3239 LocaleUpper(magic);
3240 if (IsMagickConflict(magic) == MagickFalse)
3241 {
3242 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3243 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3244 image_info->affirm=MagickTrue;
3245 else
3246 image_info->temporary=MagickTrue;
3247 }
3248 }
3249 magick_info=GetMagickInfo(magic,sans_exception);
3250 sans_exception=DestroyExceptionInfo(sans_exception);
3251 if ((magick_info == (const MagickInfo *) NULL) ||
3252 (GetMagickEndianSupport(magick_info) == MagickFalse))
3253 image_info->endian=UndefinedEndian;
3254 GetPathComponent(image_info->filename,CanonicalPath,filename);
3255 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003256 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003257 {
3258 /*
cristyd965a422010-03-03 17:47:35 +00003259 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003260 */
cristyd965a422010-03-03 17:47:35 +00003261 (void) InterpretImageFilename(image_info,(Image *) NULL,
3262 image_info->filename,(int) image_info->scene,filename);
3263 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3264 (strchr(filename,'%') == (char *) NULL))
3265 image_info->adjoin=MagickFalse;
3266 }
3267 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3268 {
3269 /*
3270 Some image formats do not support multiple frames per file.
3271 */
cristy3ed852e2009-09-05 21:47:34 +00003272 magick_info=GetMagickInfo(magic,exception);
3273 if (magick_info != (const MagickInfo *) NULL)
3274 if (GetMagickAdjoin(magick_info) == MagickFalse)
3275 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003276 }
3277 if (image_info->affirm != MagickFalse)
3278 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003279 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003280 {
3281 /*
cristyd965a422010-03-03 17:47:35 +00003282 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003283 */
cristyd965a422010-03-03 17:47:35 +00003284 image=AcquireImage(image_info);
3285 (void) CopyMagickString(image->filename,image_info->filename,
3286 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003287 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3288 if (status == MagickFalse)
3289 {
3290 image=DestroyImage(image);
3291 return(MagickFalse);
3292 }
cristyd965a422010-03-03 17:47:35 +00003293 if ((IsBlobSeekable(image) == MagickFalse) ||
3294 (IsBlobExempt(image) != MagickFalse))
3295 {
3296 /*
3297 Copy standard input or pipe to temporary file.
3298 */
3299 *filename='\0';
3300 status=ImageToFile(image,filename,exception);
3301 (void) CloseBlob(image);
3302 if (status == MagickFalse)
3303 {
3304 image=DestroyImage(image);
3305 return(MagickFalse);
3306 }
3307 SetImageInfoFile(image_info,(FILE *) NULL);
3308 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3309 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3310 if (status == MagickFalse)
3311 {
3312 image=DestroyImage(image);
3313 return(MagickFalse);
3314 }
3315 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3316 image_info->temporary=MagickTrue;
3317 }
3318 (void) ResetMagickMemory(magick,0,sizeof(magick));
3319 count=ReadBlob(image,2*MaxTextExtent,magick);
3320 (void) CloseBlob(image);
3321 image=DestroyImage(image);
3322 /*
3323 Check magic.xml configuration file.
3324 */
3325 sans_exception=AcquireExceptionInfo();
3326 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3327 if ((magic_info != (const MagicInfo *) NULL) &&
3328 (GetMagicName(magic_info) != (char *) NULL))
3329 {
3330 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3331 MaxTextExtent);
3332 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3333 if ((magick_info == (const MagickInfo *) NULL) ||
3334 (GetMagickEndianSupport(magick_info) == MagickFalse))
3335 image_info->endian=UndefinedEndian;
3336 sans_exception=DestroyExceptionInfo(sans_exception);
3337 return(MagickTrue);
3338 }
cristy3ed852e2009-09-05 21:47:34 +00003339 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3340 if ((magick_info == (const MagickInfo *) NULL) ||
3341 (GetMagickEndianSupport(magick_info) == MagickFalse))
3342 image_info->endian=UndefinedEndian;
3343 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003344 }
cristy3ed852e2009-09-05 21:47:34 +00003345 return(MagickTrue);
3346}
3347
3348/*
3349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3350% %
3351% %
3352% %
3353% S e t I m a g e I n f o B l o b %
3354% %
3355% %
3356% %
3357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3358%
3359% SetImageInfoBlob() sets the image info blob member.
3360%
3361% The format of the SetImageInfoBlob method is:
3362%
3363% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3364% const size_t length)
3365%
3366% A description of each parameter follows:
3367%
3368% o image_info: the image info.
3369%
3370% o blob: the blob.
3371%
3372% o length: the blob length.
3373%
3374*/
3375MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3376 const size_t length)
3377{
3378 assert(image_info != (ImageInfo *) NULL);
3379 assert(image_info->signature == MagickSignature);
3380 if (image_info->debug != MagickFalse)
3381 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3382 image_info->filename);
3383 image_info->blob=(void *) blob;
3384 image_info->length=length;
3385}
3386
3387/*
3388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3389% %
3390% %
3391% %
3392% S e t I m a g e I n f o F i l e %
3393% %
3394% %
3395% %
3396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397%
3398% SetImageInfoFile() sets the image info file member.
3399%
3400% The format of the SetImageInfoFile method is:
3401%
3402% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3403%
3404% A description of each parameter follows:
3405%
3406% o image_info: the image info.
3407%
3408% o file: the file.
3409%
3410*/
3411MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3412{
3413 assert(image_info != (ImageInfo *) NULL);
3414 assert(image_info->signature == MagickSignature);
3415 if (image_info->debug != MagickFalse)
3416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3417 image_info->filename);
3418 image_info->file=file;
3419}
3420
3421/*
3422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3423% %
3424% %
3425% %
3426% S e t I m a g e M a s k %
3427% %
3428% %
3429% %
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431%
3432% SetImageMask() associates a mask with the image. The mask must be the same
3433% dimensions as the image.
3434%
3435% The format of the SetImageMask method is:
3436%
3437% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3438%
3439% A description of each parameter follows:
3440%
3441% o image: the image.
3442%
3443% o mask: the image mask.
3444%
3445*/
3446MagickExport MagickBooleanType SetImageMask(Image *image,
3447 const Image *mask)
3448{
3449 assert(image != (Image *) NULL);
3450 if (image->debug != MagickFalse)
3451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3452 assert(image->signature == MagickSignature);
3453 if (mask != (const Image *) NULL)
3454 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3455 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3456 if (image->mask != (Image *) NULL)
3457 image->mask=DestroyImage(image->mask);
3458 image->mask=NewImageList();
3459 if (mask == (Image *) NULL)
3460 return(MagickTrue);
3461 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3462 return(MagickFalse);
3463 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3464 if (image->mask == (Image *) NULL)
3465 return(MagickFalse);
3466 return(MagickTrue);
3467}
3468
3469/*
3470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3471% %
3472% %
3473% %
3474% S e t I m a g e O p a c i t y %
3475% %
3476% %
3477% %
3478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3479%
3480% SetImageOpacity() sets the opacity levels of the image.
3481%
3482% The format of the SetImageOpacity method is:
3483%
3484% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3485%
3486% A description of each parameter follows:
3487%
3488% o image: the image.
3489%
3490% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3491% fully transparent.
3492%
3493*/
3494MagickExport MagickBooleanType SetImageOpacity(Image *image,
3495 const Quantum opacity)
3496{
3497 CacheView
3498 *image_view;
3499
3500 ExceptionInfo
3501 *exception;
3502
3503 long
3504 y;
3505
3506 MagickBooleanType
3507 status;
3508
3509 assert(image != (Image *) NULL);
3510 if (image->debug != MagickFalse)
3511 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3512 assert(image->signature == MagickSignature);
3513 image->matte=opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3514 status=MagickTrue;
3515 exception=(&image->exception);
3516 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003517#if defined(MAGICKCORE_OPENMP_SUPPORT)
3518 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003519#endif
3520 for (y=0; y < (long) image->rows; y++)
3521 {
3522 register long
3523 x;
3524
3525 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003526 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003527
3528 if (status == MagickFalse)
3529 continue;
3530 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3531 if (q == (PixelPacket *) NULL)
3532 {
3533 status=MagickFalse;
3534 continue;
3535 }
3536 for (x=0; x < (long) image->columns; x++)
3537 {
cristy46f08202010-01-10 04:04:21 +00003538 SetOpacityPixelComponent(q,opacity);
cristy3ed852e2009-09-05 21:47:34 +00003539 q++;
3540 }
3541 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3542 status=MagickFalse;
3543 }
3544 image_view=DestroyCacheView(image_view);
3545 return(status);
3546}
3547
3548/*
3549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3550% %
3551% %
3552% %
3553% S e t I m a g e T y p e %
3554% %
3555% %
3556% %
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558%
3559% SetImageType() sets the type of image. Choose from these types:
3560%
3561% Bilevel Grayscale GrayscaleMatte
3562% Palette PaletteMatte TrueColor
3563% TrueColorMatte ColorSeparation ColorSeparationMatte
3564% OptimizeType
3565%
3566% The format of the SetImageType method is:
3567%
3568% MagickBooleanType SetImageType(Image *image,const ImageType type)
3569%
3570% A description of each parameter follows:
3571%
3572% o image: the image.
3573%
3574% o type: Image type.
3575%
3576*/
3577MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3578{
3579 const char
3580 *artifact;
3581
3582 ImageInfo
3583 *image_info;
3584
3585 MagickBooleanType
3586 status;
3587
3588 QuantizeInfo
3589 *quantize_info;
3590
3591 assert(image != (Image *) NULL);
3592 if (image->debug != MagickFalse)
3593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3594 assert(image->signature == MagickSignature);
3595 status=MagickTrue;
3596 image_info=AcquireImageInfo();
3597 image_info->dither=image->dither;
3598 artifact=GetImageArtifact(image,"dither");
3599 if (artifact != (const char *) NULL)
3600 (void) SetImageOption(image_info,"dither",artifact);
3601 switch (type)
3602 {
3603 case BilevelType:
3604 {
3605 if (IsGrayImage(image,&image->exception) == MagickFalse)
3606 status=TransformImageColorspace(image,GRAYColorspace);
3607 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
3608 {
3609 quantize_info=AcquireQuantizeInfo(image_info);
3610 quantize_info->number_colors=2;
3611 quantize_info->colorspace=GRAYColorspace;
3612 status=QuantizeImage(quantize_info,image);
3613 quantize_info=DestroyQuantizeInfo(quantize_info);
3614 }
3615 image->matte=MagickFalse;
3616 break;
3617 }
3618 case GrayscaleType:
3619 {
3620 if (IsGrayImage(image,&image->exception) == MagickFalse)
3621 status=TransformImageColorspace(image,GRAYColorspace);
3622 image->matte=MagickFalse;
3623 break;
3624 }
3625 case GrayscaleMatteType:
3626 {
3627 if (IsGrayImage(image,&image->exception) == MagickFalse)
3628 status=TransformImageColorspace(image,GRAYColorspace);
3629 if (image->matte == MagickFalse)
3630 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3631 break;
3632 }
3633 case PaletteType:
3634 {
3635 if (image->colorspace != RGBColorspace)
3636 status=TransformImageColorspace(image,RGBColorspace);
3637 if ((image->storage_class == DirectClass) || (image->colors > 256))
3638 {
3639 quantize_info=AcquireQuantizeInfo(image_info);
3640 quantize_info->number_colors=256;
3641 status=QuantizeImage(quantize_info,image);
3642 quantize_info=DestroyQuantizeInfo(quantize_info);
3643 }
3644 image->matte=MagickFalse;
3645 break;
3646 }
3647 case PaletteBilevelMatteType:
3648 {
3649 if (image->colorspace != RGBColorspace)
3650 status=TransformImageColorspace(image,RGBColorspace);
3651 if (image->matte == MagickFalse)
3652 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3653 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3654 quantize_info=AcquireQuantizeInfo(image_info);
3655 status=QuantizeImage(quantize_info,image);
3656 quantize_info=DestroyQuantizeInfo(quantize_info);
3657 break;
3658 }
3659 case PaletteMatteType:
3660 {
3661 if (image->colorspace != RGBColorspace)
3662 status=TransformImageColorspace(image,RGBColorspace);
3663 if (image->matte == MagickFalse)
3664 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3665 quantize_info=AcquireQuantizeInfo(image_info);
3666 quantize_info->colorspace=TransparentColorspace;
3667 status=QuantizeImage(quantize_info,image);
3668 quantize_info=DestroyQuantizeInfo(quantize_info);
3669 break;
3670 }
3671 case TrueColorType:
3672 {
3673 if (image->colorspace != RGBColorspace)
3674 status=TransformImageColorspace(image,RGBColorspace);
3675 if (image->storage_class != DirectClass)
3676 status=SetImageStorageClass(image,DirectClass);
3677 image->matte=MagickFalse;
3678 break;
3679 }
3680 case TrueColorMatteType:
3681 {
3682 if (image->colorspace != RGBColorspace)
3683 status=TransformImageColorspace(image,RGBColorspace);
3684 if (image->storage_class != DirectClass)
3685 status=SetImageStorageClass(image,DirectClass);
3686 if (image->matte == MagickFalse)
3687 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3688 break;
3689 }
3690 case ColorSeparationType:
3691 {
3692 if (image->colorspace != CMYKColorspace)
3693 {
3694 if (image->colorspace != RGBColorspace)
3695 status=TransformImageColorspace(image,RGBColorspace);
3696 status=TransformImageColorspace(image,CMYKColorspace);
3697 }
3698 if (image->storage_class != DirectClass)
3699 status=SetImageStorageClass(image,DirectClass);
3700 image->matte=MagickFalse;
3701 break;
3702 }
3703 case ColorSeparationMatteType:
3704 {
3705 if (image->colorspace != CMYKColorspace)
3706 {
3707 if (image->colorspace != RGBColorspace)
3708 status=TransformImageColorspace(image,RGBColorspace);
3709 status=TransformImageColorspace(image,CMYKColorspace);
3710 }
3711 if (image->storage_class != DirectClass)
3712 status=SetImageStorageClass(image,DirectClass);
3713 if (image->matte == MagickFalse)
3714 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3715 break;
3716 }
3717 case OptimizeType:
3718 case UndefinedType:
3719 break;
3720 }
3721 image->type=type;
3722 image_info=DestroyImageInfo(image_info);
3723 return(status);
3724}
3725
3726/*
3727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3728% %
3729% %
3730% %
3731% 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 %
3732% %
3733% %
3734% %
3735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736%
3737% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3738% image and returns the previous setting. A virtual pixel is any pixel access
3739% that is outside the boundaries of the image cache.
3740%
3741% The format of the SetImageVirtualPixelMethod() method is:
3742%
3743% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3744% const VirtualPixelMethod virtual_pixel_method)
3745%
3746% A description of each parameter follows:
3747%
3748% o image: the image.
3749%
3750% o virtual_pixel_method: choose the type of virtual pixel.
3751%
3752*/
3753MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3754 const VirtualPixelMethod virtual_pixel_method)
3755{
3756 assert(image != (const Image *) NULL);
3757 assert(image->signature == MagickSignature);
3758 if (image->debug != MagickFalse)
3759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3760 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3761}
3762
3763/*
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765% %
3766% %
3767% %
cristy3ed852e2009-09-05 21:47:34 +00003768% S t r i p I m a g e %
3769% %
3770% %
3771% %
3772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773%
cristy376bda92009-12-22 21:15:23 +00003774% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00003775%
3776% The format of the StripImage method is:
3777%
3778% MagickBooleanType StripImage(Image *image)
3779%
3780% A description of each parameter follows:
3781%
3782% o image: the image.
3783%
3784*/
3785MagickExport MagickBooleanType StripImage(Image *image)
3786{
3787 assert(image != (Image *) NULL);
3788 if (image->debug != MagickFalse)
3789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3790 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00003791 (void) DeleteImageProperty(image,"comment");
cristy3ed852e2009-09-05 21:47:34 +00003792 return(MagickTrue);
3793}
3794
3795/*
3796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3797% %
3798% %
3799% %
3800+ S y n c I m a g e %
3801% %
3802% %
3803% %
3804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3805%
3806% SyncImage() initializes the red, green, and blue intensities of each pixel
3807% as defined by the colormap index.
3808%
3809% The format of the SyncImage method is:
3810%
3811% MagickBooleanType SyncImage(Image *image)
3812%
3813% A description of each parameter follows:
3814%
3815% o image: the image.
3816%
3817*/
3818
3819static inline IndexPacket PushColormapIndex(Image *image,
3820 const unsigned long index,MagickBooleanType *range_exception)
3821{
3822 if (index < image->colors)
3823 return((IndexPacket) index);
3824 *range_exception=MagickTrue;
3825 return((IndexPacket) 0);
3826}
3827
3828MagickExport MagickBooleanType SyncImage(Image *image)
3829{
3830 CacheView
3831 *image_view;
3832
3833 ExceptionInfo
3834 *exception;
3835
3836 long
3837 y;
3838
3839 MagickBooleanType
3840 range_exception,
3841 status;
3842
3843 assert(image != (Image *) NULL);
3844 if (image->debug != MagickFalse)
3845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3846 assert(image->signature == MagickSignature);
3847 if (image->storage_class == DirectClass)
3848 return(MagickFalse);
3849 range_exception=MagickFalse;
3850 status=MagickTrue;
3851 exception=(&image->exception);
3852 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00003853#if defined(MAGICKCORE_OPENMP_SUPPORT)
3854 #pragma omp parallel for schedule(dynamic,4) shared(status)
3855#endif
cristy3ed852e2009-09-05 21:47:34 +00003856 for (y=0; y < (long) image->rows; y++)
3857 {
3858 IndexPacket
3859 index;
3860
3861 PixelPacket
3862 pixel;
3863
3864 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003865 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003866
3867 register long
3868 x;
3869
3870 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003871 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003872
cristy48974b92009-12-19 02:36:06 +00003873 if (status == MagickFalse)
3874 continue;
cristy3ed852e2009-09-05 21:47:34 +00003875 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3876 if (q == (PixelPacket *) NULL)
3877 {
3878 status=MagickFalse;
3879 continue;
3880 }
3881 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3882 for (x=0; x < (long) image->columns; x++)
3883 {
3884 index=PushColormapIndex(image,(unsigned long) indexes[x],
3885 &range_exception);
3886 pixel=image->colormap[(long) index];
3887 q->red=pixel.red;
3888 q->green=pixel.green;
3889 q->blue=pixel.blue;
cristyd0272592010-04-21 01:01:49 +00003890 if (image->matte != MagickFalse)
3891 q->opacity=pixel.opacity;
cristy3ed852e2009-09-05 21:47:34 +00003892 q++;
3893 }
3894 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3895 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003896 }
3897 image_view=DestroyCacheView(image_view);
3898 if (range_exception != MagickFalse)
3899 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3900 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
3901 return(status);
3902}
cristy1626d332009-11-10 16:58:17 +00003903
3904/*
3905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3906% %
3907% %
3908% %
3909% S y n c I m a g e S e t t i n g s %
3910% %
3911% %
3912% %
3913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3914%
3915% SyncImageSettings() sync the image info options to the image.
3916%
3917% The format of the SyncImageSettings method is:
3918%
3919% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3920% Image *image)
3921% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
3922% Image *image)
3923%
3924% A description of each parameter follows:
3925%
3926% o image_info: the image info.
3927%
3928% o image: the image.
3929%
3930*/
3931
3932MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
3933 Image *images)
3934{
3935 Image
3936 *image;
3937
3938 assert(image_info != (const ImageInfo *) NULL);
3939 assert(image_info->signature == MagickSignature);
3940 assert(images != (Image *) NULL);
3941 assert(images->signature == MagickSignature);
3942 if (images->debug != MagickFalse)
3943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3944 image=images;
3945 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
3946 (void) SyncImageSettings(image_info,image);
3947 (void) DeleteImageOption(image_info,"page");
3948 return(MagickTrue);
3949}
3950
3951MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3952 Image *image)
3953{
3954 char
3955 property[MaxTextExtent];
3956
3957 const char
3958 *value,
3959 *option;
3960
3961 GeometryInfo
3962 geometry_info;
3963
3964 MagickStatusType
3965 flags;
3966
3967 /*
3968 Sync image options.
3969 */
3970 assert(image_info != (const ImageInfo *) NULL);
3971 assert(image_info->signature == MagickSignature);
3972 assert(image != (Image *) NULL);
3973 assert(image->signature == MagickSignature);
3974 if (image->debug != MagickFalse)
3975 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3976 option=GetImageOption(image_info,"background");
3977 if (option != (const char *) NULL)
3978 (void) QueryColorDatabase(option,&image->background_color,
3979 &image->exception);
3980 option=GetImageOption(image_info,"bias");
3981 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00003982 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00003983 option=GetImageOption(image_info,"black-point-compensation");
3984 if (option != (const char *) NULL)
3985 image->black_point_compensation=(MagickBooleanType) ParseMagickOption(
3986 MagickBooleanOptions,MagickFalse,option);
3987 option=GetImageOption(image_info,"blue-primary");
3988 if (option != (const char *) NULL)
3989 {
3990 flags=ParseGeometry(option,&geometry_info);
3991 image->chromaticity.blue_primary.x=geometry_info.rho;
3992 image->chromaticity.blue_primary.y=geometry_info.sigma;
3993 if ((flags & SigmaValue) == 0)
3994 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3995 }
3996 option=GetImageOption(image_info,"bordercolor");
3997 if (option != (const char *) NULL)
3998 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
3999 option=GetImageOption(image_info,"colors");
4000 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004001 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004002 option=GetImageOption(image_info,"compose");
4003 if (option != (const char *) NULL)
4004 image->compose=(CompositeOperator) ParseMagickOption(MagickComposeOptions,
4005 MagickFalse,option);
4006 option=GetImageOption(image_info,"compress");
4007 if (option != (const char *) NULL)
4008 image->compression=(CompressionType) ParseMagickOption(
4009 MagickCompressOptions,MagickFalse,option);
4010 option=GetImageOption(image_info,"debug");
4011 if (option != (const char *) NULL)
4012 image->debug=(MagickBooleanType) ParseMagickOption(MagickBooleanOptions,
4013 MagickFalse,option);
4014 option=GetImageOption(image_info,"delay");
4015 if (option != (const char *) NULL)
4016 {
4017 GeometryInfo
4018 geometry_info;
4019
4020 flags=ParseGeometry(option,&geometry_info);
4021 if ((flags & GreaterValue) != 0)
4022 {
cristy06609ee2010-03-17 20:21:27 +00004023 if (image->delay > (unsigned long) floor(geometry_info.rho+0.5))
4024 image->delay=(unsigned long) floor(geometry_info.rho+0.5);
cristy1626d332009-11-10 16:58:17 +00004025 }
4026 else
4027 if ((flags & LessValue) != 0)
4028 {
cristy06609ee2010-03-17 20:21:27 +00004029 if (image->delay < (unsigned long) floor(geometry_info.rho+0.5))
4030 image->ticks_per_second=(long) floor(geometry_info.sigma+0.5);
cristy1626d332009-11-10 16:58:17 +00004031 }
4032 else
cristy06609ee2010-03-17 20:21:27 +00004033 image->delay=(unsigned long) floor(geometry_info.rho+0.5);
cristy1626d332009-11-10 16:58:17 +00004034 if ((flags & SigmaValue) != 0)
cristy06609ee2010-03-17 20:21:27 +00004035 image->ticks_per_second=(long) floor(geometry_info.sigma+0.5);
cristy1626d332009-11-10 16:58:17 +00004036 }
4037 option=GetImageOption(image_info,"density");
4038 if (option != (const char *) NULL)
4039 {
4040 GeometryInfo
4041 geometry_info;
4042
4043 /*
4044 Set image density.
4045 */
4046 flags=ParseGeometry(option,&geometry_info);
4047 image->x_resolution=geometry_info.rho;
4048 image->y_resolution=geometry_info.sigma;
4049 if ((flags & SigmaValue) == 0)
4050 image->y_resolution=image->x_resolution;
4051 }
4052 option=GetImageOption(image_info,"depth");
4053 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004054 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004055 option=GetImageOption(image_info,"dispose");
4056 if (option != (const char *) NULL)
4057 image->dispose=(DisposeType) ParseMagickOption(MagickDisposeOptions,
4058 MagickFalse,option);
4059 option=GetImageOption(image_info,"endian");
4060 if (option != (const char *) NULL)
4061 image->endian=(EndianType) ParseMagickOption(MagickEndianOptions,
4062 MagickFalse,option);
4063 if (image_info->extract != (char *) NULL)
4064 (void) ParseAbsoluteGeometry(image_info->extract,&image->extract_info);
4065 option=GetImageOption(image_info,"filter");
4066 if (option != (const char *) NULL)
4067 image->filter=(FilterTypes) ParseMagickOption(MagickFilterOptions,
4068 MagickFalse,option);
4069 option=GetImageOption(image_info,"fuzz");
4070 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004071 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004072 option=GetImageOption(image_info,"gravity");
4073 if (option != (const char *) NULL)
4074 image->gravity=(GravityType) ParseMagickOption(MagickGravityOptions,
4075 MagickFalse,option);
4076 option=GetImageOption(image_info,"green-primary");
4077 if (option != (const char *) NULL)
4078 {
4079 flags=ParseGeometry(option,&geometry_info);
4080 image->chromaticity.green_primary.x=geometry_info.rho;
4081 image->chromaticity.green_primary.y=geometry_info.sigma;
4082 if ((flags & SigmaValue) == 0)
4083 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4084 }
4085 option=GetImageOption(image_info,"intent");
4086 if (option != (const char *) NULL)
4087 image->rendering_intent=(RenderingIntent) ParseMagickOption(
4088 MagickIntentOptions,MagickFalse,option);
4089 option=GetImageOption(image_info,"interlace");
4090 if (option != (const char *) NULL)
4091 image->interlace=(InterlaceType) ParseMagickOption(MagickInterlaceOptions,
4092 MagickFalse,option);
4093 option=GetImageOption(image_info,"interpolate");
4094 if (option != (const char *) NULL)
4095 image->interpolate=(InterpolatePixelMethod) ParseMagickOption(
4096 MagickInterpolateOptions,MagickFalse,option);
4097 option=GetImageOption(image_info,"loop");
4098 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004099 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004100 option=GetImageOption(image_info,"mattecolor");
4101 if (option != (const char *) NULL)
4102 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4103 option=GetImageOption(image_info,"orient");
4104 if (option != (const char *) NULL)
4105 image->orientation=(OrientationType) ParseMagickOption(
4106 MagickOrientationOptions,MagickFalse,option);
4107 option=GetImageOption(image_info,"quality");
4108 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004109 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004110 option=GetImageOption(image_info,"page");
4111 if (option != (const char *) NULL)
4112 {
4113 char
4114 *geometry;
4115
4116 geometry=GetPageGeometry(option);
4117 flags=ParseAbsoluteGeometry(geometry,&image->page);
4118 geometry=DestroyString(geometry);
4119 }
4120 option=GetImageOption(image_info,"red-primary");
4121 if (option != (const char *) NULL)
4122 {
4123 flags=ParseGeometry(option,&geometry_info);
4124 image->chromaticity.red_primary.x=geometry_info.rho;
4125 image->chromaticity.red_primary.y=geometry_info.sigma;
4126 if ((flags & SigmaValue) == 0)
4127 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4128 }
4129 if (image_info->quality != UndefinedCompressionQuality)
4130 image->quality=image_info->quality;
4131 option=GetImageOption(image_info,"scene");
4132 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004133 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004134 option=GetImageOption(image_info,"taint");
4135 if (option != (const char *) NULL)
4136 image->taint=(MagickBooleanType) ParseMagickOption(MagickBooleanOptions,
4137 MagickFalse,option);
4138 option=GetImageOption(image_info,"tile-offset");
4139 if (option != (const char *) NULL)
4140 {
4141 char
4142 *geometry;
4143
4144 geometry=GetPageGeometry(option);
4145 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4146 geometry=DestroyString(geometry);
4147 }
4148 option=GetImageOption(image_info,"transparent-color");
4149 if (option != (const char *) NULL)
4150 (void) QueryColorDatabase(option,&image->transparent_color,
4151 &image->exception);
4152 option=GetImageOption(image_info,"type");
4153 if (option != (const char *) NULL)
4154 image->type=(ImageType) ParseMagickOption(MagickTypeOptions,MagickFalse,
4155 option);
4156 option=GetImageOption(image_info,"units");
4157 if (option != (const char *) NULL)
4158 image->units=(ResolutionType) ParseMagickOption(MagickResolutionOptions,
4159 MagickFalse,option);
4160 if (image_info->units != UndefinedResolution)
4161 {
4162 if (image->units != image_info->units)
4163 switch (image->units)
4164 {
4165 case PixelsPerInchResolution:
4166 {
4167 if (image_info->units == PixelsPerCentimeterResolution)
4168 {
4169 image->x_resolution/=2.54;
4170 image->y_resolution/=2.54;
4171 }
4172 break;
4173 }
4174 case PixelsPerCentimeterResolution:
4175 {
4176 if (image_info->units == PixelsPerInchResolution)
4177 {
4178 image->x_resolution*=2.54;
4179 image->y_resolution*=2.54;
4180 }
4181 break;
4182 }
4183 default:
4184 break;
4185 }
4186 image->units=image_info->units;
4187 }
4188 option=GetImageOption(image_info,"white-point");
4189 if (option != (const char *) NULL)
4190 {
4191 flags=ParseGeometry(option,&geometry_info);
4192 image->chromaticity.white_point.x=geometry_info.rho;
4193 image->chromaticity.white_point.y=geometry_info.sigma;
4194 if ((flags & SigmaValue) == 0)
4195 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4196 }
4197 ResetImageOptionIterator(image_info);
4198 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4199 {
4200 value=GetImageOption(image_info,option);
4201 if (value != (const char *) NULL)
4202 {
4203 (void) FormatMagickString(property,MaxTextExtent,"%s",option);
4204 (void) SetImageArtifact(image,property,value);
4205 }
4206 option=GetNextImageOption(image_info);
4207 }
4208 return(MagickTrue);
4209}