blob: 9845f85bb4c5bdb62ed3ad122744156e4b9e82e9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% IIIII M M AAA GGGG EEEEE %
7% I MM MM A A G E %
8% I M M M AAAAA G GG EEE %
9% I M M A A G G E %
10% IIIII M M A A GGGG EEEEE %
11% %
12% %
13% MagickCore Image Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/animate.h"
45#include "magick/artifact.h"
46#include "magick/blob.h"
47#include "magick/blob-private.h"
48#include "magick/cache.h"
49#include "magick/cache-private.h"
50#include "magick/cache-view.h"
51#include "magick/client.h"
52#include "magick/color.h"
53#include "magick/color-private.h"
cristy316d5172009-09-17 19:31:25 +000054#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000055#include "magick/colorspace.h"
56#include "magick/colorspace-private.h"
57#include "magick/composite.h"
58#include "magick/composite-private.h"
59#include "magick/compress.h"
60#include "magick/constitute.h"
61#include "magick/deprecate.h"
62#include "magick/display.h"
63#include "magick/draw.h"
64#include "magick/enhance.h"
65#include "magick/exception.h"
66#include "magick/exception-private.h"
67#include "magick/gem.h"
68#include "magick/geometry.h"
cristyf2e11662009-10-14 01:24:43 +000069#include "magick/histogram.h"
cristy3ed852e2009-09-05 21:47:34 +000070#include "magick/image-private.h"
cristyf2e11662009-10-14 01:24:43 +000071#include "magick/list.h"
cristy3ed852e2009-09-05 21:47:34 +000072#include "magick/magic.h"
73#include "magick/magick.h"
74#include "magick/memory_.h"
75#include "magick/module.h"
76#include "magick/monitor.h"
77#include "magick/monitor-private.h"
78#include "magick/option.h"
79#include "magick/paint.h"
80#include "magick/pixel-private.h"
81#include "magick/profile.h"
82#include "magick/property.h"
83#include "magick/quantize.h"
84#include "magick/random_.h"
85#include "magick/segment.h"
86#include "magick/semaphore.h"
87#include "magick/signature-private.h"
88#include "magick/statistic.h"
89#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000090#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000091#include "magick/thread-private.h"
92#include "magick/threshold.h"
93#include "magick/timer.h"
94#include "magick/utility.h"
95#include "magick/version.h"
96#include "magick/xwindow-private.h"
97
98/*
99 Constant declaration.
100*/
101const char
cristy7138c592009-09-08 13:58:52 +0000102 BackgroundColor[] = "#ffffff", /* white */
103 BorderColor[] = "#dfdfdf", /* gray */
104 DefaultTileFrame[] = "15x15+3+3",
105 DefaultTileGeometry[] = "120x120+4+3>",
106 DefaultTileLabel[] = "%f\n%G\n%b",
107 ForegroundColor[] = "#000", /* black */
108 LoadImageTag[] = "Load/Image",
109 LoadImagesTag[] = "Load/Images",
110 MatteColor[] = "#bdbdbd", /* gray */
111 PSDensityGeometry[] = "72.0x72.0",
112 PSPageGeometry[] = "612x792",
113 SaveImageTag[] = "Save/Image",
114 SaveImagesTag[] = "Save/Images",
115 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000116
117const double
118 DefaultResolution = 72.0;
119
120/*
121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122% %
123% %
124% %
125% A c q u i r e I m a g e %
126% %
127% %
128% %
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%
131% AcquireImage() returns a pointer to an image structure initialized to
132% default values.
133%
134% The format of the AcquireImage method is:
135%
136% Image *AcquireImage(const ImageInfo *image_info)
137%
138% A description of each parameter follows:
139%
140% o image_info: Many of the image default values are set from this
141% structure. For example, filename, compression, depth, background color,
142% and others.
143%
144*/
145MagickExport Image *AcquireImage(const ImageInfo *image_info)
146{
cristye412c892010-07-26 12:31:36 +0000147 const char
cristyf3a660a2010-07-26 14:17:52 +0000148 *option;
cristye412c892010-07-26 12:31:36 +0000149
cristy3ed852e2009-09-05 21:47:34 +0000150 Image
151 *image;
152
153 MagickStatusType
154 flags;
155
156 /*
157 Allocate image structure.
158 */
159 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy73bd4a52010-10-05 11:24:23 +0000160 image=(Image *) AcquireMagickMemory(sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000161 if (image == (Image *) NULL)
162 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
163 (void) ResetMagickMemory(image,0,sizeof(*image));
164 /*
165 Initialize Image structure.
166 */
167 (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
168 image->storage_class=DirectClass;
169 image->depth=MAGICKCORE_QUANTUM_DEPTH;
170 image->colorspace=RGBColorspace;
171 image->interlace=NoInterlace;
172 image->ticks_per_second=UndefinedTicksPerSecond;
173 image->compose=OverCompositeOp;
174 image->blur=1.0;
175 GetExceptionInfo(&image->exception);
176 (void) QueryColorDatabase(BackgroundColor,&image->background_color,
177 &image->exception);
178 (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
179 (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
180 (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
181 &image->exception);
182 image->x_resolution=DefaultResolution;
183 image->y_resolution=DefaultResolution;
184 image->units=PixelsPerInchResolution;
185 GetTimerInfo(&image->timer);
cristy73724512010-04-12 14:43:14 +0000186 image->ping=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000187 image->cache=AcquirePixelCache(0);
188 image->blob=CloneBlobInfo((BlobInfo *) NULL);
189 image->debug=IsEventLogging();
190 image->reference_count=1;
191 image->semaphore=AllocateSemaphoreInfo();
192 image->signature=MagickSignature;
193 if (image_info == (ImageInfo *) NULL)
194 return(image);
195 /*
196 Transfer image info.
197 */
198 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
199 MagickFalse);
200 (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
201 (void) CopyMagickString(image->magick_filename,image_info->filename,
202 MaxTextExtent);
203 (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
204 if (image_info->size != (char *) NULL)
205 {
206 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
207 image->columns=image->extract_info.width;
208 image->rows=image->extract_info.height;
209 image->offset=image->extract_info.x;
210 image->extract_info.x=0;
211 image->extract_info.y=0;
212 }
213 if (image_info->extract != (char *) NULL)
214 {
215 RectangleInfo
216 geometry;
217
218 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
219 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
220 {
221 image->extract_info=geometry;
222 Swap(image->columns,image->extract_info.width);
223 Swap(image->rows,image->extract_info.height);
224 }
225 }
226 image->compression=image_info->compression;
227 image->quality=image_info->quality;
228 image->endian=image_info->endian;
229 image->interlace=image_info->interlace;
230 image->units=image_info->units;
231 if (image_info->density != (char *) NULL)
232 {
233 GeometryInfo
234 geometry_info;
235
236 flags=ParseGeometry(image_info->density,&geometry_info);
237 image->x_resolution=geometry_info.rho;
238 image->y_resolution=geometry_info.sigma;
239 if ((flags & SigmaValue) == 0)
240 image->y_resolution=image->x_resolution;
241 }
242 if (image_info->page != (char *) NULL)
243 {
244 char
245 *geometry;
246
247 image->page=image->extract_info;
248 geometry=GetPageGeometry(image_info->page);
249 (void) ParseAbsoluteGeometry(geometry,&image->page);
250 geometry=DestroyString(geometry);
251 }
252 if (image_info->depth != 0)
253 image->depth=image_info->depth;
254 image->dither=image_info->dither;
255 image->background_color=image_info->background_color;
256 image->border_color=image_info->border_color;
257 image->matte_color=image_info->matte_color;
258 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000259 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000260 image->progress_monitor=image_info->progress_monitor;
261 image->client_data=image_info->client_data;
262 if (image_info->cache != (void *) NULL)
263 ClonePixelCacheMethods(image->cache,image_info->cache);
264 (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
cristy6b9aca12010-02-21 01:50:11 +0000265 (void) SyncImageSettings(image_info,image);
cristye412c892010-07-26 12:31:36 +0000266 option=GetImageOption(image_info,"delay");
267 if (option != (const char *) NULL)
268 {
269 GeometryInfo
270 geometry_info;
271
272 flags=ParseGeometry(option,&geometry_info);
273 if ((flags & GreaterValue) != 0)
274 {
275 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
276 image->delay=(size_t) floor(geometry_info.rho+0.5);
277 }
278 else
279 if ((flags & LessValue) != 0)
280 {
281 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
282 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
283 }
284 else
285 image->delay=(size_t) floor(geometry_info.rho+0.5);
286 if ((flags & SigmaValue) != 0)
287 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
288 }
289 option=GetImageOption(image_info,"dispose");
290 if (option != (const char *) NULL)
291 image->dispose=(DisposeType) ParseMagickOption(MagickDisposeOptions,
292 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000293 return(image);
294}
295
296/*
297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298% %
299% %
300% %
cristy3ed852e2009-09-05 21:47:34 +0000301% A c q u i r e I m a g e I n f o %
302% %
303% %
304% %
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306%
307% AcquireImageInfo() allocates the ImageInfo structure.
308%
309% The format of the AcquireImageInfo method is:
310%
311% ImageInfo *AcquireImageInfo(void)
312%
313*/
314MagickExport ImageInfo *AcquireImageInfo(void)
315{
316 ImageInfo
317 *image_info;
318
cristy73bd4a52010-10-05 11:24:23 +0000319 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000320 if (image_info == (ImageInfo *) NULL)
321 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
322 GetImageInfo(image_info);
323 return(image_info);
324}
325
326/*
327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328% %
329% %
330% %
331% A c q u i r e N e x t I m a g e %
332% %
333% %
334% %
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336%
337% AcquireNextImage() initializes the next image in a sequence to
338% default values. The next member of image points to the newly allocated
339% image. If there is a memory shortage, next is assigned NULL.
340%
341% The format of the AcquireNextImage method is:
342%
343% void AcquireNextImage(const ImageInfo *image_info,Image *image)
344%
345% A description of each parameter follows:
346%
347% o image_info: Many of the image default values are set from this
348% structure. For example, filename, compression, depth, background color,
349% and others.
350%
351% o image: the image.
352%
353*/
354MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
355{
356 /*
357 Allocate image structure.
358 */
359 assert(image != (Image *) NULL);
360 assert(image->signature == MagickSignature);
361 if (image->debug != MagickFalse)
362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
363 image->next=AcquireImage(image_info);
364 if (GetNextImageInList(image) == (Image *) NULL)
365 return;
366 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
367 MaxTextExtent);
368 if (image_info != (ImageInfo *) NULL)
369 (void) CopyMagickString(GetNextImageInList(image)->filename,
370 image_info->filename,MaxTextExtent);
371 DestroyBlob(GetNextImageInList(image));
372 image->next->blob=ReferenceBlob(image->blob);
373 image->next->endian=image->endian;
374 image->next->scene=image->scene+1;
375 image->next->previous=image;
376}
377
378/*
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380% %
381% %
382% %
383% A p p e n d I m a g e s %
384% %
385% %
386% %
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388%
389% AppendImages() takes all images from the current image pointer to the end
390% of the image list and appends them to each other top-to-bottom if the
391% stack parameter is true, otherwise left-to-right.
392%
393% The current gravity setting now effects how the image is justified in the
394% final image.
395%
396% The format of the AppendImages method is:
397%
cristy4ca38e22011-02-10 02:57:49 +0000398% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000399% ExceptionInfo *exception)
400%
401% A description of each parameter follows:
402%
cristy4ca38e22011-02-10 02:57:49 +0000403% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000404%
405% o stack: A value other than 0 stacks the images top-to-bottom.
406%
407% o exception: return any errors or warnings in this structure.
408%
409*/
cristy4ca38e22011-02-10 02:57:49 +0000410MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000411 const MagickBooleanType stack,ExceptionInfo *exception)
412{
413#define AppendImageTag "Append/Image"
414
415 CacheView
416 *append_view,
417 *image_view;
418
cristy4ca38e22011-02-10 02:57:49 +0000419 const Image
420 *image;
421
cristy3ed852e2009-09-05 21:47:34 +0000422 Image
423 *append_image;
424
cristy3ed852e2009-09-05 21:47:34 +0000425 MagickBooleanType
426 matte,
427 proceed,
428 status;
429
cristybb503372010-05-27 20:51:26 +0000430 MagickOffsetType
431 n;
432
cristy3ed852e2009-09-05 21:47:34 +0000433 RectangleInfo
434 geometry;
435
436 register const Image
437 *next;
438
cristybb503372010-05-27 20:51:26 +0000439 size_t
cristy3ed852e2009-09-05 21:47:34 +0000440 height,
441 number_images,
442 width;
443
cristybb503372010-05-27 20:51:26 +0000444 ssize_t
445 x_offset,
446 y,
447 y_offset;
448
cristy3ed852e2009-09-05 21:47:34 +0000449 /*
cristy7c6dc152011-02-11 14:10:55 +0000450 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000451 */
cristy4ca38e22011-02-10 02:57:49 +0000452 assert(images != (Image *) NULL);
453 assert(images->signature == MagickSignature);
454 if (images->debug != MagickFalse)
455 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000456 assert(exception != (ExceptionInfo *) NULL);
457 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +0000458 image=images;
cristy3ed852e2009-09-05 21:47:34 +0000459 matte=image->matte;
460 number_images=1;
461 width=image->columns;
462 height=image->rows;
463 next=GetNextImageInList(image);
464 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
465 {
466 if (next->matte != MagickFalse)
467 matte=MagickTrue;
468 number_images++;
469 if (stack != MagickFalse)
470 {
471 if (next->columns > width)
472 width=next->columns;
473 height+=next->rows;
474 continue;
475 }
476 width+=next->columns;
477 if (next->rows > height)
478 height=next->rows;
479 }
480 /*
cristy7c6dc152011-02-11 14:10:55 +0000481 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000482 */
483 append_image=CloneImage(image,width,height,MagickTrue,exception);
484 if (append_image == (Image *) NULL)
485 return((Image *) NULL);
486 if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
487 {
488 InheritException(exception,&append_image->exception);
489 append_image=DestroyImage(append_image);
490 return((Image *) NULL);
491 }
492 append_image->matte=matte;
493 (void) SetImageBackgroundColor(append_image);
494 status=MagickTrue;
495 x_offset=0;
496 y_offset=0;
497 append_view=AcquireCacheView(append_image);
cristybb503372010-05-27 20:51:26 +0000498 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000499 {
500 SetGeometry(append_image,&geometry);
501 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
502 if (stack != MagickFalse)
503 x_offset-=geometry.x;
504 else
505 y_offset-=geometry.y;
506 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +0000507#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy1a2bd532010-11-19 02:53:15 +0000508 #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
cristy3ed852e2009-09-05 21:47:34 +0000509#endif
cristybb503372010-05-27 20:51:26 +0000510 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000511 {
512 MagickBooleanType
513 sync;
514
515 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000516 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000517
518 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000519 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000520
521 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000522 *restrict append_indexes;
cristy3ed852e2009-09-05 21:47:34 +0000523
cristy3ed852e2009-09-05 21:47:34 +0000524 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000525 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000526
cristycb6d09b2010-06-19 01:59:36 +0000527 register ssize_t
528 x;
529
cristy3ed852e2009-09-05 21:47:34 +0000530 if (status == MagickFalse)
531 continue;
532 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
533 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
534 image->columns,1,exception);
535 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
536 {
537 status=MagickFalse;
538 continue;
539 }
540 indexes=GetCacheViewVirtualIndexQueue(image_view);
541 append_indexes=GetCacheViewAuthenticIndexQueue(append_view);
cristybb503372010-05-27 20:51:26 +0000542 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000543 {
cristyce70c172010-01-07 17:15:30 +0000544 SetRedPixelComponent(q,GetRedPixelComponent(p));
545 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
546 SetBluePixelComponent(q,GetBluePixelComponent(p));
547 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +0000548 if (image->matte != MagickFalse)
cristyce70c172010-01-07 17:15:30 +0000549 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristyff775322011-02-24 15:05:25 +0000550 if ((image->colorspace == CMYKColorspace) &&
551 (append_image->colorspace == CMYKColorspace))
cristy3ed852e2009-09-05 21:47:34 +0000552 append_indexes[x]=indexes[x];
553 p++;
554 q++;
555 }
556 sync=SyncCacheViewAuthenticPixels(append_view,exception);
557 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000558 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000559 }
560 image_view=DestroyCacheView(image_view);
561 proceed=SetImageProgress(image,AppendImageTag,n,number_images);
562 if (proceed == MagickFalse)
563 break;
564 if (stack == MagickFalse)
565 {
cristyeaedf062010-05-29 22:36:02 +0000566 x_offset+=(ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000567 y_offset=0;
568 }
569 else
570 {
571 x_offset=0;
cristyeaedf062010-05-29 22:36:02 +0000572 y_offset+=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000573 }
574 image=GetNextImageInList(image);
575 }
576 append_view=DestroyCacheView(append_view);
577 if (status == MagickFalse)
578 append_image=DestroyImage(append_image);
579 return(append_image);
580}
581
582/*
583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584% %
585% %
586% %
cristy3ed852e2009-09-05 21:47:34 +0000587% C a t c h I m a g e E x c e p t i o n %
588% %
589% %
590% %
591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592%
593% CatchImageException() returns if no exceptions are found in the image
594% sequence, otherwise it determines the most severe exception and reports
595% it as a warning or error depending on the severity.
596%
597% The format of the CatchImageException method is:
598%
599% ExceptionType CatchImageException(Image *image)
600%
601% A description of each parameter follows:
602%
603% o image: An image sequence.
604%
605*/
606MagickExport ExceptionType CatchImageException(Image *image)
607{
608 ExceptionInfo
609 *exception;
610
611 ExceptionType
612 severity;
613
614 assert(image != (const Image *) NULL);
615 assert(image->signature == MagickSignature);
616 if (image->debug != MagickFalse)
617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
618 exception=AcquireExceptionInfo();
619 GetImageException(image,exception);
620 CatchException(exception);
621 severity=exception->severity;
622 exception=DestroyExceptionInfo(exception);
623 return(severity);
624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
631% C l i p I m a g e P a t h %
632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636%
637% ClipImagePath() sets the image clip mask based any clipping path information
638% if it exists.
639%
640% The format of the ClipImagePath method is:
641%
642% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
643% const MagickBooleanType inside)
644%
645% A description of each parameter follows:
646%
647% o image: the image.
648%
649% o pathname: name of clipping path resource. If name is preceded by #, use
650% clipping path numbered by name.
651%
652% o inside: if non-zero, later operations take effect inside clipping path.
653% Otherwise later operations take effect outside clipping path.
654%
655*/
656
657MagickExport MagickBooleanType ClipImage(Image *image)
658{
659 return(ClipImagePath(image,"#1",MagickTrue));
660}
661
662MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
663 const MagickBooleanType inside)
664{
665#define ClipImagePathTag "ClipPath/Image"
666
667 char
668 *property;
669
670 const char
671 *value;
672
673 Image
674 *clip_mask;
675
676 ImageInfo
677 *image_info;
678
679 assert(image != (const Image *) NULL);
680 assert(image->signature == MagickSignature);
681 if (image->debug != MagickFalse)
682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
683 assert(pathname != NULL);
684 property=AcquireString(pathname);
685 (void) FormatMagickString(property,MaxTextExtent,"8BIM:1999,2998:%s",
686 pathname);
687 value=GetImageProperty(image,property);
688 property=DestroyString(property);
689 if (value == (const char *) NULL)
690 {
691 ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
692 image->filename);
693 return(MagickFalse);
694 }
695 image_info=AcquireImageInfo();
696 (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
697 (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
698 clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
699 image_info=DestroyImageInfo(image_info);
700 if (clip_mask == (Image *) NULL)
701 return(MagickFalse);
702 if (clip_mask->storage_class == PseudoClass)
703 {
704 (void) SyncImage(clip_mask);
705 if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
706 return(MagickFalse);
707 }
708 if (inside == MagickFalse)
709 (void) NegateImage(clip_mask,MagickFalse);
710 (void) FormatMagickString(clip_mask->magick_filename,MaxTextExtent,
711 "8BIM:1999,2998:%s\nPS",pathname);
712 (void) SetImageClipMask(image,clip_mask);
713 clip_mask=DestroyImage(clip_mask);
714 return(MagickTrue);
715}
716
717/*
718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719% %
720% %
721% %
722% C l o n e I m a g e %
723% %
724% %
725% %
726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727%
728% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000729%
cristy3ed852e2009-09-05 21:47:34 +0000730% If the specified columns and rows is 0, an exact copy of the image is
731% returned, otherwise the pixel data is undefined and must be initialized
732% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
733% failure, a NULL image is returned and exception describes the reason for the
734% failure.
735%
736% The format of the CloneImage method is:
737%
cristybb503372010-05-27 20:51:26 +0000738% Image *CloneImage(const Image *image,const size_t columns,
739% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000740% ExceptionInfo *exception)
741%
742% A description of each parameter follows:
743%
744% o image: the image.
745%
746% o columns: the number of columns in the cloned image.
747%
748% o rows: the number of rows in the cloned image.
749%
750% o detach: With a value other than 0, the cloned image is detached from
751% its parent I/O stream.
752%
753% o exception: return any errors or warnings in this structure.
754%
755*/
cristybb503372010-05-27 20:51:26 +0000756MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000757 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000758{
759 Image
760 *clone_image;
761
762 MagickRealType
763 scale;
764
765 size_t
766 length;
767
768 /*
769 Clone the image.
770 */
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(exception != (ExceptionInfo *) NULL);
776 assert(exception->signature == MagickSignature);
cristy73bd4a52010-10-05 11:24:23 +0000777 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000778 if (clone_image == (Image *) NULL)
779 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
780 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
781 clone_image->signature=MagickSignature;
782 clone_image->storage_class=image->storage_class;
783 clone_image->colorspace=image->colorspace;
784 clone_image->matte=image->matte;
785 clone_image->columns=image->columns;
786 clone_image->rows=image->rows;
787 clone_image->dither=image->dither;
788 if (image->colormap != (PixelPacket *) NULL)
789 {
790 /*
791 Allocate and copy the image colormap.
792 */
793 clone_image->colors=image->colors;
794 length=(size_t) image->colors;
795 clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
796 sizeof(*clone_image->colormap));
797 if (clone_image->colormap == (PixelPacket *) NULL)
798 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
799 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
800 sizeof(*clone_image->colormap));
801 }
802 (void) CloneImageProfiles(clone_image,image);
803 (void) CloneImageProperties(clone_image,image);
804 (void) CloneImageArtifacts(clone_image,image);
805 GetTimerInfo(&clone_image->timer);
806 GetExceptionInfo(&clone_image->exception);
807 InheritException(&clone_image->exception,&image->exception);
808 if (image->ascii85 != (void *) NULL)
809 Ascii85Initialize(clone_image);
810 clone_image->magick_columns=image->magick_columns;
811 clone_image->magick_rows=image->magick_rows;
812 clone_image->type=image->type;
813 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
814 MaxTextExtent);
815 (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
816 (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
817 clone_image->progress_monitor=image->progress_monitor;
818 clone_image->client_data=image->client_data;
819 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000820 clone_image->next=image->next;
821 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000822 clone_image->list=NewImageList();
823 clone_image->clip_mask=NewImageList();
824 clone_image->mask=NewImageList();
825 if (detach == MagickFalse)
826 clone_image->blob=ReferenceBlob(image->blob);
827 else
cristybee00932011-01-15 20:28:27 +0000828 {
829 clone_image->next=NewImageList();
830 clone_image->previous=NewImageList();
831 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
832 }
cristy73724512010-04-12 14:43:14 +0000833 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000834 clone_image->debug=IsEventLogging();
835 clone_image->semaphore=AllocateSemaphoreInfo();
836 if ((columns == 0) && (rows == 0))
837 {
838 if (image->montage != (char *) NULL)
839 (void) CloneString(&clone_image->montage,image->montage);
840 if (image->directory != (char *) NULL)
841 (void) CloneString(&clone_image->directory,image->directory);
842 if (image->clip_mask != (Image *) NULL)
843 clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
844 exception);
845 if (image->mask != (Image *) NULL)
846 clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
847 clone_image->cache=ReferencePixelCache(image->cache);
848 return(clone_image);
849 }
850 scale=(MagickRealType) columns/(MagickRealType) image->columns;
cristybb503372010-05-27 20:51:26 +0000851 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
852 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
853 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000854 scale=(MagickRealType) rows/(MagickRealType) image->rows;
cristybb503372010-05-27 20:51:26 +0000855 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
856 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
857 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000858 clone_image->columns=columns;
859 clone_image->rows=rows;
860 clone_image->cache=ClonePixelCache(image->cache);
861 return(clone_image);
862}
863
864/*
865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866% %
867% %
868% %
869% C l o n e I m a g e I n f o %
870% %
871% %
872% %
873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
874%
875% CloneImageInfo() makes a copy of the given image info structure. If
876% NULL is specified, a new image info structure is created initialized to
877% default values.
878%
879% The format of the CloneImageInfo method is:
880%
881% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
882%
883% A description of each parameter follows:
884%
885% o image_info: the image info.
886%
887*/
888MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
889{
890 ImageInfo
891 *clone_info;
892
893 clone_info=AcquireImageInfo();
894 if (image_info == (ImageInfo *) NULL)
895 return(clone_info);
896 clone_info->compression=image_info->compression;
897 clone_info->temporary=image_info->temporary;
898 clone_info->adjoin=image_info->adjoin;
899 clone_info->antialias=image_info->antialias;
900 clone_info->scene=image_info->scene;
901 clone_info->number_scenes=image_info->number_scenes;
902 clone_info->depth=image_info->depth;
903 if (image_info->size != (char *) NULL)
904 (void) CloneString(&clone_info->size,image_info->size);
905 if (image_info->extract != (char *) NULL)
906 (void) CloneString(&clone_info->extract,image_info->extract);
907 if (image_info->scenes != (char *) NULL)
908 (void) CloneString(&clone_info->scenes,image_info->scenes);
909 if (image_info->page != (char *) NULL)
910 (void) CloneString(&clone_info->page,image_info->page);
911 clone_info->interlace=image_info->interlace;
912 clone_info->endian=image_info->endian;
913 clone_info->units=image_info->units;
914 clone_info->quality=image_info->quality;
915 if (image_info->sampling_factor != (char *) NULL)
916 (void) CloneString(&clone_info->sampling_factor,
917 image_info->sampling_factor);
918 if (image_info->server_name != (char *) NULL)
919 (void) CloneString(&clone_info->server_name,image_info->server_name);
920 if (image_info->font != (char *) NULL)
921 (void) CloneString(&clone_info->font,image_info->font);
922 if (image_info->texture != (char *) NULL)
923 (void) CloneString(&clone_info->texture,image_info->texture);
924 if (image_info->density != (char *) NULL)
925 (void) CloneString(&clone_info->density,image_info->density);
926 clone_info->pointsize=image_info->pointsize;
927 clone_info->fuzz=image_info->fuzz;
928 clone_info->pen=image_info->pen;
929 clone_info->background_color=image_info->background_color;
930 clone_info->border_color=image_info->border_color;
931 clone_info->matte_color=image_info->matte_color;
932 clone_info->transparent_color=image_info->transparent_color;
933 clone_info->dither=image_info->dither;
934 clone_info->monochrome=image_info->monochrome;
935 clone_info->colors=image_info->colors;
936 clone_info->colorspace=image_info->colorspace;
937 clone_info->type=image_info->type;
938 clone_info->orientation=image_info->orientation;
939 clone_info->preview_type=image_info->preview_type;
940 clone_info->group=image_info->group;
941 clone_info->ping=image_info->ping;
942 clone_info->verbose=image_info->verbose;
943 if (image_info->view != (char *) NULL)
944 (void) CloneString(&clone_info->view,image_info->view);
945 if (image_info->authenticate != (char *) NULL)
946 (void) CloneString(&clone_info->authenticate,image_info->authenticate);
947 (void) CloneImageOptions(clone_info,image_info);
948 clone_info->progress_monitor=image_info->progress_monitor;
949 clone_info->client_data=image_info->client_data;
950 clone_info->cache=image_info->cache;
951 if (image_info->cache != (void *) NULL)
952 clone_info->cache=ReferencePixelCache(image_info->cache);
953 if (image_info->profile != (void *) NULL)
954 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
955 image_info->profile);
956 SetImageInfoFile(clone_info,image_info->file);
957 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
958 clone_info->stream=image_info->stream;
959 clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
960 (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
961 (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
962 (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
963 (void) CopyMagickString(clone_info->filename,image_info->filename,
964 MaxTextExtent);
965 clone_info->subimage=image_info->scene; /* deprecated */
966 clone_info->subrange=image_info->number_scenes; /* deprecated */
967 clone_info->channel=image_info->channel;
968 clone_info->debug=IsEventLogging();
969 clone_info->signature=image_info->signature;
970 return(clone_info);
971}
972
973/*
974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975% %
976% %
977% %
978% C o m b i n e I m a g e s %
979% %
980% %
981% %
982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983%
984% CombineImages() combines one or more images into a single image. The
985% grayscale value of the pixels of each image in the sequence is assigned in
986% order to the specified channels of the combined image. The typical
987% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
988%
989% The format of the CombineImages method is:
990%
991% Image *CombineImages(const Image *image,const ChannelType channel,
992% ExceptionInfo *exception)
993%
994% A description of each parameter follows:
995%
996% o image: the image.
997%
998% o exception: return any errors or warnings in this structure.
999%
1000*/
1001MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
1002 ExceptionInfo *exception)
1003{
1004#define CombineImageTag "Combine/Image"
1005
1006 CacheView
1007 *combine_view;
1008
1009 const Image
1010 *next;
1011
1012 Image
1013 *combine_image;
1014
cristy3ed852e2009-09-05 21:47:34 +00001015 MagickBooleanType
1016 status;
1017
cristybb503372010-05-27 20:51:26 +00001018 MagickOffsetType
1019 progress;
1020
1021 ssize_t
1022 y;
1023
cristy3ed852e2009-09-05 21:47:34 +00001024 /*
1025 Ensure the image are the same size.
1026 */
1027 assert(image != (const Image *) NULL);
1028 assert(image->signature == MagickSignature);
1029 if (image->debug != MagickFalse)
1030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1031 assert(exception != (ExceptionInfo *) NULL);
1032 assert(exception->signature == MagickSignature);
1033 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1034 {
1035 if ((next->columns != image->columns) || (next->rows != image->rows))
1036 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
1037 }
1038 combine_image=CloneImage(image,0,0,MagickTrue,exception);
1039 if (combine_image == (Image *) NULL)
1040 return((Image *) NULL);
1041 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
1042 {
1043 InheritException(exception,&combine_image->exception);
1044 combine_image=DestroyImage(combine_image);
1045 return((Image *) NULL);
1046 }
1047 if ((channel & OpacityChannel) != 0)
1048 combine_image->matte=MagickTrue;
1049 (void) SetImageBackgroundColor(combine_image);
1050 /*
1051 Combine images.
1052 */
1053 status=MagickTrue;
1054 progress=0;
1055 combine_view=AcquireCacheView(combine_image);
cristybb503372010-05-27 20:51:26 +00001056 for (y=0; y < (ssize_t) combine_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001057 {
1058 CacheView
1059 *image_view;
1060
1061 const Image
1062 *next;
1063
1064 PixelPacket
1065 *pixels;
1066
1067 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001068 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001069
cristy3ed852e2009-09-05 21:47:34 +00001070 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001071 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001072
cristycb6d09b2010-06-19 01:59:36 +00001073 register ssize_t
1074 x;
1075
cristy3ed852e2009-09-05 21:47:34 +00001076 if (status == MagickFalse)
1077 continue;
1078 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
1079 1,exception);
1080 if (pixels == (PixelPacket *) NULL)
1081 {
1082 status=MagickFalse;
1083 continue;
1084 }
1085 next=image;
1086 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
1087 {
1088 image_view=AcquireCacheView(next);
1089 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1090 if (p == (const PixelPacket *) NULL)
1091 continue;
1092 q=pixels;
cristybb503372010-05-27 20:51:26 +00001093 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001094 {
cristyce70c172010-01-07 17:15:30 +00001095 SetRedPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001096 p++;
1097 q++;
1098 }
1099 image_view=DestroyCacheView(image_view);
1100 next=GetNextImageInList(next);
1101 }
1102 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
1103 {
1104 image_view=AcquireCacheView(next);
1105 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1106 if (p == (const PixelPacket *) NULL)
1107 continue;
1108 q=pixels;
cristybb503372010-05-27 20:51:26 +00001109 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001110 {
cristyce70c172010-01-07 17:15:30 +00001111 SetGreenPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001112 p++;
1113 q++;
1114 }
1115 image_view=DestroyCacheView(image_view);
1116 next=GetNextImageInList(next);
1117 }
1118 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
1119 {
1120 image_view=AcquireCacheView(next);
1121 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1122 if (p == (const PixelPacket *) NULL)
1123 continue;
1124 q=pixels;
cristybb503372010-05-27 20:51:26 +00001125 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
cristyce70c172010-01-07 17:15:30 +00001127 SetBluePixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001128 p++;
1129 q++;
1130 }
1131 image_view=DestroyCacheView(image_view);
1132 next=GetNextImageInList(next);
1133 }
1134 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
1135 {
1136 image_view=AcquireCacheView(next);
1137 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1138 if (p == (const PixelPacket *) NULL)
1139 continue;
1140 q=pixels;
cristybb503372010-05-27 20:51:26 +00001141 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001142 {
cristyce70c172010-01-07 17:15:30 +00001143 SetOpacityPixelComponent(q,PixelIntensityToQuantum(p));
cristy3ed852e2009-09-05 21:47:34 +00001144 p++;
1145 q++;
1146 }
1147 image_view=DestroyCacheView(image_view);
1148 next=GetNextImageInList(next);
1149 }
1150 if (((channel & IndexChannel) != 0) &&
1151 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
1152 {
1153 IndexPacket
1154 *indexes;
1155
1156 image_view=AcquireCacheView(next);
1157 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1158 if (p == (const PixelPacket *) NULL)
1159 continue;
1160 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
cristybb503372010-05-27 20:51:26 +00001161 for (x=0; x < (ssize_t) combine_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001162 {
1163 indexes[x]=PixelIntensityToQuantum(p);
1164 p++;
1165 }
1166 image_view=DestroyCacheView(image_view);
1167 next=GetNextImageInList(next);
1168 }
1169 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
1170 status=MagickFalse;
1171 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1172 {
1173 MagickBooleanType
1174 proceed;
1175
cristy3ed852e2009-09-05 21:47:34 +00001176 proceed=SetImageProgress(image,CombineImageTag,progress++,
1177 combine_image->rows);
1178 if (proceed == MagickFalse)
1179 status=MagickFalse;
1180 }
1181 }
1182 combine_view=DestroyCacheView(combine_view);
1183 if (status == MagickFalse)
1184 combine_image=DestroyImage(combine_image);
1185 return(combine_image);
1186}
1187
1188/*
1189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190% %
1191% %
1192% %
cristy3ed852e2009-09-05 21:47:34 +00001193% D e s t r o y I m a g e %
1194% %
1195% %
1196% %
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198%
1199% DestroyImage() dereferences an image, deallocating memory associated with
1200% the image if the reference count becomes zero.
1201%
1202% The format of the DestroyImage method is:
1203%
1204% Image *DestroyImage(Image *image)
1205%
1206% A description of each parameter follows:
1207%
1208% o image: the image.
1209%
1210*/
1211MagickExport Image *DestroyImage(Image *image)
1212{
1213 MagickBooleanType
1214 destroy;
1215
1216 /*
1217 Dereference image.
1218 */
1219 assert(image != (Image *) NULL);
1220 assert(image->signature == MagickSignature);
1221 if (image->debug != MagickFalse)
1222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1223 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001224 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001225 image->reference_count--;
1226 if (image->reference_count == 0)
1227 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001228 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001229 if (destroy == MagickFalse)
1230 return((Image *) NULL);
1231 /*
1232 Destroy image.
1233 */
1234 DestroyImagePixels(image);
1235 if (image->clip_mask != (Image *) NULL)
1236 image->clip_mask=DestroyImage(image->clip_mask);
1237 if (image->mask != (Image *) NULL)
1238 image->mask=DestroyImage(image->mask);
1239 if (image->montage != (char *) NULL)
1240 image->montage=DestroyString(image->montage);
1241 if (image->directory != (char *) NULL)
1242 image->directory=DestroyString(image->directory);
1243 if (image->colormap != (PixelPacket *) NULL)
1244 image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
1245 if (image->geometry != (char *) NULL)
1246 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001247 DestroyImageProfiles(image);
1248 DestroyImageProperties(image);
1249 DestroyImageArtifacts(image);
1250 if (image->ascii85 != (Ascii85Info*) NULL)
1251 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1252 DestroyBlob(image);
1253 (void) DestroyExceptionInfo(&image->exception);
1254 if (image->semaphore != (SemaphoreInfo *) NULL)
1255 DestroySemaphoreInfo(&image->semaphore);
1256 image->signature=(~MagickSignature);
1257 image=(Image *) RelinquishMagickMemory(image);
1258 return(image);
1259}
1260
1261/*
1262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263% %
1264% %
1265% %
1266% D e s t r o y I m a g e I n f o %
1267% %
1268% %
1269% %
1270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271%
1272% DestroyImageInfo() deallocates memory associated with an ImageInfo
1273% structure.
1274%
1275% The format of the DestroyImageInfo method is:
1276%
1277% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1278%
1279% A description of each parameter follows:
1280%
1281% o image_info: the image info.
1282%
1283*/
1284MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1285{
1286 assert(image_info != (ImageInfo *) NULL);
1287 assert(image_info->signature == MagickSignature);
1288 if (image_info->debug != MagickFalse)
1289 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1290 image_info->filename);
1291 if (image_info->size != (char *) NULL)
1292 image_info->size=DestroyString(image_info->size);
1293 if (image_info->extract != (char *) NULL)
1294 image_info->extract=DestroyString(image_info->extract);
1295 if (image_info->scenes != (char *) NULL)
1296 image_info->scenes=DestroyString(image_info->scenes);
1297 if (image_info->page != (char *) NULL)
1298 image_info->page=DestroyString(image_info->page);
1299 if (image_info->sampling_factor != (char *) NULL)
1300 image_info->sampling_factor=DestroyString(
1301 image_info->sampling_factor);
1302 if (image_info->server_name != (char *) NULL)
1303 image_info->server_name=DestroyString(
1304 image_info->server_name);
1305 if (image_info->font != (char *) NULL)
1306 image_info->font=DestroyString(image_info->font);
1307 if (image_info->texture != (char *) NULL)
1308 image_info->texture=DestroyString(image_info->texture);
1309 if (image_info->density != (char *) NULL)
1310 image_info->density=DestroyString(image_info->density);
1311 if (image_info->view != (char *) NULL)
1312 image_info->view=DestroyString(image_info->view);
1313 if (image_info->authenticate != (char *) NULL)
1314 image_info->authenticate=DestroyString(
1315 image_info->authenticate);
1316 DestroyImageOptions(image_info);
1317 if (image_info->cache != (void *) NULL)
1318 image_info->cache=DestroyPixelCache(image_info->cache);
1319 if (image_info->profile != (StringInfo *) NULL)
1320 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1321 image_info->profile);
1322 image_info->signature=(~MagickSignature);
1323 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1324 return(image_info);
1325}
1326
1327/*
1328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329% %
1330% %
1331% %
1332+ D i s a s s o c i a t e I m a g e S t r e a m %
1333% %
1334% %
1335% %
1336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337%
1338% DisassociateImageStream() disassociates the image stream.
1339%
1340% The format of the DisassociateImageStream method is:
1341%
1342% MagickBooleanType DisassociateImageStream(const Image *image)
1343%
1344% A description of each parameter follows:
1345%
1346% o image: the image.
1347%
1348*/
1349MagickExport void DisassociateImageStream(Image *image)
1350{
1351 assert(image != (const Image *) NULL);
1352 assert(image->signature == MagickSignature);
1353 if (image->debug != MagickFalse)
1354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1355 (void) DetachBlob(image->blob);
1356}
1357
1358/*
1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360% %
1361% %
1362% %
1363% G e t I m a g e A l p h a C h a n n e l %
1364% %
1365% %
1366% %
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368%
1369% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
1370% not activated. That is, the image is RGB rather than RGBA or CMYK rather
1371% than CMYKA.
1372%
1373% The format of the GetImageAlphaChannel method is:
1374%
1375% MagickBooleanType GetImageAlphaChannel(const Image *image)
1376%
1377% A description of each parameter follows:
1378%
1379% o image: the image.
1380%
1381*/
1382MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
1383{
1384 assert(image != (const Image *) NULL);
1385 if (image->debug != MagickFalse)
1386 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1387 assert(image->signature == MagickSignature);
1388 return(image->matte);
1389}
1390
1391/*
1392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393% %
1394% %
1395% %
1396% G e t I m a g e C l i p M a s k %
1397% %
1398% %
1399% %
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401%
1402% GetImageClipMask() returns the clip path associated with the image.
1403%
1404% The format of the GetImageClipMask method is:
1405%
1406% Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
1407%
1408% A description of each parameter follows:
1409%
1410% o image: the image.
1411%
1412*/
1413MagickExport Image *GetImageClipMask(const Image *image,
1414 ExceptionInfo *exception)
1415{
1416 assert(image != (const Image *) NULL);
1417 if (image->debug != MagickFalse)
1418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1419 assert(image->signature == MagickSignature);
1420 if (image->clip_mask == (Image *) NULL)
1421 return((Image *) NULL);
1422 return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
1423}
1424
1425/*
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427% %
1428% %
1429% %
1430% G e t I m a g e E x c e p t i o n %
1431% %
1432% %
1433% %
1434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435%
1436% GetImageException() traverses an image sequence and returns any
1437% error more severe than noted by the exception parameter.
1438%
1439% The format of the GetImageException method is:
1440%
1441% void GetImageException(Image *image,ExceptionInfo *exception)
1442%
1443% A description of each parameter follows:
1444%
1445% o image: Specifies a pointer to a list of one or more images.
1446%
1447% o exception: return the highest severity exception.
1448%
1449*/
1450MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
1451{
1452 register Image
1453 *next;
1454
1455 assert(image != (Image *) NULL);
1456 assert(image->signature == MagickSignature);
1457 if (image->debug != MagickFalse)
1458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1459 assert(exception != (ExceptionInfo *) NULL);
1460 assert(exception->signature == MagickSignature);
1461 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
1462 {
1463 if (next->exception.severity == UndefinedException)
1464 continue;
1465 if (next->exception.severity > exception->severity)
1466 InheritException(exception,&next->exception);
1467 next->exception.severity=UndefinedException;
1468 }
1469}
1470
1471/*
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473% %
1474% %
1475% %
1476% G e t I m a g e I n f o %
1477% %
1478% %
1479% %
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481%
1482% GetImageInfo() initializes image_info to default values.
1483%
1484% The format of the GetImageInfo method is:
1485%
1486% void GetImageInfo(ImageInfo *image_info)
1487%
1488% A description of each parameter follows:
1489%
1490% o image_info: the image info.
1491%
1492*/
1493MagickExport void GetImageInfo(ImageInfo *image_info)
1494{
cristyd9a29192010-10-16 16:49:53 +00001495 const char
1496 *synchronize;
1497
cristy3ed852e2009-09-05 21:47:34 +00001498 ExceptionInfo
1499 *exception;
1500
1501 /*
1502 File and image dimension members.
1503 */
1504 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1505 assert(image_info != (ImageInfo *) NULL);
1506 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1507 image_info->adjoin=MagickTrue;
1508 image_info->interlace=NoInterlace;
1509 image_info->channel=DefaultChannels;
1510 image_info->quality=UndefinedCompressionQuality;
1511 image_info->antialias=MagickTrue;
1512 image_info->dither=MagickTrue;
cristyd9a29192010-10-16 16:49:53 +00001513 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1514 if (synchronize != (const char *) NULL)
1515 image_info->synchronize=IsMagickTrue(synchronize);
cristy3ed852e2009-09-05 21:47:34 +00001516 exception=AcquireExceptionInfo();
1517 (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
1518 exception);
1519 (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
1520 (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
1521 (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
1522 exception);
1523 exception=DestroyExceptionInfo(exception);
1524 image_info->debug=IsEventLogging();
1525 image_info->signature=MagickSignature;
1526}
1527
1528/*
1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530% %
1531% %
1532% %
cristy15781e52009-12-05 23:05:27 +00001533% G e t I m a g e I n f o F i l e %
1534% %
1535% %
1536% %
1537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538%
1539% GetImageInfoFile() returns the image info file member.
1540%
1541% The format of the GetImageInfoFile method is:
1542%
1543% FILE *GetImageInfoFile(const ImageInfo *image_info)
1544%
1545% A description of each parameter follows:
1546%
1547% o image_info: the image info.
1548%
1549*/
1550MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1551{
1552 return(image_info->file);
1553}
1554
1555/*
1556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557% %
1558% %
1559% %
cristy3ed852e2009-09-05 21:47:34 +00001560% G e t I m a g e M a s k %
1561% %
1562% %
1563% %
1564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565%
1566% GetImageMask() returns the mask associated with the image.
1567%
1568% The format of the GetImageMask method is:
1569%
1570% Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1571%
1572% A description of each parameter follows:
1573%
1574% o image: the image.
1575%
1576*/
1577MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
1578{
1579 assert(image != (const Image *) NULL);
1580 if (image->debug != MagickFalse)
1581 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1582 assert(image->signature == MagickSignature);
1583 if (image->mask == (Image *) NULL)
1584 return((Image *) NULL);
1585 return(CloneImage(image->mask,0,0,MagickTrue,exception));
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
1593+ G e t I m a g e R e f e r e n c e C o u n t %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetImageReferenceCount() returns the image reference count.
1600%
1601% The format of the GetReferenceCount method is:
1602%
cristybb503372010-05-27 20:51:26 +00001603% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
cristybb503372010-05-27 20:51:26 +00001610MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001611{
cristybb503372010-05-27 20:51:26 +00001612 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001613 reference_count;
1614
1615 assert(image != (Image *) NULL);
1616 assert(image->signature == MagickSignature);
1617 if (image->debug != MagickFalse)
1618 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001619 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001620 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001621 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001622 return(reference_count);
1623}
1624
1625/*
1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627% %
1628% %
1629% %
cristy3ed852e2009-09-05 21:47:34 +00001630% 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 %
1631% %
1632% %
1633% %
1634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635%
1636% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1637% image. A virtual pixel is any pixel access that is outside the boundaries
1638% of the image cache.
1639%
1640% The format of the GetImageVirtualPixelMethod() method is:
1641%
1642% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1643%
1644% A description of each parameter follows:
1645%
1646% o image: the image.
1647%
1648*/
1649MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1650{
1651 assert(image != (Image *) NULL);
1652 assert(image->signature == MagickSignature);
1653 if (image->debug != MagickFalse)
1654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1655 return(GetPixelCacheVirtualMethod(image));
1656}
1657
1658/*
1659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1660% %
1661% %
1662% %
1663% I n t e r p r e t I m a g e F i l e n a m e %
1664% %
1665% %
1666% %
1667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668%
1669% InterpretImageFilename() interprets embedded characters in an image filename.
1670% The filename length is returned.
1671%
1672% The format of the InterpretImageFilename method is:
1673%
1674% size_t InterpretImageFilename(const ImageInfo *image_info,
1675% Image *image,const char *format,int value,char *filename)
1676%
1677% A description of each parameter follows.
1678%
1679% o image_info: the image info..
1680%
1681% o image: the image.
1682%
1683% o format: A filename describing the format to use to write the numeric
1684% argument. Only the first numeric format identifier is replaced.
1685%
1686% o value: Numeric value to substitute into format filename.
1687%
1688% o filename: return the formatted filename in this character buffer.
1689%
1690*/
1691MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1692 Image *image,const char *format,int value,char *filename)
1693{
1694 char
1695 *q;
1696
1697 int
1698 c;
1699
1700 MagickBooleanType
1701 canonical;
1702
1703 register const char
1704 *p;
1705
1706 canonical=MagickFalse;
1707 (void) CopyMagickString(filename,format,MaxTextExtent);
1708 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1709 {
1710 q=(char *) p+1;
1711 if (*q == '%')
1712 {
1713 p=q+1;
1714 continue;
1715 }
1716 if (*q == '0')
1717 {
cristybb503372010-05-27 20:51:26 +00001718 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001719 value;
1720
cristybb503372010-05-27 20:51:26 +00001721 value=(ssize_t) strtol(q,&q,10);
cristyda16f162011-02-19 23:52:17 +00001722 (void) value;
cristy3ed852e2009-09-05 21:47:34 +00001723 }
1724 switch (*q)
1725 {
1726 case 'd':
1727 case 'o':
1728 case 'x':
1729 {
1730 q++;
1731 c=(*q);
1732 *q='\0';
1733 (void) FormatMagickString(filename+(p-format),(size_t) (MaxTextExtent-
1734 (p-format)),p,value);
1735 *q=c;
1736 (void) ConcatenateMagickString(filename,q,MaxTextExtent);
1737 canonical=MagickTrue;
1738 if (*(q-1) != '%')
1739 break;
1740 p++;
1741 break;
1742 }
1743 case '[':
1744 {
1745 char
1746 pattern[MaxTextExtent];
1747
1748 const char
1749 *value;
1750
cristy3ed852e2009-09-05 21:47:34 +00001751 register char
1752 *r;
1753
cristybb503372010-05-27 20:51:26 +00001754 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001755 i;
1756
cristycb6d09b2010-06-19 01:59:36 +00001757 ssize_t
1758 depth;
1759
cristy3ed852e2009-09-05 21:47:34 +00001760 /*
1761 Image option.
1762 */
1763 if (strchr(p,']') == (char *) NULL)
1764 break;
1765 depth=1;
1766 r=q+1;
1767 for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
1768 {
1769 if (*r == '[')
1770 depth++;
1771 if (*r == ']')
1772 depth--;
1773 if (depth <= 0)
1774 break;
1775 pattern[i]=(*r++);
1776 }
1777 pattern[i]='\0';
1778 if (LocaleNCompare(pattern,"filename:",9) != 0)
1779 break;
1780 value=(const char *) NULL;
1781 if ((image_info != (const ImageInfo *) NULL) &&
1782 (image != (const Image *) NULL))
cristy86fe49e2010-06-25 01:18:11 +00001783 value=GetMagickProperty(image_info,image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001784 else
1785 if (image != (Image *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001786 value=GetImageProperty(image,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001787 else
1788 if (image_info != (ImageInfo *) NULL)
cristy86fe49e2010-06-25 01:18:11 +00001789 value=GetImageOption(image_info,pattern);
cristy3ed852e2009-09-05 21:47:34 +00001790 if (value == (const char *) NULL)
1791 break;
1792 q--;
1793 c=(*q);
1794 *q='\0';
1795 (void) CopyMagickString(filename+(p-format),value,(size_t)
1796 (MaxTextExtent-(p-format)));
1797 *q=c;
1798 (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
1799 canonical=MagickTrue;
1800 if (*(q-1) != '%')
1801 break;
1802 p++;
1803 break;
1804 }
1805 default:
1806 break;
1807 }
1808 }
1809 for (q=filename; *q != '\0'; q++)
1810 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001811 {
1812 (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
1813 canonical=MagickTrue;
1814 }
cristy3ed852e2009-09-05 21:47:34 +00001815 if (canonical == MagickFalse)
1816 (void) CopyMagickString(filename,format,MaxTextExtent);
1817 return(strlen(filename));
1818}
1819
1820/*
1821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1822% %
1823% %
1824% %
1825% I s H i g h D y n a m i c R a n g e I m a g e %
1826% %
1827% %
1828% %
1829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830%
1831% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1832% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1833% 0..65535.
1834%
1835% The format of the IsHighDynamicRangeImage method is:
1836%
1837% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1838% ExceptionInfo *exception)
1839%
1840% A description of each parameter follows:
1841%
1842% o image: the image.
1843%
1844% o exception: return any errors or warnings in this structure.
1845%
1846*/
1847MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1848 ExceptionInfo *exception)
1849{
1850#if !defined(MAGICKCORE_HDRI_SUPPORT)
1851 (void) image;
1852 (void) exception;
1853 return(MagickFalse);
1854#else
1855 CacheView
1856 *image_view;
1857
cristy3ed852e2009-09-05 21:47:34 +00001858 MagickBooleanType
1859 status;
1860
1861 MagickPixelPacket
1862 zero;
1863
cristycb6d09b2010-06-19 01:59:36 +00001864 ssize_t
1865 y;
1866
cristy3ed852e2009-09-05 21:47:34 +00001867 assert(image != (Image *) NULL);
1868 assert(image->signature == MagickSignature);
1869 if (image->debug != MagickFalse)
1870 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1871 status=MagickTrue;
1872 GetMagickPixelPacket(image,&zero);
1873 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00001874#if defined(MAGICKCORE_OPENMP_SUPPORT)
1875 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001876#endif
cristybb503372010-05-27 20:51:26 +00001877 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001878 {
1879 MagickPixelPacket
1880 pixel;
1881
1882 register const IndexPacket
1883 *indexes;
1884
1885 register const PixelPacket
1886 *p;
1887
cristybb503372010-05-27 20:51:26 +00001888 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001889 x;
1890
1891 if (status == MagickFalse)
1892 continue;
1893 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1894 if (p == (const PixelPacket *) NULL)
1895 {
1896 status=MagickFalse;
1897 continue;
1898 }
1899 indexes=GetCacheViewVirtualIndexQueue(image_view);
1900 pixel=zero;
cristybb503372010-05-27 20:51:26 +00001901 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001902 {
1903 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1904 if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
1905 (pixel.red != (QuantumAny) pixel.red))
1906 break;
1907 if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
1908 (pixel.green != (QuantumAny) pixel.green))
1909 break;
1910 if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
1911 (pixel.blue != (QuantumAny) pixel.blue))
1912 break;
1913 if (pixel.matte != MagickFalse)
1914 {
1915 if ((pixel.opacity < 0.0) || (pixel.opacity > QuantumRange) ||
1916 (pixel.opacity != (QuantumAny) pixel.opacity))
1917 break;
1918 }
1919 if (pixel.colorspace == CMYKColorspace)
1920 {
1921 if ((pixel.index < 0.0) || (pixel.index > QuantumRange) ||
1922 (pixel.index != (QuantumAny) pixel.index))
1923 break;
1924 }
1925 p++;
1926 }
cristybb503372010-05-27 20:51:26 +00001927 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001928 status=MagickFalse;
1929 }
1930 image_view=DestroyCacheView(image_view);
1931 return(status != MagickFalse ? MagickFalse : MagickTrue);
1932#endif
1933}
1934
1935/*
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937% %
1938% %
1939% %
1940% I s I m a g e O b j e c t %
1941% %
1942% %
1943% %
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945%
1946% IsImageObject() returns MagickTrue if the image sequence contains a valid
1947% set of image objects.
1948%
1949% The format of the IsImageObject method is:
1950%
1951% MagickBooleanType IsImageObject(const Image *image)
1952%
1953% A description of each parameter follows:
1954%
1955% o image: the image.
1956%
1957*/
1958MagickExport MagickBooleanType IsImageObject(const Image *image)
1959{
1960 register const Image
1961 *p;
1962
1963 assert(image != (Image *) NULL);
1964 if (image->debug != MagickFalse)
1965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1966 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1967 if (p->signature != MagickSignature)
1968 return(MagickFalse);
1969 return(MagickTrue);
1970}
1971
1972/*
1973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974% %
1975% %
1976% %
1977% I s T a i n t I m a g e %
1978% %
1979% %
1980% %
1981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982%
1983% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1984% since it was first constituted.
1985%
1986% The format of the IsTaintImage method is:
1987%
1988% MagickBooleanType IsTaintImage(const Image *image)
1989%
1990% A description of each parameter follows:
1991%
1992% o image: the image.
1993%
1994*/
1995MagickExport MagickBooleanType IsTaintImage(const Image *image)
1996{
1997 char
1998 magick[MaxTextExtent],
1999 filename[MaxTextExtent];
2000
2001 register const Image
2002 *p;
2003
2004 assert(image != (Image *) NULL);
2005 if (image->debug != MagickFalse)
2006 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2007 assert(image->signature == MagickSignature);
2008 (void) CopyMagickString(magick,image->magick,MaxTextExtent);
2009 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2010 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2011 {
2012 if (p->taint != MagickFalse)
2013 return(MagickTrue);
2014 if (LocaleCompare(p->magick,magick) != 0)
2015 return(MagickTrue);
2016 if (LocaleCompare(p->filename,filename) != 0)
2017 return(MagickTrue);
2018 }
2019 return(MagickFalse);
2020}
2021
2022/*
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024% %
2025% %
2026% %
2027% M o d i f y I m a g e %
2028% %
2029% %
2030% %
2031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2032%
2033% ModifyImage() ensures that there is only a single reference to the image
2034% to be modified, updating the provided image pointer to point to a clone of
2035% the original image if necessary.
2036%
2037% The format of the ModifyImage method is:
2038%
2039% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2040%
2041% A description of each parameter follows:
2042%
2043% o image: the image.
2044%
2045% o exception: return any errors or warnings in this structure.
2046%
2047*/
2048MagickExport MagickBooleanType ModifyImage(Image **image,
2049 ExceptionInfo *exception)
2050{
2051 Image
2052 *clone_image;
2053
2054 assert(image != (Image **) NULL);
2055 assert(*image != (Image *) NULL);
2056 assert((*image)->signature == MagickSignature);
2057 if ((*image)->debug != MagickFalse)
2058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2059 if (GetImageReferenceCount(*image) <= 1)
2060 return(MagickTrue);
2061 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00002062 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002063 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00002064 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002065 *image=clone_image;
2066 return(MagickTrue);
2067}
2068
2069/*
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071% %
2072% %
2073% %
2074% N e w M a g i c k I m a g e %
2075% %
2076% %
2077% %
2078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079%
2080% NewMagickImage() creates a blank image canvas of the specified size and
2081% background color.
2082%
2083% The format of the NewMagickImage method is:
2084%
2085% Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002086% const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002087% const MagickPixelPacket *background)
2088%
2089% A description of each parameter follows:
2090%
2091% o image: the image.
2092%
2093% o width: the image width.
2094%
2095% o height: the image height.
2096%
2097% o background: the image color.
2098%
2099*/
2100MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +00002101 const size_t width,const size_t height,
cristy3ed852e2009-09-05 21:47:34 +00002102 const MagickPixelPacket *background)
2103{
2104 CacheView
2105 *image_view;
2106
2107 ExceptionInfo
2108 *exception;
2109
2110 Image
2111 *image;
2112
cristybb503372010-05-27 20:51:26 +00002113 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002114 y;
2115
2116 MagickBooleanType
2117 status;
2118
2119 assert(image_info != (const ImageInfo *) NULL);
2120 if (image_info->debug != MagickFalse)
2121 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2122 assert(image_info->signature == MagickSignature);
2123 assert(background != (const MagickPixelPacket *) NULL);
2124 image=AcquireImage(image_info);
2125 image->columns=width;
2126 image->rows=height;
2127 image->colorspace=background->colorspace;
2128 image->matte=background->matte;
2129 image->fuzz=background->fuzz;
2130 image->depth=background->depth;
2131 status=MagickTrue;
2132 exception=(&image->exception);
2133 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00002134#if defined(MAGICKCORE_OPENMP_SUPPORT)
2135 #pragma omp parallel for schedule(dynamic,4) shared(status)
2136#endif
cristybb503372010-05-27 20:51:26 +00002137 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002138 {
2139 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002140 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002141
cristy3ed852e2009-09-05 21:47:34 +00002142 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002143 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002144
cristycb6d09b2010-06-19 01:59:36 +00002145 register ssize_t
2146 x;
2147
cristy48974b92009-12-19 02:36:06 +00002148 if (status == MagickFalse)
2149 continue;
cristy3ed852e2009-09-05 21:47:34 +00002150 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2151 if (q == (PixelPacket *) NULL)
2152 {
2153 status=MagickFalse;
2154 continue;
2155 }
2156 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002157 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002158 {
2159 SetPixelPacket(image,background,q,indexes+x);
2160 q++;
2161 }
2162 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2163 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002164 }
2165 image_view=DestroyCacheView(image_view);
2166 if (status == MagickFalse)
2167 image=DestroyImage(image);
2168 return(image);
2169}
2170
2171/*
2172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173% %
2174% %
2175% %
2176% R e f e r e n c e I m a g e %
2177% %
2178% %
2179% %
2180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2181%
2182% ReferenceImage() increments the reference count associated with an image
2183% returning a pointer to the image.
2184%
2185% The format of the ReferenceImage method is:
2186%
2187% Image *ReferenceImage(Image *image)
2188%
2189% A description of each parameter follows:
2190%
2191% o image: the image.
2192%
2193*/
2194MagickExport Image *ReferenceImage(Image *image)
2195{
2196 assert(image != (Image *) NULL);
2197 if (image->debug != MagickFalse)
2198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2199 assert(image->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00002200 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002201 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002202 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002203 return(image);
2204}
2205
2206/*
2207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208% %
2209% %
2210% %
2211% R e s e t I m a g e P a g e %
2212% %
2213% %
2214% %
2215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216%
2217% ResetImagePage() resets the image page canvas and position.
2218%
2219% The format of the ResetImagePage method is:
2220%
2221% MagickBooleanType ResetImagePage(Image *image,const char *page)
2222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o page: the relative page specification.
2228%
2229*/
2230MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2231{
2232 MagickStatusType
2233 flags;
2234
2235 RectangleInfo
2236 geometry;
2237
2238 assert(image != (Image *) NULL);
2239 assert(image->signature == MagickSignature);
2240 if (image->debug != MagickFalse)
2241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2242 flags=ParseAbsoluteGeometry(page,&geometry);
2243 if ((flags & WidthValue) != 0)
2244 {
2245 if ((flags & HeightValue) == 0)
2246 geometry.height=geometry.width;
2247 image->page.width=geometry.width;
2248 image->page.height=geometry.height;
2249 }
2250 if ((flags & AspectValue) != 0)
2251 {
2252 if ((flags & XValue) != 0)
2253 image->page.x+=geometry.x;
2254 if ((flags & YValue) != 0)
2255 image->page.y+=geometry.y;
2256 }
2257 else
2258 {
2259 if ((flags & XValue) != 0)
2260 {
2261 image->page.x=geometry.x;
2262 if ((image->page.width == 0) && (geometry.x > 0))
2263 image->page.width=image->columns+geometry.x;
2264 }
2265 if ((flags & YValue) != 0)
2266 {
2267 image->page.y=geometry.y;
2268 if ((image->page.height == 0) && (geometry.y > 0))
2269 image->page.height=image->rows+geometry.y;
2270 }
2271 }
2272 return(MagickTrue);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
2280% S e p a r a t e I m a g e C h a n n e l %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
2286% SeparateImageChannel() separates a channel from the image and returns it as
2287% a grayscale image. A channel is a particular color component of each pixel
2288% in the image.
2289%
2290% The format of the SeparateImageChannel method is:
2291%
2292% MagickBooleanType SeparateImageChannel(Image *image,
2293% const ChannelType channel)
2294%
2295% A description of each parameter follows:
2296%
2297% o image: the image.
2298%
2299% o channel: Identify which channel to extract: RedChannel, GreenChannel,
2300% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2301% YellowChannel, or BlackChannel.
2302%
2303*/
2304MagickExport MagickBooleanType SeparateImageChannel(Image *image,
2305 const ChannelType channel)
2306{
2307#define SeparateImageTag "Separate/Image"
2308
2309 CacheView
2310 *image_view;
2311
2312 ExceptionInfo
2313 *exception;
2314
cristy3ed852e2009-09-05 21:47:34 +00002315 MagickBooleanType
2316 status;
2317
cristybb503372010-05-27 20:51:26 +00002318 MagickOffsetType
2319 progress;
2320
2321 ssize_t
2322 y;
2323
cristy3ed852e2009-09-05 21:47:34 +00002324 assert(image != (Image *) NULL);
2325 assert(image->signature == MagickSignature);
2326 if (image->debug != MagickFalse)
2327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2328 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2329 return(MagickFalse);
2330 /*
2331 Separate image channels.
2332 */
2333 status=MagickTrue;
cristy11b66ce2010-03-11 13:34:19 +00002334 if (channel == GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002335 image->matte=MagickTrue;
2336 progress=0;
2337 exception=(&image->exception);
2338 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002339#if defined(MAGICKCORE_OPENMP_SUPPORT)
2340 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
cristy3ed852e2009-09-05 21:47:34 +00002341#endif
cristybb503372010-05-27 20:51:26 +00002342 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002343 {
2344 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002345 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002346
cristy3ed852e2009-09-05 21:47:34 +00002347 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002348 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002349
cristycb6d09b2010-06-19 01:59:36 +00002350 register ssize_t
2351 x;
2352
cristy3ed852e2009-09-05 21:47:34 +00002353 if (status == MagickFalse)
2354 continue;
2355 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2356 if (q == (PixelPacket *) NULL)
2357 {
2358 status=MagickFalse;
2359 continue;
2360 }
2361 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2362 switch (channel)
2363 {
2364 case RedChannel:
2365 {
cristybb503372010-05-27 20:51:26 +00002366 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002367 {
2368 q->green=q->red;
2369 q->blue=q->red;
2370 q++;
2371 }
2372 break;
2373 }
2374 case GreenChannel:
2375 {
cristybb503372010-05-27 20:51:26 +00002376 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002377 {
2378 q->red=q->green;
2379 q->blue=q->green;
2380 q++;
2381 }
2382 break;
2383 }
2384 case BlueChannel:
2385 {
cristybb503372010-05-27 20:51:26 +00002386 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002387 {
2388 q->red=q->blue;
2389 q->green=q->blue;
2390 q++;
2391 }
2392 break;
2393 }
2394 case OpacityChannel:
2395 {
cristybb503372010-05-27 20:51:26 +00002396 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002397 {
2398 q->red=q->opacity;
2399 q->green=q->opacity;
2400 q->blue=q->opacity;
2401 q++;
2402 }
2403 break;
2404 }
2405 case BlackChannel:
2406 {
2407 if ((image->storage_class != PseudoClass) &&
2408 (image->colorspace != CMYKColorspace))
2409 break;
cristybb503372010-05-27 20:51:26 +00002410 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002411 {
2412 q->red=indexes[x];
2413 q->green=indexes[x];
2414 q->blue=indexes[x];
2415 q++;
2416 }
2417 break;
2418 }
2419 case TrueAlphaChannel:
2420 {
cristybb503372010-05-27 20:51:26 +00002421 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002422 {
cristy46f08202010-01-10 04:04:21 +00002423 q->red=(Quantum) GetAlphaPixelComponent(q);
2424 q->green=(Quantum) GetAlphaPixelComponent(q);
2425 q->blue=(Quantum) GetAlphaPixelComponent(q);
cristy3ed852e2009-09-05 21:47:34 +00002426 q++;
2427 }
2428 break;
2429 }
2430 case GrayChannels:
2431 {
cristybb503372010-05-27 20:51:26 +00002432 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002433 {
2434 q->opacity=(Quantum) (QuantumRange-PixelIntensityToQuantum(q));
2435 q++;
2436 }
2437 break;
2438 }
2439 default:
2440 break;
2441 }
2442 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2443 status=MagickFalse;
2444 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2445 {
2446 MagickBooleanType
2447 proceed;
2448
cristyb5d5f722009-11-04 03:03:49 +00002449#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00002450 #pragma omp critical (MagickCore_SeparateImageChannel)
2451#endif
2452 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
2453 if (proceed == MagickFalse)
2454 status=MagickFalse;
2455 }
2456 }
2457 image_view=DestroyCacheView(image_view);
cristy11b66ce2010-03-11 13:34:19 +00002458 if (channel != GrayChannels)
cristy3ed852e2009-09-05 21:47:34 +00002459 image->matte=MagickFalse;
2460 (void) SetImageColorspace(image,RGBColorspace);
2461 return(status);
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469% S e p a r a t e I m a g e s %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
2475% SeparateImages() returns a separate grayscale image for each channel
2476% specified.
2477%
2478% The format of the SeparateImages method is:
2479%
2480% MagickBooleanType SeparateImages(const Image *image,
2481% const ChannelType channel,ExceptionInfo *exception)
2482%
2483% A description of each parameter follows:
2484%
2485% o image: the image.
2486%
2487% o channel: Identify which channels to extract: RedChannel, GreenChannel,
2488% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
2489% YellowChannel, or BlackChannel.
2490%
2491% o exception: return any errors or warnings in this structure.
2492%
2493*/
2494MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
2495 ExceptionInfo *exception)
2496{
2497 Image
2498 *images,
2499 *separate_image;
2500
2501 assert(image != (Image *) NULL);
2502 assert(image->signature == MagickSignature);
2503 if (image->debug != MagickFalse)
2504 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2505 images=NewImageList();
2506 if ((channel & RedChannel) != 0)
2507 {
2508 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2509 (void) SeparateImageChannel(separate_image,RedChannel);
2510 AppendImageToList(&images,separate_image);
2511 }
2512 if ((channel & GreenChannel) != 0)
2513 {
2514 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2515 (void) SeparateImageChannel(separate_image,GreenChannel);
2516 AppendImageToList(&images,separate_image);
2517 }
2518 if ((channel & BlueChannel) != 0)
2519 {
2520 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2521 (void) SeparateImageChannel(separate_image,BlueChannel);
2522 AppendImageToList(&images,separate_image);
2523 }
2524 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
2525 {
2526 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2527 (void) SeparateImageChannel(separate_image,BlackChannel);
2528 AppendImageToList(&images,separate_image);
2529 }
2530 if ((channel & OpacityChannel) != 0)
2531 {
2532 separate_image=CloneImage(image,0,0,MagickTrue,exception);
2533 (void) SeparateImageChannel(separate_image,OpacityChannel);
2534 AppendImageToList(&images,separate_image);
2535 }
2536 return(images);
2537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
2544% S e t I m a g e A l p h a C h a n n e l %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
2551% channel.
2552%
2553% The format of the SetImageAlphaChannel method is:
2554%
2555% MagickBooleanType SetImageAlphaChannel(Image *image,
2556% const AlphaChannelType alpha_type)
2557%
2558% A description of each parameter follows:
2559%
2560% o image: the image.
2561%
2562% o alpha_type: The alpha channel type: ActivateAlphaChannel,
2563% CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
2564% OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
2565% ShapeAlphaChannel, and TransparentAlphaChannel.
2566%
2567*/
2568MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
2569 const AlphaChannelType alpha_type)
2570{
2571 MagickBooleanType
2572 status;
2573
2574 assert(image != (Image *) NULL);
2575 if (image->debug != MagickFalse)
2576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2577 assert(image->signature == MagickSignature);
2578 status=MagickFalse;
2579 switch (alpha_type)
2580 {
2581 case ActivateAlphaChannel:
2582 {
2583 image->matte=MagickTrue;
2584 break;
2585 }
2586 case BackgroundAlphaChannel:
2587 {
2588 CacheView
2589 *image_view;
2590
2591 ExceptionInfo
2592 *exception;
2593
2594 IndexPacket
2595 index;
2596
cristy3ed852e2009-09-05 21:47:34 +00002597 MagickBooleanType
2598 status;
2599
2600 MagickPixelPacket
2601 background;
2602
2603 PixelPacket
2604 pixel;
2605
cristycb6d09b2010-06-19 01:59:36 +00002606 ssize_t
2607 y;
2608
cristy3ed852e2009-09-05 21:47:34 +00002609 /*
2610 Set transparent pixels to background color.
2611 */
2612 if (image->matte == MagickFalse)
2613 break;
2614 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2615 break;
2616 GetMagickPixelPacket(image,&background);
2617 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2618 NULL,&background);
2619 if (image->colorspace == CMYKColorspace)
2620 ConvertRGBToCMYK(&background);
2621 index=0;
2622 SetPixelPacket(image,&background,&pixel,&index);
2623 status=MagickTrue;
2624 exception=(&image->exception);
2625 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00002626 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2627 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00002628 #endif
cristybb503372010-05-27 20:51:26 +00002629 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002630 {
2631 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002632 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002633
cristy3ed852e2009-09-05 21:47:34 +00002634 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002635 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002636
cristycb6d09b2010-06-19 01:59:36 +00002637 register ssize_t
2638 x;
2639
cristy3ed852e2009-09-05 21:47:34 +00002640 if (status == MagickFalse)
2641 continue;
2642 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2643 exception);
2644 if (q == (PixelPacket *) NULL)
2645 {
2646 status=MagickFalse;
2647 continue;
2648 }
cristybb503372010-05-27 20:51:26 +00002649 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002650 {
2651 if (q->opacity == TransparentOpacity)
2652 {
2653 q->red=pixel.red;
2654 q->green=pixel.green;
2655 q->blue=pixel.blue;
2656 }
2657 q++;
2658 }
2659 if (image->colorspace == CMYKColorspace)
2660 {
2661 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002662 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002663 indexes[x]=index;
2664 }
2665 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2666 status=MagickFalse;
2667 }
2668 image_view=DestroyCacheView(image_view);
2669 return(status);
2670 }
2671 case DeactivateAlphaChannel:
2672 {
2673 image->matte=MagickFalse;
2674 break;
2675 }
2676 case ShapeAlphaChannel:
2677 case CopyAlphaChannel:
2678 {
2679 /*
2680 Special usage case for SeparateImageChannel(): copy grayscale color to
2681 the alpha channel.
2682 */
2683 status=SeparateImageChannel(image,GrayChannels);
2684 image->matte=MagickTrue; /* make sure transparency is now on! */
2685 if (alpha_type == ShapeAlphaChannel)
2686 {
2687 MagickPixelPacket
2688 background;
2689
2690 /*
2691 Reset all color channels to background color.
2692 */
2693 GetMagickPixelPacket(image,&background);
2694 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
2695 NULL,&background);
cristy308b4e62009-09-21 14:40:44 +00002696 (void) LevelColorsImage(image,&background,&background,MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002697 }
2698 break;
2699 }
2700 case ExtractAlphaChannel:
2701 {
2702 status=SeparateImageChannel(image,TrueAlphaChannel);
2703 image->matte=MagickFalse;
2704 break;
2705 }
cristyf64d18b2010-04-30 12:47:03 +00002706 case ResetAlphaChannel: /* deprecated */
cristy3ed852e2009-09-05 21:47:34 +00002707 case OpaqueAlphaChannel:
2708 {
2709 status=SetImageOpacity(image,OpaqueOpacity);
2710 image->matte=MagickTrue;
2711 break;
2712 }
2713 case TransparentAlphaChannel:
2714 {
2715 status=SetImageOpacity(image,TransparentOpacity);
2716 image->matte=MagickTrue;
2717 break;
2718 }
2719 case SetAlphaChannel:
2720 {
2721 if (image->matte == MagickFalse)
2722 {
2723 status=SetImageOpacity(image,OpaqueOpacity);
2724 image->matte=MagickTrue;
2725 }
2726 break;
2727 }
2728 case UndefinedAlphaChannel:
2729 break;
2730 }
2731 return(status);
2732}
2733
2734/*
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736% %
2737% %
2738% %
2739% S e t I m a g e B a c k g r o u n d C o l o r %
2740% %
2741% %
2742% %
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744%
2745% SetImageBackgroundColor() initializes the image pixels to the image
2746% background color. The background color is defined by the background_color
2747% member of the image structure.
2748%
2749% The format of the SetImage method is:
2750%
2751% MagickBooleanType SetImageBackgroundColor(Image *image)
2752%
2753% A description of each parameter follows:
2754%
2755% o image: the image.
2756%
2757*/
2758MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
2759{
2760 CacheView
2761 *image_view;
2762
2763 ExceptionInfo
2764 *exception;
2765
2766 IndexPacket
2767 index;
2768
cristy3ed852e2009-09-05 21:47:34 +00002769 MagickBooleanType
2770 status;
2771
2772 MagickPixelPacket
2773 background;
2774
2775 PixelPacket
2776 pixel;
2777
cristycb6d09b2010-06-19 01:59:36 +00002778 ssize_t
2779 y;
2780
cristy3ed852e2009-09-05 21:47:34 +00002781 assert(image != (Image *) NULL);
2782 if (image->debug != MagickFalse)
2783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2784 assert(image->signature == MagickSignature);
2785 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2786 return(MagickFalse);
2787 if (image->background_color.opacity != OpaqueOpacity)
2788 image->matte=MagickTrue;
2789 GetMagickPixelPacket(image,&background);
2790 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
2791 NULL,&background);
2792 if (image->colorspace == CMYKColorspace)
2793 ConvertRGBToCMYK(&background);
2794 index=0;
2795 SetPixelPacket(image,&background,&pixel,&index);
2796 /*
2797 Set image background color.
2798 */
2799 status=MagickTrue;
2800 exception=(&image->exception);
2801 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +00002802 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002803 {
cristy3ed852e2009-09-05 21:47:34 +00002804 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002805 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002806
cristycb6d09b2010-06-19 01:59:36 +00002807 register ssize_t
2808 x;
2809
cristy3ed852e2009-09-05 21:47:34 +00002810 if (status == MagickFalse)
2811 continue;
2812 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2813 if (q == (PixelPacket *) NULL)
2814 {
2815 status=MagickFalse;
2816 continue;
2817 }
cristybb503372010-05-27 20:51:26 +00002818 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002819 *q++=pixel;
2820 if (image->colorspace == CMYKColorspace)
2821 {
cristy29058e62011-02-24 03:12:50 +00002822 register IndexPacket
2823 *restrict indexes;
2824
cristy3ed852e2009-09-05 21:47:34 +00002825 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002826 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002827 indexes[x]=index;
2828 }
2829 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2830 status=MagickFalse;
2831 }
2832 image_view=DestroyCacheView(image_view);
2833 return(status);
2834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristya5b77cb2010-05-07 19:34:48 +00002841% S e t I m a g e C o l o r %
2842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
2847% SetImageColor() set the entire image canvas to the specified color.
2848%
2849% The format of the SetImageColor method is:
2850%
2851% MagickBooleanType SetImageColor(Image *image,
2852% const MagickPixelPacket *color)
2853%
2854% A description of each parameter follows:
2855%
2856% o image: the image.
2857%
2858% o background: the image color.
2859%
2860*/
2861MagickExport MagickBooleanType SetImageColor(Image *image,
2862 const MagickPixelPacket *color)
2863{
2864 CacheView
2865 *image_view;
2866
2867 ExceptionInfo
2868 *exception;
2869
cristya5b77cb2010-05-07 19:34:48 +00002870 MagickBooleanType
2871 status;
2872
cristycb6d09b2010-06-19 01:59:36 +00002873 ssize_t
2874 y;
2875
cristya5b77cb2010-05-07 19:34:48 +00002876 assert(image != (Image *) NULL);
2877 if (image->debug != MagickFalse)
2878 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2879 assert(image->signature == MagickSignature);
2880 assert(color != (const MagickPixelPacket *) NULL);
2881 image->colorspace=color->colorspace;
2882 image->matte=color->matte;
2883 image->fuzz=color->fuzz;
2884 image->depth=color->depth;
2885 status=MagickTrue;
2886 exception=(&image->exception);
2887 image_view=AcquireCacheView(image);
2888#if defined(MAGICKCORE_OPENMP_SUPPORT)
2889 #pragma omp parallel for schedule(dynamic,4) shared(status)
2890#endif
cristybb503372010-05-27 20:51:26 +00002891 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002892 {
2893 register IndexPacket
2894 *restrict indexes;
2895
cristya5b77cb2010-05-07 19:34:48 +00002896 register PixelPacket
2897 *restrict q;
2898
cristycb6d09b2010-06-19 01:59:36 +00002899 register ssize_t
2900 x;
2901
cristya5b77cb2010-05-07 19:34:48 +00002902 if (status == MagickFalse)
2903 continue;
2904 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2905 if (q == (PixelPacket *) NULL)
2906 {
2907 status=MagickFalse;
2908 continue;
2909 }
2910 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00002911 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002912 {
2913 SetPixelPacket(image,color,q,indexes+x);
2914 q++;
2915 }
2916 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2917 status=MagickFalse;
2918 }
2919 image_view=DestroyCacheView(image_view);
2920 return(status);
2921}
2922
2923/*
2924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925% %
2926% %
2927% %
cristy3ed852e2009-09-05 21:47:34 +00002928% S e t I m a g e S t o r a g e C l a s s %
2929% %
2930% %
2931% %
2932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933%
2934% SetImageStorageClass() sets the image class: DirectClass for true color
2935% images or PseudoClass for colormapped images.
2936%
2937% The format of the SetImageStorageClass method is:
2938%
2939% MagickBooleanType SetImageStorageClass(Image *image,
2940% const ClassType storage_class)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946% o storage_class: The image class.
2947%
2948*/
2949MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2950 const ClassType storage_class)
2951{
cristy3ed852e2009-09-05 21:47:34 +00002952 image->storage_class=storage_class;
cristy537e2722010-09-21 15:30:59 +00002953 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002954}
2955
2956/*
2957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2958% %
2959% %
2960% %
2961% S e t I m a g e C l i p M a s k %
2962% %
2963% %
2964% %
2965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2966%
2967% SetImageClipMask() associates a clip path with the image. The clip path
2968% must be the same dimensions as the image. Set any pixel component of
2969% the clip path to TransparentOpacity to prevent that corresponding image
2970% pixel component from being updated when SyncAuthenticPixels() is applied.
2971%
2972% The format of the SetImageClipMask method is:
2973%
2974% MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
2975%
2976% A description of each parameter follows:
2977%
2978% o image: the image.
2979%
2980% o clip_mask: the image clip path.
2981%
2982*/
2983MagickExport MagickBooleanType SetImageClipMask(Image *image,
2984 const Image *clip_mask)
2985{
2986 assert(image != (Image *) NULL);
2987 if (image->debug != MagickFalse)
2988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2989 assert(image->signature == MagickSignature);
2990 if (clip_mask != (const Image *) NULL)
2991 if ((clip_mask->columns != image->columns) ||
2992 (clip_mask->rows != image->rows))
2993 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
2994 if (image->clip_mask != (Image *) NULL)
2995 image->clip_mask=DestroyImage(image->clip_mask);
2996 image->clip_mask=NewImageList();
2997 if (clip_mask == (Image *) NULL)
2998 return(MagickTrue);
2999 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3000 return(MagickFalse);
3001 image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
3002 if (image->clip_mask == (Image *) NULL)
3003 return(MagickFalse);
3004 return(MagickTrue);
3005}
3006
3007/*
3008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009% %
3010% %
3011% %
3012% S e t I m a g e E x t e n t %
3013% %
3014% %
3015% %
3016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3017%
3018% SetImageExtent() sets the image size (i.e. columns & rows).
3019%
3020% The format of the SetImageExtent method is:
3021%
3022% MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003023% const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003024%
3025% A description of each parameter follows:
3026%
3027% o image: the image.
3028%
3029% o columns: The image width in pixels.
3030%
3031% o rows: The image height in pixels.
3032%
3033*/
3034MagickExport MagickBooleanType SetImageExtent(Image *image,
cristybb503372010-05-27 20:51:26 +00003035 const size_t columns,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003036{
cristy537e2722010-09-21 15:30:59 +00003037 if ((columns == 0) || (rows == 0))
3038 return(MagickFalse);
3039 image->columns=columns;
3040 image->rows=rows;
3041 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00003042}
3043
3044/*
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046% %
3047% %
3048% %
3049+ S e t I m a g e I n f o %
3050% %
3051% %
3052% %
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054%
3055% SetImageInfo() initializes the `magick' field of the ImageInfo structure.
3056% It is set to a type of image format based on the prefix or suffix of the
3057% filename. For example, `ps:image' returns PS indicating a Postscript image.
3058% JPEG is returned for this filename: `image.jpg'. The filename prefix has
3059% precendence over the suffix. Use an optional index enclosed in brackets
3060% after a file name to specify a desired scene of a multi-resolution image
3061% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
3062% indicates success.
3063%
3064% The format of the SetImageInfo method is:
3065%
3066% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003067% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003068%
3069% A description of each parameter follows:
3070%
cristyd965a422010-03-03 17:47:35 +00003071% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00003072%
cristyd965a422010-03-03 17:47:35 +00003073% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00003074%
3075% o exception: return any errors or warnings in this structure.
3076%
3077*/
3078MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00003079 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003080{
3081 char
3082 extension[MaxTextExtent],
3083 filename[MaxTextExtent],
3084 magic[MaxTextExtent],
3085 *q,
3086 subimage[MaxTextExtent];
3087
3088 const MagicInfo
3089 *magic_info;
3090
3091 const MagickInfo
3092 *magick_info;
3093
3094 ExceptionInfo
3095 *sans_exception;
3096
3097 Image
3098 *image;
3099
3100 MagickBooleanType
3101 status;
3102
3103 register const char
3104 *p;
3105
3106 ssize_t
3107 count;
3108
3109 unsigned char
3110 magick[2*MaxTextExtent];
3111
3112 /*
3113 Look for 'image.format' in filename.
3114 */
3115 assert(image_info != (ImageInfo *) NULL);
3116 assert(image_info->signature == MagickSignature);
3117 if (image_info->debug != MagickFalse)
3118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3119 image_info->filename);
3120 *subimage='\0';
cristyd965a422010-03-03 17:47:35 +00003121 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003122 {
cristyd965a422010-03-03 17:47:35 +00003123 GetPathComponent(image_info->filename,SubimagePath,subimage);
3124 if (*subimage != '\0')
cristy3ed852e2009-09-05 21:47:34 +00003125 {
cristyd965a422010-03-03 17:47:35 +00003126 /*
3127 Look for scene specification (e.g. img0001.pcd[4]).
3128 */
3129 if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
3130 {
3131 if (IsGeometry(subimage) != MagickFalse)
3132 (void) CloneString(&image_info->extract,subimage);
3133 }
3134 else
3135 {
cristybb503372010-05-27 20:51:26 +00003136 size_t
cristyd965a422010-03-03 17:47:35 +00003137 first,
3138 last;
cristy3ed852e2009-09-05 21:47:34 +00003139
cristyd965a422010-03-03 17:47:35 +00003140 (void) CloneString(&image_info->scenes,subimage);
3141 image_info->scene=StringToUnsignedLong(image_info->scenes);
3142 image_info->number_scenes=image_info->scene;
3143 p=image_info->scenes;
3144 for (q=(char *) image_info->scenes; *q != '\0'; p++)
3145 {
3146 while ((isspace((int) ((unsigned char) *p)) != 0) ||
3147 (*p == ','))
3148 p++;
cristybb503372010-05-27 20:51:26 +00003149 first=(size_t) strtol(p,&q,10);
cristyd965a422010-03-03 17:47:35 +00003150 last=first;
3151 while (isspace((int) ((unsigned char) *q)) != 0)
3152 q++;
3153 if (*q == '-')
cristybb503372010-05-27 20:51:26 +00003154 last=(size_t) strtol(q+1,&q,10);
cristyd965a422010-03-03 17:47:35 +00003155 if (first > last)
3156 Swap(first,last);
3157 if (first < image_info->scene)
3158 image_info->scene=first;
3159 if (last > image_info->number_scenes)
3160 image_info->number_scenes=last;
3161 p=q;
3162 }
3163 image_info->number_scenes-=image_info->scene-1;
3164 image_info->subimage=image_info->scene;
3165 image_info->subrange=image_info->number_scenes;
3166 }
cristy3ed852e2009-09-05 21:47:34 +00003167 }
3168 }
3169 *extension='\0';
3170 GetPathComponent(image_info->filename,ExtensionPath,extension);
3171#if defined(MAGICKCORE_ZLIB_DELEGATE)
3172 if (*extension != '\0')
3173 if ((LocaleCompare(extension,"gz") == 0) ||
3174 (LocaleCompare(extension,"Z") == 0) ||
3175 (LocaleCompare(extension,"wmz") == 0))
3176 {
3177 char
3178 path[MaxTextExtent];
3179
3180 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3181 path[strlen(path)-strlen(extension)-1]='\0';
3182 GetPathComponent(path,ExtensionPath,extension);
3183 }
3184#endif
3185#if defined(MAGICKCORE_BZLIB_DELEGATE)
3186 if (*extension != '\0')
3187 if (LocaleCompare(extension,"bz2") == 0)
3188 {
3189 char
3190 path[MaxTextExtent];
3191
3192 (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
3193 path[strlen(path)-strlen(extension)-1]='\0';
3194 GetPathComponent(path,ExtensionPath,extension);
3195 }
3196#endif
3197 image_info->affirm=MagickFalse;
3198 sans_exception=AcquireExceptionInfo();
3199 if (*extension != '\0')
3200 {
3201 MagickFormatType
3202 format_type;
3203
cristybb503372010-05-27 20:51:26 +00003204 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003205 i;
3206
3207 static const char
3208 *format_type_formats[] =
3209 {
3210 "AUTOTRACE",
3211 "BROWSE",
3212 "DCRAW",
3213 "EDIT",
3214 "EPHEMERAL",
3215 "LAUNCH",
3216 "MPEG:DECODE",
3217 "MPEG:ENCODE",
3218 "PRINT",
3219 "PS:ALPHA",
3220 "PS:CMYK",
3221 "PS:COLOR",
3222 "PS:GRAY",
3223 "PS:MONO",
3224 "SCAN",
3225 "SHOW",
3226 "WIN",
3227 (char *) NULL
3228 };
3229
3230 /*
3231 User specified image format.
3232 */
3233 (void) CopyMagickString(magic,extension,MaxTextExtent);
3234 LocaleUpper(magic);
3235 /*
3236 Look for explicit image formats.
3237 */
3238 format_type=UndefinedFormatType;
3239 i=0;
cristydd9a2532010-02-20 19:26:46 +00003240 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00003241 (format_type_formats[i] != (char *) NULL))
3242 {
3243 if ((*magic == *format_type_formats[i]) &&
3244 (LocaleCompare(magic,format_type_formats[i]) == 0))
3245 format_type=ExplicitFormatType;
3246 i++;
3247 }
3248 magick_info=GetMagickInfo(magic,sans_exception);
3249 if ((magick_info != (const MagickInfo *) NULL) &&
3250 (magick_info->format_type != UndefinedFormatType))
3251 format_type=magick_info->format_type;
3252 if (format_type == UndefinedFormatType)
3253 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3254 else
3255 if (format_type == ExplicitFormatType)
3256 {
3257 image_info->affirm=MagickTrue;
3258 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3259 }
3260 if (LocaleCompare(magic,"RGB") == 0)
3261 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
3262 }
3263 /*
3264 Look for explicit 'format:image' in filename.
3265 */
3266 *magic='\0';
3267 GetPathComponent(image_info->filename,MagickPath,magic);
3268 if (*magic == '\0')
3269 (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
3270 else
3271 {
3272 /*
3273 User specified image format.
3274 */
3275 LocaleUpper(magic);
3276 if (IsMagickConflict(magic) == MagickFalse)
3277 {
3278 (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
3279 if (LocaleCompare(magic,"EPHEMERAL") != 0)
3280 image_info->affirm=MagickTrue;
3281 else
3282 image_info->temporary=MagickTrue;
3283 }
3284 }
3285 magick_info=GetMagickInfo(magic,sans_exception);
3286 sans_exception=DestroyExceptionInfo(sans_exception);
3287 if ((magick_info == (const MagickInfo *) NULL) ||
3288 (GetMagickEndianSupport(magick_info) == MagickFalse))
3289 image_info->endian=UndefinedEndian;
3290 GetPathComponent(image_info->filename,CanonicalPath,filename);
3291 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristyd965a422010-03-03 17:47:35 +00003292 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00003293 {
3294 /*
cristyd965a422010-03-03 17:47:35 +00003295 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00003296 */
cristyd965a422010-03-03 17:47:35 +00003297 (void) InterpretImageFilename(image_info,(Image *) NULL,
3298 image_info->filename,(int) image_info->scene,filename);
3299 if ((LocaleCompare(filename,image_info->filename) != 0) &&
3300 (strchr(filename,'%') == (char *) NULL))
3301 image_info->adjoin=MagickFalse;
3302 }
3303 if ((image_info->adjoin != MagickFalse) && (frames > 0))
3304 {
3305 /*
3306 Some image formats do not support multiple frames per file.
3307 */
cristy3ed852e2009-09-05 21:47:34 +00003308 magick_info=GetMagickInfo(magic,exception);
3309 if (magick_info != (const MagickInfo *) NULL)
3310 if (GetMagickAdjoin(magick_info) == MagickFalse)
3311 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003312 }
3313 if (image_info->affirm != MagickFalse)
3314 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00003315 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
3317 /*
cristyd965a422010-03-03 17:47:35 +00003318 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00003319 */
cristyd965a422010-03-03 17:47:35 +00003320 image=AcquireImage(image_info);
3321 (void) CopyMagickString(image->filename,image_info->filename,
3322 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00003323 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3324 if (status == MagickFalse)
3325 {
3326 image=DestroyImage(image);
3327 return(MagickFalse);
3328 }
cristyd965a422010-03-03 17:47:35 +00003329 if ((IsBlobSeekable(image) == MagickFalse) ||
3330 (IsBlobExempt(image) != MagickFalse))
3331 {
3332 /*
3333 Copy standard input or pipe to temporary file.
3334 */
3335 *filename='\0';
3336 status=ImageToFile(image,filename,exception);
3337 (void) CloseBlob(image);
3338 if (status == MagickFalse)
3339 {
3340 image=DestroyImage(image);
3341 return(MagickFalse);
3342 }
3343 SetImageInfoFile(image_info,(FILE *) NULL);
3344 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
3345 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3346 if (status == MagickFalse)
3347 {
3348 image=DestroyImage(image);
3349 return(MagickFalse);
3350 }
3351 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
3352 image_info->temporary=MagickTrue;
3353 }
3354 (void) ResetMagickMemory(magick,0,sizeof(magick));
3355 count=ReadBlob(image,2*MaxTextExtent,magick);
3356 (void) CloseBlob(image);
3357 image=DestroyImage(image);
3358 /*
3359 Check magic.xml configuration file.
3360 */
3361 sans_exception=AcquireExceptionInfo();
3362 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3363 if ((magic_info != (const MagicInfo *) NULL) &&
3364 (GetMagicName(magic_info) != (char *) NULL))
3365 {
3366 (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
3367 MaxTextExtent);
3368 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3369 if ((magick_info == (const MagickInfo *) NULL) ||
3370 (GetMagickEndianSupport(magick_info) == MagickFalse))
3371 image_info->endian=UndefinedEndian;
3372 sans_exception=DestroyExceptionInfo(sans_exception);
3373 return(MagickTrue);
3374 }
cristy3ed852e2009-09-05 21:47:34 +00003375 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3376 if ((magick_info == (const MagickInfo *) NULL) ||
3377 (GetMagickEndianSupport(magick_info) == MagickFalse))
3378 image_info->endian=UndefinedEndian;
3379 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00003380 }
cristy3ed852e2009-09-05 21:47:34 +00003381 return(MagickTrue);
3382}
3383
3384/*
3385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3386% %
3387% %
3388% %
3389% S e t I m a g e I n f o B l o b %
3390% %
3391% %
3392% %
3393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3394%
3395% SetImageInfoBlob() sets the image info blob member.
3396%
3397% The format of the SetImageInfoBlob method is:
3398%
3399% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3400% const size_t length)
3401%
3402% A description of each parameter follows:
3403%
3404% o image_info: the image info.
3405%
3406% o blob: the blob.
3407%
3408% o length: the blob length.
3409%
3410*/
3411MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3412 const size_t length)
3413{
3414 assert(image_info != (ImageInfo *) NULL);
3415 assert(image_info->signature == MagickSignature);
3416 if (image_info->debug != MagickFalse)
3417 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3418 image_info->filename);
3419 image_info->blob=(void *) blob;
3420 image_info->length=length;
3421}
3422
3423/*
3424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3425% %
3426% %
3427% %
3428% S e t I m a g e I n f o F i l e %
3429% %
3430% %
3431% %
3432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3433%
3434% SetImageInfoFile() sets the image info file member.
3435%
3436% The format of the SetImageInfoFile method is:
3437%
3438% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3439%
3440% A description of each parameter follows:
3441%
3442% o image_info: the image info.
3443%
3444% o file: the file.
3445%
3446*/
3447MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3448{
3449 assert(image_info != (ImageInfo *) NULL);
3450 assert(image_info->signature == MagickSignature);
3451 if (image_info->debug != MagickFalse)
3452 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3453 image_info->filename);
3454 image_info->file=file;
3455}
3456
3457/*
3458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3459% %
3460% %
3461% %
3462% S e t I m a g e M a s k %
3463% %
3464% %
3465% %
3466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3467%
3468% SetImageMask() associates a mask with the image. The mask must be the same
3469% dimensions as the image.
3470%
3471% The format of the SetImageMask method is:
3472%
3473% MagickBooleanType SetImageMask(Image *image,const Image *mask)
3474%
3475% A description of each parameter follows:
3476%
3477% o image: the image.
3478%
3479% o mask: the image mask.
3480%
3481*/
3482MagickExport MagickBooleanType SetImageMask(Image *image,
3483 const Image *mask)
3484{
3485 assert(image != (Image *) NULL);
3486 if (image->debug != MagickFalse)
3487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3488 assert(image->signature == MagickSignature);
3489 if (mask != (const Image *) NULL)
3490 if ((mask->columns != image->columns) || (mask->rows != image->rows))
3491 ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
3492 if (image->mask != (Image *) NULL)
3493 image->mask=DestroyImage(image->mask);
3494 image->mask=NewImageList();
3495 if (mask == (Image *) NULL)
3496 return(MagickTrue);
3497 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3498 return(MagickFalse);
3499 image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
3500 if (image->mask == (Image *) NULL)
3501 return(MagickFalse);
3502 return(MagickTrue);
3503}
3504
3505/*
3506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507% %
3508% %
3509% %
3510% S e t I m a g e O p a c i t y %
3511% %
3512% %
3513% %
3514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3515%
3516% SetImageOpacity() sets the opacity levels of the image.
3517%
3518% The format of the SetImageOpacity method is:
3519%
3520% MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
3521%
3522% A description of each parameter follows:
3523%
3524% o image: the image.
3525%
3526% o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
3527% fully transparent.
3528%
3529*/
3530MagickExport MagickBooleanType SetImageOpacity(Image *image,
3531 const Quantum opacity)
3532{
3533 CacheView
3534 *image_view;
3535
3536 ExceptionInfo
3537 *exception;
3538
cristy3ed852e2009-09-05 21:47:34 +00003539 MagickBooleanType
3540 status;
3541
cristycb6d09b2010-06-19 01:59:36 +00003542 ssize_t
3543 y;
3544
cristy3ed852e2009-09-05 21:47:34 +00003545 assert(image != (Image *) NULL);
3546 if (image->debug != MagickFalse)
3547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3548 assert(image->signature == MagickSignature);
3549 image->matte=opacity != OpaqueOpacity ? MagickTrue : MagickFalse;
3550 status=MagickTrue;
3551 exception=(&image->exception);
3552 image_view=AcquireCacheView(image);
cristyb5d5f722009-11-04 03:03:49 +00003553#if defined(MAGICKCORE_OPENMP_SUPPORT)
3554 #pragma omp parallel for schedule(dynamic,4) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00003555#endif
cristybb503372010-05-27 20:51:26 +00003556 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003557 {
cristy3ed852e2009-09-05 21:47:34 +00003558 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003559 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003560
cristycb6d09b2010-06-19 01:59:36 +00003561 register ssize_t
3562 x;
3563
cristy3ed852e2009-09-05 21:47:34 +00003564 if (status == MagickFalse)
3565 continue;
3566 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3567 if (q == (PixelPacket *) NULL)
3568 {
3569 status=MagickFalse;
3570 continue;
3571 }
cristybb503372010-05-27 20:51:26 +00003572 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003573 {
cristy46f08202010-01-10 04:04:21 +00003574 SetOpacityPixelComponent(q,opacity);
cristy3ed852e2009-09-05 21:47:34 +00003575 q++;
3576 }
3577 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3578 status=MagickFalse;
3579 }
3580 image_view=DestroyCacheView(image_view);
3581 return(status);
3582}
3583
3584/*
3585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3586% %
3587% %
3588% %
3589% S e t I m a g e T y p e %
3590% %
3591% %
3592% %
3593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3594%
3595% SetImageType() sets the type of image. Choose from these types:
3596%
3597% Bilevel Grayscale GrayscaleMatte
3598% Palette PaletteMatte TrueColor
3599% TrueColorMatte ColorSeparation ColorSeparationMatte
3600% OptimizeType
3601%
3602% The format of the SetImageType method is:
3603%
3604% MagickBooleanType SetImageType(Image *image,const ImageType type)
3605%
3606% A description of each parameter follows:
3607%
3608% o image: the image.
3609%
3610% o type: Image type.
3611%
3612*/
3613MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
3614{
3615 const char
3616 *artifact;
3617
3618 ImageInfo
3619 *image_info;
3620
3621 MagickBooleanType
3622 status;
3623
3624 QuantizeInfo
3625 *quantize_info;
3626
3627 assert(image != (Image *) NULL);
3628 if (image->debug != MagickFalse)
3629 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3630 assert(image->signature == MagickSignature);
3631 status=MagickTrue;
3632 image_info=AcquireImageInfo();
3633 image_info->dither=image->dither;
3634 artifact=GetImageArtifact(image,"dither");
3635 if (artifact != (const char *) NULL)
3636 (void) SetImageOption(image_info,"dither",artifact);
3637 switch (type)
3638 {
3639 case BilevelType:
3640 {
3641 if (IsGrayImage(image,&image->exception) == MagickFalse)
3642 status=TransformImageColorspace(image,GRAYColorspace);
3643 if (IsMonochromeImage(image,&image->exception) == MagickFalse)
3644 {
3645 quantize_info=AcquireQuantizeInfo(image_info);
3646 quantize_info->number_colors=2;
3647 quantize_info->colorspace=GRAYColorspace;
3648 status=QuantizeImage(quantize_info,image);
3649 quantize_info=DestroyQuantizeInfo(quantize_info);
3650 }
3651 image->matte=MagickFalse;
3652 break;
3653 }
3654 case GrayscaleType:
3655 {
3656 if (IsGrayImage(image,&image->exception) == MagickFalse)
3657 status=TransformImageColorspace(image,GRAYColorspace);
3658 image->matte=MagickFalse;
3659 break;
3660 }
3661 case GrayscaleMatteType:
3662 {
3663 if (IsGrayImage(image,&image->exception) == MagickFalse)
3664 status=TransformImageColorspace(image,GRAYColorspace);
3665 if (image->matte == MagickFalse)
3666 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3667 break;
3668 }
3669 case PaletteType:
3670 {
3671 if (image->colorspace != RGBColorspace)
3672 status=TransformImageColorspace(image,RGBColorspace);
3673 if ((image->storage_class == DirectClass) || (image->colors > 256))
3674 {
3675 quantize_info=AcquireQuantizeInfo(image_info);
3676 quantize_info->number_colors=256;
3677 status=QuantizeImage(quantize_info,image);
3678 quantize_info=DestroyQuantizeInfo(quantize_info);
3679 }
3680 image->matte=MagickFalse;
3681 break;
3682 }
3683 case PaletteBilevelMatteType:
3684 {
3685 if (image->colorspace != RGBColorspace)
3686 status=TransformImageColorspace(image,RGBColorspace);
3687 if (image->matte == MagickFalse)
3688 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3689 (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
3690 quantize_info=AcquireQuantizeInfo(image_info);
3691 status=QuantizeImage(quantize_info,image);
3692 quantize_info=DestroyQuantizeInfo(quantize_info);
3693 break;
3694 }
3695 case PaletteMatteType:
3696 {
3697 if (image->colorspace != RGBColorspace)
3698 status=TransformImageColorspace(image,RGBColorspace);
3699 if (image->matte == MagickFalse)
3700 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3701 quantize_info=AcquireQuantizeInfo(image_info);
3702 quantize_info->colorspace=TransparentColorspace;
3703 status=QuantizeImage(quantize_info,image);
3704 quantize_info=DestroyQuantizeInfo(quantize_info);
3705 break;
3706 }
3707 case TrueColorType:
3708 {
3709 if (image->colorspace != RGBColorspace)
3710 status=TransformImageColorspace(image,RGBColorspace);
3711 if (image->storage_class != DirectClass)
3712 status=SetImageStorageClass(image,DirectClass);
3713 image->matte=MagickFalse;
3714 break;
3715 }
3716 case TrueColorMatteType:
3717 {
3718 if (image->colorspace != RGBColorspace)
3719 status=TransformImageColorspace(image,RGBColorspace);
3720 if (image->storage_class != DirectClass)
3721 status=SetImageStorageClass(image,DirectClass);
3722 if (image->matte == MagickFalse)
3723 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3724 break;
3725 }
3726 case ColorSeparationType:
3727 {
3728 if (image->colorspace != CMYKColorspace)
3729 {
3730 if (image->colorspace != RGBColorspace)
3731 status=TransformImageColorspace(image,RGBColorspace);
3732 status=TransformImageColorspace(image,CMYKColorspace);
3733 }
3734 if (image->storage_class != DirectClass)
3735 status=SetImageStorageClass(image,DirectClass);
3736 image->matte=MagickFalse;
3737 break;
3738 }
3739 case ColorSeparationMatteType:
3740 {
3741 if (image->colorspace != CMYKColorspace)
3742 {
3743 if (image->colorspace != RGBColorspace)
3744 status=TransformImageColorspace(image,RGBColorspace);
3745 status=TransformImageColorspace(image,CMYKColorspace);
3746 }
3747 if (image->storage_class != DirectClass)
3748 status=SetImageStorageClass(image,DirectClass);
3749 if (image->matte == MagickFalse)
3750 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
3751 break;
3752 }
3753 case OptimizeType:
cristy5f1c1ff2010-12-23 21:38:06 +00003754 case UndefinedType:
cristy3ed852e2009-09-05 21:47:34 +00003755 break;
3756 }
3757 image->type=type;
3758 image_info=DestroyImageInfo(image_info);
3759 return(status);
3760}
3761
3762/*
3763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764% %
3765% %
3766% %
3767% 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 %
3768% %
3769% %
3770% %
3771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772%
3773% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3774% image and returns the previous setting. A virtual pixel is any pixel access
3775% that is outside the boundaries of the image cache.
3776%
3777% The format of the SetImageVirtualPixelMethod() method is:
3778%
3779% VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3780% const VirtualPixelMethod virtual_pixel_method)
3781%
3782% A description of each parameter follows:
3783%
3784% o image: the image.
3785%
3786% o virtual_pixel_method: choose the type of virtual pixel.
3787%
3788*/
3789MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
3790 const VirtualPixelMethod virtual_pixel_method)
3791{
3792 assert(image != (const Image *) NULL);
3793 assert(image->signature == MagickSignature);
3794 if (image->debug != MagickFalse)
3795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3796 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
3797}
3798
3799/*
3800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3801% %
3802% %
3803% %
cristy4285d782011-02-09 20:12:28 +00003804% S m u s h I m a g e s %
3805% %
3806% %
3807% %
3808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3809%
3810% SmushImages() takes all images from the current image pointer to the end
3811% of the image list and smushes them to each other top-to-bottom if the
3812% stack parameter is true, otherwise left-to-right.
3813%
3814% The current gravity setting now effects how the image is justified in the
3815% final image.
3816%
3817% The format of the SmushImages method is:
3818%
cristy4ca38e22011-02-10 02:57:49 +00003819% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003820% ExceptionInfo *exception)
3821%
3822% A description of each parameter follows:
3823%
cristy4ca38e22011-02-10 02:57:49 +00003824% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003825%
3826% o stack: A value other than 0 stacks the images top-to-bottom.
3827%
3828% o offset: minimum distance in pixels between images.
3829%
3830% o exception: return any errors or warnings in this structure.
3831%
3832*/
cristy4ca38e22011-02-10 02:57:49 +00003833
cristy7c6dc152011-02-11 14:10:55 +00003834static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003835 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003836{
cristy4d727152011-02-10 19:57:21 +00003837 CacheView
3838 *left_view,
3839 *right_view;
3840
3841 const Image
3842 *left_image,
3843 *right_image;
3844
cristy4d727152011-02-10 19:57:21 +00003845 RectangleInfo
3846 left_geometry,
3847 right_geometry;
3848
cristydab7e912011-02-11 18:19:24 +00003849 register const PixelPacket
3850 *p;
3851
cristy4d727152011-02-10 19:57:21 +00003852 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003853 i,
cristy4d727152011-02-10 19:57:21 +00003854 y;
3855
cristy7c6dc152011-02-11 14:10:55 +00003856 size_t
3857 gap;
3858
cristy4d727152011-02-10 19:57:21 +00003859 ssize_t
cristy4d727152011-02-10 19:57:21 +00003860 x;
3861
3862 if (images->previous == (Image *) NULL)
3863 return(0);
3864 right_image=images;
3865 SetGeometry(smush_image,&right_geometry);
3866 GravityAdjustGeometry(right_image->columns,right_image->rows,
3867 right_image->gravity,&right_geometry);
3868 left_image=images->previous;
3869 SetGeometry(smush_image,&left_geometry);
3870 GravityAdjustGeometry(left_image->columns,left_image->rows,
3871 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003872 gap=right_image->columns;
cristy4d727152011-02-10 19:57:21 +00003873 left_view=AcquireCacheView(left_image);
3874 right_view=AcquireCacheView(right_image);
3875 for (y=0; y < (ssize_t) smush_image->rows; y++)
3876 {
3877 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3878 {
cristydab7e912011-02-11 18:19:24 +00003879 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3880 if ((p == (const PixelPacket *) NULL) ||
3881 (p->opacity != TransparentOpacity) ||
cristy7c6dc152011-02-11 14:10:55 +00003882 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003883 break;
3884 }
cristy4ef6f062011-02-10 20:30:22 +00003885 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003886 for (x=0; x < (ssize_t) right_image->columns; x++)
3887 {
cristydab7e912011-02-11 18:19:24 +00003888 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003889 exception);
cristydab7e912011-02-11 18:19:24 +00003890 if ((p == (const PixelPacket *) NULL) ||
3891 (p->opacity != TransparentOpacity) || ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003892 break;
3893 }
cristy7c6dc152011-02-11 14:10:55 +00003894 if ((x+i) < (ssize_t) gap)
3895 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003896 }
3897 right_view=DestroyCacheView(right_view);
3898 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003899 if (y < (ssize_t) smush_image->rows)
3900 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003901 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003902}
3903
cristy7c6dc152011-02-11 14:10:55 +00003904static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003905 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003906{
cristy4d727152011-02-10 19:57:21 +00003907 CacheView
3908 *bottom_view,
3909 *top_view;
3910
3911 const Image
3912 *bottom_image,
3913 *top_image;
3914
cristy4d727152011-02-10 19:57:21 +00003915 RectangleInfo
3916 bottom_geometry,
3917 top_geometry;
3918
cristydab7e912011-02-11 18:19:24 +00003919 register const PixelPacket
3920 *p;
3921
cristy4d727152011-02-10 19:57:21 +00003922 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003923 i,
cristy4d727152011-02-10 19:57:21 +00003924 x;
3925
cristy7c6dc152011-02-11 14:10:55 +00003926 size_t
3927 gap;
3928
cristy4d727152011-02-10 19:57:21 +00003929 ssize_t
cristy4d727152011-02-10 19:57:21 +00003930 y;
3931
3932 if (images->previous == (Image *) NULL)
3933 return(0);
3934 bottom_image=images;
3935 SetGeometry(smush_image,&bottom_geometry);
3936 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3937 bottom_image->gravity,&bottom_geometry);
3938 top_image=images->previous;
3939 SetGeometry(smush_image,&top_geometry);
3940 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3941 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003942 gap=bottom_image->rows;
cristy4d727152011-02-10 19:57:21 +00003943 top_view=AcquireCacheView(top_image);
3944 bottom_view=AcquireCacheView(bottom_image);
3945 for (x=0; x < (ssize_t) smush_image->columns; x++)
3946 {
3947 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3948 {
cristydab7e912011-02-11 18:19:24 +00003949 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3950 if ((p == (const PixelPacket *) NULL) ||
3951 (p->opacity != TransparentOpacity) || ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003952 break;
3953 }
cristy4ef6f062011-02-10 20:30:22 +00003954 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003955 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3956 {
cristydab7e912011-02-11 18:19:24 +00003957 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3958 exception);
3959 if ((p == (const PixelPacket *) NULL) ||
3960 (p->opacity != TransparentOpacity) || ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003961 break;
3962 }
cristy7c6dc152011-02-11 14:10:55 +00003963 if ((y+i) < (ssize_t) gap)
3964 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003965 }
3966 bottom_view=DestroyCacheView(bottom_view);
3967 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003968 if (x < (ssize_t) smush_image->columns)
3969 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003970 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003971}
3972
3973MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003974 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3975{
3976#define SmushImageTag "Smush/Image"
3977
3978 CacheView
cristybb5dced2011-02-10 02:17:16 +00003979 *smush_view;
cristy4285d782011-02-09 20:12:28 +00003980
cristy4ca38e22011-02-10 02:57:49 +00003981 const Image
3982 *image;
3983
cristy4285d782011-02-09 20:12:28 +00003984 Image
3985 *smush_image;
3986
3987 MagickBooleanType
3988 matte,
3989 proceed,
3990 status;
3991
3992 MagickOffsetType
3993 n;
3994
3995 RectangleInfo
3996 geometry;
3997
3998 register const Image
3999 *next;
4000
4001 size_t
4002 height,
4003 number_images,
4004 width;
4005
4006 ssize_t
4007 x_offset,
cristy4285d782011-02-09 20:12:28 +00004008 y_offset;
4009
4010 /*
cristy7c6dc152011-02-11 14:10:55 +00004011 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00004012 */
cristy4ca38e22011-02-10 02:57:49 +00004013 assert(images != (Image *) NULL);
4014 assert(images->signature == MagickSignature);
4015 if (images->debug != MagickFalse)
4016 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00004017 assert(exception != (ExceptionInfo *) NULL);
4018 assert(exception->signature == MagickSignature);
cristy4ca38e22011-02-10 02:57:49 +00004019 image=images;
cristy4285d782011-02-09 20:12:28 +00004020 matte=image->matte;
4021 number_images=1;
4022 width=image->columns;
4023 height=image->rows;
4024 next=GetNextImageInList(image);
4025 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4026 {
4027 if (next->matte != MagickFalse)
4028 matte=MagickTrue;
4029 number_images++;
4030 if (stack != MagickFalse)
4031 {
4032 if (next->columns > width)
4033 width=next->columns;
4034 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00004035 if (next->previous != (Image *) NULL)
4036 height+=offset;
cristy4285d782011-02-09 20:12:28 +00004037 continue;
4038 }
4039 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00004040 if (next->previous != (Image *) NULL)
4041 width+=offset;
cristy4285d782011-02-09 20:12:28 +00004042 if (next->rows > height)
4043 height=next->rows;
4044 }
4045 /*
cristy7c6dc152011-02-11 14:10:55 +00004046 Smush images.
cristy4285d782011-02-09 20:12:28 +00004047 */
4048 smush_image=CloneImage(image,width,height,MagickTrue,exception);
4049 if (smush_image == (Image *) NULL)
4050 return((Image *) NULL);
4051 if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
4052 {
4053 InheritException(exception,&smush_image->exception);
4054 smush_image=DestroyImage(smush_image);
4055 return((Image *) NULL);
4056 }
4057 smush_image->matte=matte;
4058 (void) SetImageBackgroundColor(smush_image);
4059 status=MagickTrue;
4060 x_offset=0;
4061 y_offset=0;
4062 smush_view=AcquireCacheView(smush_image);
4063 for (n=0; n < (MagickOffsetType) number_images; n++)
4064 {
4065 SetGeometry(smush_image,&geometry);
4066 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
4067 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00004068 {
4069 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00004070 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004071 }
cristy4285d782011-02-09 20:12:28 +00004072 else
cristy4ca38e22011-02-10 02:57:49 +00004073 {
cristy7c6dc152011-02-11 14:10:55 +00004074 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00004075 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00004076 }
cristybb5dced2011-02-10 02:17:16 +00004077 status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
cristy4285d782011-02-09 20:12:28 +00004078 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
4079 if (proceed == MagickFalse)
4080 break;
4081 if (stack == MagickFalse)
4082 {
4083 x_offset+=(ssize_t) image->columns;
4084 y_offset=0;
4085 }
4086 else
4087 {
4088 x_offset=0;
4089 y_offset+=(ssize_t) image->rows;
4090 }
4091 image=GetNextImageInList(image);
4092 }
cristy4ef6f062011-02-10 20:30:22 +00004093 if (stack == MagickFalse)
4094 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00004095 else
cristy4ef6f062011-02-10 20:30:22 +00004096 smush_image->rows=(size_t) y_offset;
4097 smush_view=DestroyCacheView(smush_view);
cristy4285d782011-02-09 20:12:28 +00004098 if (status == MagickFalse)
4099 smush_image=DestroyImage(smush_image);
4100 return(smush_image);
4101}
4102
4103/*
4104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4105% %
4106% %
4107% %
cristy3ed852e2009-09-05 21:47:34 +00004108% S t r i p I m a g e %
4109% %
4110% %
4111% %
4112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4113%
cristy376bda92009-12-22 21:15:23 +00004114% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00004115%
4116% The format of the StripImage method is:
4117%
4118% MagickBooleanType StripImage(Image *image)
4119%
4120% A description of each parameter follows:
4121%
4122% o image: the image.
4123%
4124*/
4125MagickExport MagickBooleanType StripImage(Image *image)
4126{
4127 assert(image != (Image *) NULL);
4128 if (image->debug != MagickFalse)
4129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4130 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00004131 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00004132 (void) DeleteImageProperty(image,"date:create");
4133 (void) DeleteImageProperty(image,"date:modify");
glennrpce91ed52010-12-23 22:37:49 +00004134 (void) SetImageArtifact(image,"png:include-chunk","none,gama");
cristy3ed852e2009-09-05 21:47:34 +00004135 return(MagickTrue);
4136}
4137
4138/*
4139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4140% %
4141% %
4142% %
4143+ S y n c I m a g e %
4144% %
4145% %
4146% %
4147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4148%
4149% SyncImage() initializes the red, green, and blue intensities of each pixel
4150% as defined by the colormap index.
4151%
4152% The format of the SyncImage method is:
4153%
4154% MagickBooleanType SyncImage(Image *image)
4155%
4156% A description of each parameter follows:
4157%
4158% o image: the image.
4159%
4160*/
4161
4162static inline IndexPacket PushColormapIndex(Image *image,
cristybb503372010-05-27 20:51:26 +00004163 const size_t index,MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00004164{
4165 if (index < image->colors)
4166 return((IndexPacket) index);
4167 *range_exception=MagickTrue;
4168 return((IndexPacket) 0);
4169}
4170
4171MagickExport MagickBooleanType SyncImage(Image *image)
4172{
4173 CacheView
4174 *image_view;
4175
4176 ExceptionInfo
4177 *exception;
4178
cristy3ed852e2009-09-05 21:47:34 +00004179 MagickBooleanType
4180 range_exception,
4181 status;
4182
cristycb6d09b2010-06-19 01:59:36 +00004183 ssize_t
4184 y;
4185
cristy3ed852e2009-09-05 21:47:34 +00004186 assert(image != (Image *) NULL);
4187 if (image->debug != MagickFalse)
4188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4189 assert(image->signature == MagickSignature);
4190 if (image->storage_class == DirectClass)
4191 return(MagickFalse);
4192 range_exception=MagickFalse;
4193 status=MagickTrue;
4194 exception=(&image->exception);
4195 image_view=AcquireCacheView(image);
cristy48974b92009-12-19 02:36:06 +00004196#if defined(MAGICKCORE_OPENMP_SUPPORT)
4197 #pragma omp parallel for schedule(dynamic,4) shared(status)
4198#endif
cristybb503372010-05-27 20:51:26 +00004199 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004200 {
4201 IndexPacket
4202 index;
4203
4204 PixelPacket
4205 pixel;
4206
4207 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004208 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00004209
cristy3ed852e2009-09-05 21:47:34 +00004210 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004211 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004212
cristycb6d09b2010-06-19 01:59:36 +00004213 register ssize_t
4214 x;
4215
cristy48974b92009-12-19 02:36:06 +00004216 if (status == MagickFalse)
4217 continue;
cristy3ed852e2009-09-05 21:47:34 +00004218 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4219 if (q == (PixelPacket *) NULL)
4220 {
4221 status=MagickFalse;
4222 continue;
4223 }
4224 indexes=GetCacheViewAuthenticIndexQueue(image_view);
cristybb503372010-05-27 20:51:26 +00004225 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00004226 {
cristybb503372010-05-27 20:51:26 +00004227 index=PushColormapIndex(image,(size_t) indexes[x],
cristy3ed852e2009-09-05 21:47:34 +00004228 &range_exception);
cristybb503372010-05-27 20:51:26 +00004229 pixel=image->colormap[(ssize_t) index];
cristy3ed852e2009-09-05 21:47:34 +00004230 q->red=pixel.red;
4231 q->green=pixel.green;
4232 q->blue=pixel.blue;
cristyd0272592010-04-21 01:01:49 +00004233 if (image->matte != MagickFalse)
4234 q->opacity=pixel.opacity;
cristy3ed852e2009-09-05 21:47:34 +00004235 q++;
4236 }
4237 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4238 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00004239 }
4240 image_view=DestroyCacheView(image_view);
4241 if (range_exception != MagickFalse)
4242 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4243 CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
4244 return(status);
4245}
cristy1626d332009-11-10 16:58:17 +00004246
4247/*
4248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249% %
4250% %
4251% %
4252% S y n c I m a g e S e t t i n g s %
4253% %
4254% %
4255% %
4256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4257%
4258% SyncImageSettings() sync the image info options to the image.
4259%
4260% The format of the SyncImageSettings method is:
4261%
4262% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4263% Image *image)
4264% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4265% Image *image)
4266%
4267% A description of each parameter follows:
4268%
4269% o image_info: the image info.
4270%
4271% o image: the image.
4272%
4273*/
4274
4275MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4276 Image *images)
4277{
4278 Image
4279 *image;
4280
4281 assert(image_info != (const ImageInfo *) NULL);
4282 assert(image_info->signature == MagickSignature);
4283 assert(images != (Image *) NULL);
4284 assert(images->signature == MagickSignature);
4285 if (images->debug != MagickFalse)
4286 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4287 image=images;
4288 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4289 (void) SyncImageSettings(image_info,image);
4290 (void) DeleteImageOption(image_info,"page");
4291 return(MagickTrue);
4292}
4293
4294MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4295 Image *image)
4296{
4297 char
4298 property[MaxTextExtent];
4299
4300 const char
cristy9a703812010-07-26 14:50:29 +00004301 *option,
4302 *value;
cristy1626d332009-11-10 16:58:17 +00004303
4304 GeometryInfo
4305 geometry_info;
4306
4307 MagickStatusType
4308 flags;
4309
cristy19eb6412010-04-23 14:42:29 +00004310 ResolutionType
4311 units;
4312
cristy1626d332009-11-10 16:58:17 +00004313 /*
4314 Sync image options.
4315 */
4316 assert(image_info != (const ImageInfo *) NULL);
4317 assert(image_info->signature == MagickSignature);
4318 assert(image != (Image *) NULL);
4319 assert(image->signature == MagickSignature);
4320 if (image->debug != MagickFalse)
4321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4322 option=GetImageOption(image_info,"background");
4323 if (option != (const char *) NULL)
4324 (void) QueryColorDatabase(option,&image->background_color,
4325 &image->exception);
4326 option=GetImageOption(image_info,"bias");
4327 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004328 image->bias=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004329 option=GetImageOption(image_info,"black-point-compensation");
4330 if (option != (const char *) NULL)
4331 image->black_point_compensation=(MagickBooleanType) ParseMagickOption(
4332 MagickBooleanOptions,MagickFalse,option);
4333 option=GetImageOption(image_info,"blue-primary");
4334 if (option != (const char *) NULL)
4335 {
4336 flags=ParseGeometry(option,&geometry_info);
4337 image->chromaticity.blue_primary.x=geometry_info.rho;
4338 image->chromaticity.blue_primary.y=geometry_info.sigma;
4339 if ((flags & SigmaValue) == 0)
4340 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4341 }
4342 option=GetImageOption(image_info,"bordercolor");
4343 if (option != (const char *) NULL)
4344 (void) QueryColorDatabase(option,&image->border_color,&image->exception);
4345 option=GetImageOption(image_info,"colors");
4346 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004347 image->colors=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004348 option=GetImageOption(image_info,"compose");
4349 if (option != (const char *) NULL)
4350 image->compose=(CompositeOperator) ParseMagickOption(MagickComposeOptions,
4351 MagickFalse,option);
4352 option=GetImageOption(image_info,"compress");
4353 if (option != (const char *) NULL)
4354 image->compression=(CompressionType) ParseMagickOption(
4355 MagickCompressOptions,MagickFalse,option);
4356 option=GetImageOption(image_info,"debug");
4357 if (option != (const char *) NULL)
4358 image->debug=(MagickBooleanType) ParseMagickOption(MagickBooleanOptions,
4359 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00004360 option=GetImageOption(image_info,"density");
4361 if (option != (const char *) NULL)
4362 {
4363 GeometryInfo
4364 geometry_info;
4365
4366 /*
4367 Set image density.
4368 */
4369 flags=ParseGeometry(option,&geometry_info);
4370 image->x_resolution=geometry_info.rho;
4371 image->y_resolution=geometry_info.sigma;
4372 if ((flags & SigmaValue) == 0)
4373 image->y_resolution=image->x_resolution;
4374 }
cristy1626d332009-11-10 16:58:17 +00004375 option=GetImageOption(image_info,"depth");
4376 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004377 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004378 option=GetImageOption(image_info,"endian");
4379 if (option != (const char *) NULL)
4380 image->endian=(EndianType) ParseMagickOption(MagickEndianOptions,
4381 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00004382 option=GetImageOption(image_info,"filter");
4383 if (option != (const char *) NULL)
4384 image->filter=(FilterTypes) ParseMagickOption(MagickFilterOptions,
4385 MagickFalse,option);
4386 option=GetImageOption(image_info,"fuzz");
4387 if (option != (const char *) NULL)
cristyf2f27272009-12-17 14:48:46 +00004388 image->fuzz=SiPrefixToDouble(option,QuantumRange);
cristy1626d332009-11-10 16:58:17 +00004389 option=GetImageOption(image_info,"gravity");
4390 if (option != (const char *) NULL)
4391 image->gravity=(GravityType) ParseMagickOption(MagickGravityOptions,
4392 MagickFalse,option);
4393 option=GetImageOption(image_info,"green-primary");
4394 if (option != (const char *) NULL)
4395 {
4396 flags=ParseGeometry(option,&geometry_info);
4397 image->chromaticity.green_primary.x=geometry_info.rho;
4398 image->chromaticity.green_primary.y=geometry_info.sigma;
4399 if ((flags & SigmaValue) == 0)
4400 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4401 }
4402 option=GetImageOption(image_info,"intent");
4403 if (option != (const char *) NULL)
4404 image->rendering_intent=(RenderingIntent) ParseMagickOption(
4405 MagickIntentOptions,MagickFalse,option);
4406 option=GetImageOption(image_info,"interlace");
4407 if (option != (const char *) NULL)
4408 image->interlace=(InterlaceType) ParseMagickOption(MagickInterlaceOptions,
4409 MagickFalse,option);
4410 option=GetImageOption(image_info,"interpolate");
4411 if (option != (const char *) NULL)
4412 image->interpolate=(InterpolatePixelMethod) ParseMagickOption(
4413 MagickInterpolateOptions,MagickFalse,option);
4414 option=GetImageOption(image_info,"loop");
4415 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004416 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004417 option=GetImageOption(image_info,"mattecolor");
4418 if (option != (const char *) NULL)
4419 (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
4420 option=GetImageOption(image_info,"orient");
4421 if (option != (const char *) NULL)
4422 image->orientation=(OrientationType) ParseMagickOption(
4423 MagickOrientationOptions,MagickFalse,option);
cristy9a703812010-07-26 14:50:29 +00004424 option=GetImageOption(image_info,"page");
4425 if (option != (const char *) NULL)
4426 {
4427 char
4428 *geometry;
4429
4430 geometry=GetPageGeometry(option);
4431 flags=ParseAbsoluteGeometry(geometry,&image->page);
4432 geometry=DestroyString(geometry);
4433 }
cristy1626d332009-11-10 16:58:17 +00004434 option=GetImageOption(image_info,"quality");
4435 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004436 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004437 option=GetImageOption(image_info,"red-primary");
4438 if (option != (const char *) NULL)
4439 {
4440 flags=ParseGeometry(option,&geometry_info);
4441 image->chromaticity.red_primary.x=geometry_info.rho;
4442 image->chromaticity.red_primary.y=geometry_info.sigma;
4443 if ((flags & SigmaValue) == 0)
4444 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4445 }
4446 if (image_info->quality != UndefinedCompressionQuality)
4447 image->quality=image_info->quality;
4448 option=GetImageOption(image_info,"scene");
4449 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00004450 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00004451 option=GetImageOption(image_info,"taint");
4452 if (option != (const char *) NULL)
4453 image->taint=(MagickBooleanType) ParseMagickOption(MagickBooleanOptions,
4454 MagickFalse,option);
4455 option=GetImageOption(image_info,"tile-offset");
4456 if (option != (const char *) NULL)
4457 {
4458 char
4459 *geometry;
4460
4461 geometry=GetPageGeometry(option);
4462 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4463 geometry=DestroyString(geometry);
4464 }
4465 option=GetImageOption(image_info,"transparent-color");
4466 if (option != (const char *) NULL)
4467 (void) QueryColorDatabase(option,&image->transparent_color,
4468 &image->exception);
4469 option=GetImageOption(image_info,"type");
4470 if (option != (const char *) NULL)
4471 image->type=(ImageType) ParseMagickOption(MagickTypeOptions,MagickFalse,
4472 option);
4473 option=GetImageOption(image_info,"units");
4474 if (option != (const char *) NULL)
cristy19eb6412010-04-23 14:42:29 +00004475 units=(ResolutionType) ParseMagickOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004476 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004477 else
4478 units = image_info->units;
4479 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004480 {
cristy19eb6412010-04-23 14:42:29 +00004481 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004482 switch (image->units)
4483 {
4484 case PixelsPerInchResolution:
4485 {
cristy19eb6412010-04-23 14:42:29 +00004486 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004487 {
4488 image->x_resolution/=2.54;
4489 image->y_resolution/=2.54;
4490 }
4491 break;
4492 }
4493 case PixelsPerCentimeterResolution:
4494 {
cristy19eb6412010-04-23 14:42:29 +00004495 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004496 {
cristybb503372010-05-27 20:51:26 +00004497 image->x_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004498 image->x_resolution+0.5))/100.0;
cristybb503372010-05-27 20:51:26 +00004499 image->y_resolution=(double) ((size_t) (100.0*2.54*
cristy1f9ce9f2010-04-28 11:55:12 +00004500 image->y_resolution+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004501 }
4502 break;
4503 }
4504 default:
4505 break;
4506 }
cristy19eb6412010-04-23 14:42:29 +00004507 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004508 }
4509 option=GetImageOption(image_info,"white-point");
4510 if (option != (const char *) NULL)
4511 {
4512 flags=ParseGeometry(option,&geometry_info);
4513 image->chromaticity.white_point.x=geometry_info.rho;
4514 image->chromaticity.white_point.y=geometry_info.sigma;
4515 if ((flags & SigmaValue) == 0)
4516 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4517 }
4518 ResetImageOptionIterator(image_info);
4519 for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
4520 {
4521 value=GetImageOption(image_info,option);
4522 if (value != (const char *) NULL)
4523 {
4524 (void) FormatMagickString(property,MaxTextExtent,"%s",option);
cristydf81b992011-02-27 14:33:24 +00004525 (void) SetImageArtifact(image,property,value);
cristy1626d332009-11-10 16:58:17 +00004526 }
4527 option=GetNextImageOption(image_info);
4528 }
4529 return(MagickTrue);
4530}