blob: a8e98f87086889b0095e994226f57ef3921f483c [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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/animate.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/attribute.h"
47#include "MagickCore/blob.h"
48#include "MagickCore/blob-private.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-private.h"
51#include "MagickCore/cache-view.h"
52#include "MagickCore/client.h"
53#include "MagickCore/color.h"
54#include "MagickCore/color-private.h"
55#include "MagickCore/colormap.h"
56#include "MagickCore/colorspace.h"
57#include "MagickCore/colorspace-private.h"
58#include "MagickCore/composite.h"
59#include "MagickCore/composite-private.h"
60#include "MagickCore/compress.h"
61#include "MagickCore/constitute.h"
Cristy446b7ac2016-06-06 09:18:22 -040062#include "MagickCore/delegate.h"
cristy4c08aed2011-07-01 19:47:50 +000063#include "MagickCore/display.h"
64#include "MagickCore/draw.h"
65#include "MagickCore/enhance.h"
66#include "MagickCore/exception.h"
67#include "MagickCore/exception-private.h"
68#include "MagickCore/gem.h"
69#include "MagickCore/geometry.h"
70#include "MagickCore/histogram.h"
71#include "MagickCore/image-private.h"
72#include "MagickCore/list.h"
73#include "MagickCore/magic.h"
74#include "MagickCore/magick.h"
cristy7832dc22011-09-05 01:21:53 +000075#include "MagickCore/magick-private.h"
cristy4c08aed2011-07-01 19:47:50 +000076#include "MagickCore/memory_.h"
77#include "MagickCore/module.h"
78#include "MagickCore/monitor.h"
79#include "MagickCore/monitor-private.h"
80#include "MagickCore/option.h"
81#include "MagickCore/paint.h"
82#include "MagickCore/pixel-accessor.h"
83#include "MagickCore/profile.h"
84#include "MagickCore/property.h"
85#include "MagickCore/quantize.h"
86#include "MagickCore/random_.h"
cristyac245f82012-05-05 17:13:57 +000087#include "MagickCore/resource_.h"
cristy4c08aed2011-07-01 19:47:50 +000088#include "MagickCore/segment.h"
89#include "MagickCore/semaphore.h"
90#include "MagickCore/signature-private.h"
91#include "MagickCore/statistic.h"
92#include "MagickCore/string_.h"
93#include "MagickCore/string-private.h"
94#include "MagickCore/thread-private.h"
95#include "MagickCore/threshold.h"
96#include "MagickCore/timer.h"
cristy63a81872012-03-22 15:52:52 +000097#include "MagickCore/token.h"
cristy4c08aed2011-07-01 19:47:50 +000098#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000099#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +0000100#include "MagickCore/version.h"
101#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +0000102
103/*
104 Constant declaration.
105*/
cristy94b11832011-09-08 19:46:03 +0000106const char
dirkb797b2c2016-02-01 22:20:32 +0100107 AlphaColor[] = "#bdbdbd", /* gray */
cristy7138c592009-09-08 13:58:52 +0000108 BackgroundColor[] = "#ffffff", /* white */
109 BorderColor[] = "#dfdfdf", /* gray */
cristy9639ba32011-09-05 15:09:42 +0000110 DefaultTileFrame[] = "15x15+3+3",
cristy7138c592009-09-08 13:58:52 +0000111 DefaultTileGeometry[] = "120x120+4+3>",
112 DefaultTileLabel[] = "%f\n%G\n%b",
cristy94b11832011-09-08 19:46:03 +0000113 ForegroundColor[] = "#000", /* black */
cristy7138c592009-09-08 13:58:52 +0000114 LoadImageTag[] = "Load/Image",
115 LoadImagesTag[] = "Load/Images",
cristy7138c592009-09-08 13:58:52 +0000116 PSDensityGeometry[] = "72.0x72.0",
117 PSPageGeometry[] = "612x792",
118 SaveImageTag[] = "Save/Image",
119 SaveImagesTag[] = "Save/Images",
120 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000121
cristy94b11832011-09-08 19:46:03 +0000122const double
cristy3ed852e2009-09-05 21:47:34 +0000123 DefaultResolution = 72.0;
124
125/*
126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127% %
128% %
129% %
130% A c q u i r e I m a g e %
131% %
132% %
133% %
134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135%
136% AcquireImage() returns a pointer to an image structure initialized to
137% default values.
138%
139% The format of the AcquireImage method is:
140%
cristy9950d572011-10-01 18:22:35 +0000141% Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000142%
143% A description of each parameter follows:
144%
145% o image_info: Many of the image default values are set from this
146% structure. For example, filename, compression, depth, background color,
147% and others.
148%
cristy9950d572011-10-01 18:22:35 +0000149% o exception: return any errors or warnings in this structure.
150%
cristy3ed852e2009-09-05 21:47:34 +0000151*/
cristy9950d572011-10-01 18:22:35 +0000152MagickExport Image *AcquireImage(const ImageInfo *image_info,
153 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000154{
cristye412c892010-07-26 12:31:36 +0000155 const char
cristyf3a660a2010-07-26 14:17:52 +0000156 *option;
cristye412c892010-07-26 12:31:36 +0000157
cristy3ed852e2009-09-05 21:47:34 +0000158 Image
159 *image;
160
161 MagickStatusType
162 flags;
163
164 /*
165 Allocate image structure.
166 */
167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy73bd4a52010-10-05 11:24:23 +0000168 image=(Image *) AcquireMagickMemory(sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000169 if (image == (Image *) NULL)
170 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
171 (void) ResetMagickMemory(image,0,sizeof(*image));
172 /*
173 Initialize Image structure.
174 */
cristy151b66d2015-04-15 10:50:31 +0000175 (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000176 image->storage_class=DirectClass;
177 image->depth=MAGICKCORE_QUANTUM_DEPTH;
cristy8d951092012-02-08 18:54:56 +0000178 image->colorspace=sRGBColorspace;
cristye540eb42012-04-16 12:50:34 +0000179 image->rendering_intent=PerceptualIntent;
cristy6b221892012-05-03 01:21:35 +0000180 image->gamma=1.000f/2.200f;
181 image->chromaticity.red_primary.x=0.6400f;
182 image->chromaticity.red_primary.y=0.3300f;
cristyf767ec92012-05-03 01:27:21 +0000183 image->chromaticity.red_primary.z=0.0300f;
cristy6b221892012-05-03 01:21:35 +0000184 image->chromaticity.green_primary.x=0.3000f;
185 image->chromaticity.green_primary.y=0.6000f;
cristyf767ec92012-05-03 01:27:21 +0000186 image->chromaticity.green_primary.z=0.1000f;
cristy6b221892012-05-03 01:21:35 +0000187 image->chromaticity.blue_primary.x=0.1500f;
188 image->chromaticity.blue_primary.y=0.0600f;
cristyf767ec92012-05-03 01:27:21 +0000189 image->chromaticity.blue_primary.z=0.7900f;
cristy6b221892012-05-03 01:21:35 +0000190 image->chromaticity.white_point.x=0.3127f;
191 image->chromaticity.white_point.y=0.3290f;
cristyf767ec92012-05-03 01:27:21 +0000192 image->chromaticity.white_point.z=0.3583f;
cristy3ed852e2009-09-05 21:47:34 +0000193 image->interlace=NoInterlace;
194 image->ticks_per_second=UndefinedTicksPerSecond;
195 image->compose=OverCompositeOp;
dirkb797b2c2016-02-01 22:20:32 +0100196 (void) QueryColorCompliance(AlphaColor,AllCompliance,&image->alpha_color,
197 exception);
cristy9950d572011-10-01 18:22:35 +0000198 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
199 &image->background_color,exception);
200 (void) QueryColorCompliance(BorderColor,AllCompliance,&image->border_color,
201 exception);
cristy9950d572011-10-01 18:22:35 +0000202 (void) QueryColorCompliance(TransparentColor,AllCompliance,
203 &image->transparent_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000204 GetTimerInfo(&image->timer);
205 image->cache=AcquirePixelCache(0);
cristybd5a96c2011-08-21 00:04:26 +0000206 image->channel_mask=DefaultChannels;
cristyed231572011-07-14 02:18:59 +0000207 image->channel_map=AcquirePixelChannelMap();
cristy3ed852e2009-09-05 21:47:34 +0000208 image->blob=CloneBlobInfo((BlobInfo *) NULL);
cristybd686c62013-02-03 19:01:05 +0000209 image->timestamp=time((time_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000210 image->debug=IsEventLogging();
211 image->reference_count=1;
cristy3d162a92014-02-16 14:05:06 +0000212 image->semaphore=AcquireSemaphoreInfo();
cristye1c94d92015-06-28 12:16:33 +0000213 image->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +0000214 if (image_info == (ImageInfo *) NULL)
215 return(image);
216 /*
217 Transfer image info.
218 */
219 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
220 MagickFalse);
cristyee2f5d62015-07-28 13:19:43 +0000221 (void) CopyMagickString(image->filename,image_info->filename,
222 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000223 (void) CopyMagickString(image->magick_filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +0000224 MagickPathExtent);
225 (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000226 if (image_info->size != (char *) NULL)
227 {
228 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
229 image->columns=image->extract_info.width;
230 image->rows=image->extract_info.height;
231 image->offset=image->extract_info.x;
232 image->extract_info.x=0;
233 image->extract_info.y=0;
234 }
235 if (image_info->extract != (char *) NULL)
236 {
237 RectangleInfo
238 geometry;
239
240 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
241 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
242 {
243 image->extract_info=geometry;
244 Swap(image->columns,image->extract_info.width);
245 Swap(image->rows,image->extract_info.height);
246 }
247 }
248 image->compression=image_info->compression;
249 image->quality=image_info->quality;
250 image->endian=image_info->endian;
251 image->interlace=image_info->interlace;
252 image->units=image_info->units;
253 if (image_info->density != (char *) NULL)
254 {
255 GeometryInfo
256 geometry_info;
257
258 flags=ParseGeometry(image_info->density,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000259 image->resolution.x=geometry_info.rho;
260 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000261 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000262 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000263 }
264 if (image_info->page != (char *) NULL)
265 {
266 char
267 *geometry;
268
269 image->page=image->extract_info;
270 geometry=GetPageGeometry(image_info->page);
271 (void) ParseAbsoluteGeometry(geometry,&image->page);
272 geometry=DestroyString(geometry);
273 }
274 if (image_info->depth != 0)
275 image->depth=image_info->depth;
276 image->dither=image_info->dither;
dirkb797b2c2016-02-01 22:20:32 +0100277 image->alpha_color=image_info->alpha_color;
cristy3ed852e2009-09-05 21:47:34 +0000278 image->background_color=image_info->background_color;
279 image->border_color=image_info->border_color;
cristy3ed852e2009-09-05 21:47:34 +0000280 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000281 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000282 image->progress_monitor=image_info->progress_monitor;
283 image->client_data=image_info->client_data;
284 if (image_info->cache != (void *) NULL)
285 ClonePixelCacheMethods(image->cache,image_info->cache);
cristy1a780952013-02-10 17:15:30 +0000286 /*
287 Set all global options that map to per-image settings.
288 */
cristy6fccee12011-10-20 18:43:18 +0000289 (void) SyncImageSettings(image_info,image,exception);
cristy1a780952013-02-10 17:15:30 +0000290 /*
291 Global options that are only set for new images.
292 */
cristye412c892010-07-26 12:31:36 +0000293 option=GetImageOption(image_info,"delay");
294 if (option != (const char *) NULL)
295 {
296 GeometryInfo
297 geometry_info;
298
299 flags=ParseGeometry(option,&geometry_info);
300 if ((flags & GreaterValue) != 0)
301 {
302 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
303 image->delay=(size_t) floor(geometry_info.rho+0.5);
304 }
305 else
306 if ((flags & LessValue) != 0)
307 {
308 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
309 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
310 }
311 else
312 image->delay=(size_t) floor(geometry_info.rho+0.5);
313 if ((flags & SigmaValue) != 0)
314 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
315 }
316 option=GetImageOption(image_info,"dispose");
317 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000318 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
cristye412c892010-07-26 12:31:36 +0000319 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000320 return(image);
321}
322
323/*
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325% %
326% %
327% %
cristy3ed852e2009-09-05 21:47:34 +0000328% A c q u i r e I m a g e I n f o %
329% %
330% %
331% %
332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333%
334% AcquireImageInfo() allocates the ImageInfo structure.
335%
336% The format of the AcquireImageInfo method is:
337%
338% ImageInfo *AcquireImageInfo(void)
339%
340*/
341MagickExport ImageInfo *AcquireImageInfo(void)
342{
343 ImageInfo
344 *image_info;
345
cristy73bd4a52010-10-05 11:24:23 +0000346 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000347 if (image_info == (ImageInfo *) NULL)
348 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
349 GetImageInfo(image_info);
350 return(image_info);
351}
352
353/*
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355% %
356% %
357% %
358% A c q u i r e N e x t I m a g e %
359% %
360% %
361% %
362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363%
364% AcquireNextImage() initializes the next image in a sequence to
365% default values. The next member of image points to the newly allocated
366% image. If there is a memory shortage, next is assigned NULL.
367%
368% The format of the AcquireNextImage method is:
369%
cristy9950d572011-10-01 18:22:35 +0000370% void AcquireNextImage(const ImageInfo *image_info,Image *image,
371% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000372%
373% A description of each parameter follows:
374%
375% o image_info: Many of the image default values are set from this
376% structure. For example, filename, compression, depth, background color,
377% and others.
378%
379% o image: the image.
380%
cristy9950d572011-10-01 18:22:35 +0000381% o exception: return any errors or warnings in this structure.
382%
cristy3ed852e2009-09-05 21:47:34 +0000383*/
cristy9950d572011-10-01 18:22:35 +0000384MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
385 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000386{
387 /*
388 Allocate image structure.
389 */
390 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000391 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000392 if (image->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy9950d572011-10-01 18:22:35 +0000394 image->next=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000395 if (GetNextImageInList(image) == (Image *) NULL)
396 return;
397 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
cristy151b66d2015-04-15 10:50:31 +0000398 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000399 if (image_info != (ImageInfo *) NULL)
400 (void) CopyMagickString(GetNextImageInList(image)->filename,
cristy151b66d2015-04-15 10:50:31 +0000401 image_info->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000402 DestroyBlob(GetNextImageInList(image));
403 image->next->blob=ReferenceBlob(image->blob);
404 image->next->endian=image->endian;
405 image->next->scene=image->scene+1;
406 image->next->previous=image;
407}
408
409/*
410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411% %
412% %
413% %
414% A p p e n d I m a g e s %
415% %
416% %
417% %
418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419%
420% AppendImages() takes all images from the current image pointer to the end
421% of the image list and appends them to each other top-to-bottom if the
422% stack parameter is true, otherwise left-to-right.
423%
anthony7bcfe7f2012-03-30 14:01:22 +0000424% The current gravity setting effects how the image is justified in the
cristy3ed852e2009-09-05 21:47:34 +0000425% final image.
426%
427% The format of the AppendImages method is:
428%
cristy4ca38e22011-02-10 02:57:49 +0000429% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000430% ExceptionInfo *exception)
431%
432% A description of each parameter follows:
433%
cristy4ca38e22011-02-10 02:57:49 +0000434% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000435%
436% o stack: A value other than 0 stacks the images top-to-bottom.
437%
438% o exception: return any errors or warnings in this structure.
439%
440*/
cristy4ca38e22011-02-10 02:57:49 +0000441MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000442 const MagickBooleanType stack,ExceptionInfo *exception)
443{
444#define AppendImageTag "Append/Image"
445
446 CacheView
cristyeeebdde2012-04-14 16:29:34 +0000447 *append_view;
cristy4ca38e22011-02-10 02:57:49 +0000448
cristy3ed852e2009-09-05 21:47:34 +0000449 Image
450 *append_image;
451
cristy3ed852e2009-09-05 21:47:34 +0000452 MagickBooleanType
cristy3ed852e2009-09-05 21:47:34 +0000453 status;
454
cristybb503372010-05-27 20:51:26 +0000455 MagickOffsetType
456 n;
457
cristy5a5e4d92012-08-29 00:06:25 +0000458 PixelTrait
459 alpha_trait;
460
cristy3ed852e2009-09-05 21:47:34 +0000461 RectangleInfo
462 geometry;
463
464 register const Image
465 *next;
466
cristybb503372010-05-27 20:51:26 +0000467 size_t
Cristya38b4562015-12-28 08:47:22 -0500468 depth,
cristy3ed852e2009-09-05 21:47:34 +0000469 height,
470 number_images,
471 width;
472
cristybb503372010-05-27 20:51:26 +0000473 ssize_t
474 x_offset,
475 y,
476 y_offset;
477
cristy3ed852e2009-09-05 21:47:34 +0000478 /*
cristy7c6dc152011-02-11 14:10:55 +0000479 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000480 */
cristy4ca38e22011-02-10 02:57:49 +0000481 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000482 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +0000483 if (images->debug != MagickFalse)
484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000485 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000486 assert(exception->signature == MagickCoreSignature);
cristy5a5e4d92012-08-29 00:06:25 +0000487 alpha_trait=images->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +0000488 number_images=1;
cristyeeebdde2012-04-14 16:29:34 +0000489 width=images->columns;
490 height=images->rows;
Cristya38b4562015-12-28 08:47:22 -0500491 depth=images->depth;
cristyeeebdde2012-04-14 16:29:34 +0000492 next=GetNextImageInList(images);
cristy3ed852e2009-09-05 21:47:34 +0000493 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
494 {
Cristya38b4562015-12-28 08:47:22 -0500495 if (next->depth > depth)
496 depth=next->depth;
cristy17f11b02014-12-20 19:37:04 +0000497 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +0000498 alpha_trait=BlendPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000499 number_images++;
500 if (stack != MagickFalse)
501 {
502 if (next->columns > width)
503 width=next->columns;
504 height+=next->rows;
505 continue;
506 }
507 width+=next->columns;
508 if (next->rows > height)
509 height=next->rows;
510 }
511 /*
cristy7c6dc152011-02-11 14:10:55 +0000512 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000513 */
cristyeeebdde2012-04-14 16:29:34 +0000514 append_image=CloneImage(images,width,height,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000515 if (append_image == (Image *) NULL)
516 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +0000517 if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000518 {
cristy3ed852e2009-09-05 21:47:34 +0000519 append_image=DestroyImage(append_image);
520 return((Image *) NULL);
521 }
Cristya38b4562015-12-28 08:47:22 -0500522 append_image->depth=depth;
cristy5a5e4d92012-08-29 00:06:25 +0000523 append_image->alpha_trait=alpha_trait;
cristyea1a8aa2011-10-20 13:24:06 +0000524 (void) SetImageBackgroundColor(append_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000525 status=MagickTrue;
526 x_offset=0;
527 y_offset=0;
cristyeeebdde2012-04-14 16:29:34 +0000528 next=images;
cristy46ff2672012-12-14 15:32:26 +0000529 append_view=AcquireAuthenticCacheView(append_image,exception);
cristybb503372010-05-27 20:51:26 +0000530 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000531 {
cristyeeebdde2012-04-14 16:29:34 +0000532 CacheView
533 *image_view;
534
cristy9eed59f2013-02-19 15:26:48 +0000535 MagickBooleanType
536 proceed;
537
cristy3ed852e2009-09-05 21:47:34 +0000538 SetGeometry(append_image,&geometry);
Cristyc1e19262016-02-05 07:54:16 -0500539 GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
cristy3ed852e2009-09-05 21:47:34 +0000540 if (stack != MagickFalse)
541 x_offset-=geometry.x;
542 else
543 y_offset-=geometry.y;
Cristyc1e19262016-02-05 07:54:16 -0500544 image_view=AcquireVirtualCacheView(next,exception);
cristyb5d5f722009-11-04 03:03:49 +0000545#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000546 #pragma omp parallel for schedule(static,4) shared(status) \
Cristyc1e19262016-02-05 07:54:16 -0500547 magick_threads(next,next,next->rows,1)
cristy3ed852e2009-09-05 21:47:34 +0000548#endif
Cristyc1e19262016-02-05 07:54:16 -0500549 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000550 {
551 MagickBooleanType
552 sync;
553
cristye14e3202012-04-11 18:48:17 +0000554 PixelInfo
555 pixel;
556
cristy4c08aed2011-07-01 19:47:50 +0000557 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +0100558 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000559
cristy4c08aed2011-07-01 19:47:50 +0000560 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100561 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000562
cristycb6d09b2010-06-19 01:59:36 +0000563 register ssize_t
564 x;
565
cristy3ed852e2009-09-05 21:47:34 +0000566 if (status == MagickFalse)
567 continue;
Cristyc1e19262016-02-05 07:54:16 -0500568 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000569 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
Cristyc1e19262016-02-05 07:54:16 -0500570 next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000571 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000572 {
573 status=MagickFalse;
574 continue;
575 }
Cristyc1e19262016-02-05 07:54:16 -0500576 GetPixelInfo(next,&pixel);
577 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000578 {
Cristyc1e19262016-02-05 07:54:16 -0500579 if (GetPixelReadMask(next,p) == 0)
cristy10a6c612012-01-29 21:41:05 +0000580 {
cristyc3a58022013-10-09 23:22:42 +0000581 SetPixelBackgoundColor(append_image,q);
Cristyc1e19262016-02-05 07:54:16 -0500582 p+=GetPixelChannels(next);
cristy10a6c612012-01-29 21:41:05 +0000583 q+=GetPixelChannels(append_image);
584 continue;
585 }
Cristyc1e19262016-02-05 07:54:16 -0500586 GetPixelInfoPixel(next,p,&pixel);
cristy11a06d32015-01-04 12:03:27 +0000587 SetPixelViaPixelInfo(append_image,&pixel,q);
Cristyc1e19262016-02-05 07:54:16 -0500588 p+=GetPixelChannels(next);
cristyed231572011-07-14 02:18:59 +0000589 q+=GetPixelChannels(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000590 }
591 sync=SyncCacheViewAuthenticPixels(append_view,exception);
592 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000593 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000594 }
595 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000596 if (stack == MagickFalse)
597 {
Cristyc1e19262016-02-05 07:54:16 -0500598 x_offset+=(ssize_t) next->columns;
cristy3ed852e2009-09-05 21:47:34 +0000599 y_offset=0;
600 }
601 else
602 {
603 x_offset=0;
Cristyc1e19262016-02-05 07:54:16 -0500604 y_offset+=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000605 }
cristyeeebdde2012-04-14 16:29:34 +0000606 proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
607 if (proceed == MagickFalse)
608 break;
609 next=GetNextImageInList(next);
cristy3ed852e2009-09-05 21:47:34 +0000610 }
611 append_view=DestroyCacheView(append_view);
612 if (status == MagickFalse)
613 append_image=DestroyImage(append_image);
614 return(append_image);
615}
616
617/*
618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619% %
620% %
621% %
cristy3ed852e2009-09-05 21:47:34 +0000622% C a t c h I m a g e E x c e p t i o n %
623% %
624% %
625% %
626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627%
628% CatchImageException() returns if no exceptions are found in the image
629% sequence, otherwise it determines the most severe exception and reports
630% it as a warning or error depending on the severity.
631%
632% The format of the CatchImageException method is:
633%
634% ExceptionType CatchImageException(Image *image)
635%
636% A description of each parameter follows:
637%
638% o image: An image sequence.
639%
640*/
641MagickExport ExceptionType CatchImageException(Image *image)
642{
643 ExceptionInfo
644 *exception;
645
646 ExceptionType
647 severity;
648
649 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000650 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000651 if (image->debug != MagickFalse)
652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
653 exception=AcquireExceptionInfo();
cristy3ed852e2009-09-05 21:47:34 +0000654 CatchException(exception);
655 severity=exception->severity;
656 exception=DestroyExceptionInfo(exception);
657 return(severity);
658}
659
660/*
661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662% %
663% %
664% %
665% C l i p I m a g e P a t h %
666% %
667% %
668% %
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670%
671% ClipImagePath() sets the image clip mask based any clipping path information
672% if it exists.
673%
674% The format of the ClipImagePath method is:
675%
676% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000677% const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000678%
679% A description of each parameter follows:
680%
681% o image: the image.
682%
683% o pathname: name of clipping path resource. If name is preceded by #, use
684% clipping path numbered by name.
685%
686% o inside: if non-zero, later operations take effect inside clipping path.
687% Otherwise later operations take effect outside clipping path.
688%
cristy018f07f2011-09-04 21:15:19 +0000689% o exception: return any errors or warnings in this structure.
690%
cristy3ed852e2009-09-05 21:47:34 +0000691*/
692
cristy018f07f2011-09-04 21:15:19 +0000693MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000694{
cristy018f07f2011-09-04 21:15:19 +0000695 return(ClipImagePath(image,"#1",MagickTrue,exception));
cristy3ed852e2009-09-05 21:47:34 +0000696}
697
698MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000699 const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000700{
701#define ClipImagePathTag "ClipPath/Image"
702
703 char
704 *property;
705
706 const char
707 *value;
708
709 Image
710 *clip_mask;
711
712 ImageInfo
713 *image_info;
714
715 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000716 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000717 if (image->debug != MagickFalse)
718 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
719 assert(pathname != NULL);
720 property=AcquireString(pathname);
cristy151b66d2015-04-15 10:50:31 +0000721 (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000722 pathname);
cristyd15e6592011-10-15 00:13:06 +0000723 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +0000724 property=DestroyString(property);
725 if (value == (const char *) NULL)
726 {
cristy6fccee12011-10-20 18:43:18 +0000727 ThrowFileException(exception,OptionError,"NoClipPathDefined",
cristy3ed852e2009-09-05 21:47:34 +0000728 image->filename);
729 return(MagickFalse);
730 }
731 image_info=AcquireImageInfo();
cristyee2f5d62015-07-28 13:19:43 +0000732 (void) CopyMagickString(image_info->filename,image->filename,
733 MagickPathExtent);
734 (void) ConcatenateMagickString(image_info->filename,pathname,
735 MagickPathExtent);
cristy6fccee12011-10-20 18:43:18 +0000736 clip_mask=BlobToImage(image_info,value,strlen(value),exception);
cristy3ed852e2009-09-05 21:47:34 +0000737 image_info=DestroyImageInfo(image_info);
738 if (clip_mask == (Image *) NULL)
739 return(MagickFalse);
740 if (clip_mask->storage_class == PseudoClass)
741 {
cristyea1a8aa2011-10-20 13:24:06 +0000742 (void) SyncImage(clip_mask,exception);
cristy6fccee12011-10-20 18:43:18 +0000743 if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000744 return(MagickFalse);
745 }
746 if (inside == MagickFalse)
cristy6fccee12011-10-20 18:43:18 +0000747 (void) NegateImage(clip_mask,MagickFalse,exception);
cristy151b66d2015-04-15 10:50:31 +0000748 (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000749 "8BIM:1999,2998:%s\nPS",pathname);
cristyacd0d4c2015-07-25 16:12:33 +0000750 (void) SetImageMask(image,ReadPixelMask,clip_mask,exception);
cristy3ed852e2009-09-05 21:47:34 +0000751 clip_mask=DestroyImage(clip_mask);
752 return(MagickTrue);
753}
754
755/*
756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757% %
758% %
759% %
760% C l o n e I m a g e %
761% %
762% %
763% %
764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765%
766% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000767%
cristy3ed852e2009-09-05 21:47:34 +0000768% If the specified columns and rows is 0, an exact copy of the image is
769% returned, otherwise the pixel data is undefined and must be initialized
770% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
771% failure, a NULL image is returned and exception describes the reason for the
772% failure.
773%
774% The format of the CloneImage method is:
775%
cristybb503372010-05-27 20:51:26 +0000776% Image *CloneImage(const Image *image,const size_t columns,
777% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000778% ExceptionInfo *exception)
779%
780% A description of each parameter follows:
781%
782% o image: the image.
783%
784% o columns: the number of columns in the cloned image.
785%
786% o rows: the number of rows in the cloned image.
787%
788% o detach: With a value other than 0, the cloned image is detached from
789% its parent I/O stream.
790%
791% o exception: return any errors or warnings in this structure.
792%
793*/
cristybb503372010-05-27 20:51:26 +0000794MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000795 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000796{
797 Image
798 *clone_image;
799
cristya19f1d72012-08-07 18:24:38 +0000800 double
cristy3ed852e2009-09-05 21:47:34 +0000801 scale;
802
803 size_t
804 length;
805
806 /*
807 Clone the image.
808 */
809 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000810 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000811 if (image->debug != MagickFalse)
812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
813 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000814 assert(exception->signature == MagickCoreSignature);
cristybe1cfca2014-10-21 14:00:29 +0000815 if ((image->columns == 0) || (image->rows == 0))
816 {
817 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
818 "NegativeOrZeroImageSize","`%s'",image->filename);
819 return((Image *) NULL);
820 }
cristy73bd4a52010-10-05 11:24:23 +0000821 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000822 if (clone_image == (Image *) NULL)
823 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
824 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
cristye1c94d92015-06-28 12:16:33 +0000825 clone_image->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +0000826 clone_image->storage_class=image->storage_class;
cristyed231572011-07-14 02:18:59 +0000827 clone_image->number_channels=image->number_channels;
cristyb3a73b52011-07-26 01:34:43 +0000828 clone_image->number_meta_channels=image->number_meta_channels;
cristy4c08aed2011-07-01 19:47:50 +0000829 clone_image->metacontent_extent=image->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +0000830 clone_image->colorspace=image->colorspace;
cristy883fde12013-04-08 00:50:13 +0000831 clone_image->read_mask=image->read_mask;
832 clone_image->write_mask=image->write_mask;
cristy8a46d822012-08-28 23:32:39 +0000833 clone_image->alpha_trait=image->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +0000834 clone_image->columns=image->columns;
835 clone_image->rows=image->rows;
836 clone_image->dither=image->dither;
cristy101ab702011-10-13 13:06:32 +0000837 if (image->colormap != (PixelInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
839 /*
840 Allocate and copy the image colormap.
841 */
842 clone_image->colors=image->colors;
843 length=(size_t) image->colors;
cristy101ab702011-10-13 13:06:32 +0000844 clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length,
cristy3ed852e2009-09-05 21:47:34 +0000845 sizeof(*clone_image->colormap));
cristy101ab702011-10-13 13:06:32 +0000846 if (clone_image->colormap == (PixelInfo *) NULL)
Cristyaecd0ad2016-05-16 16:05:02 -0400847 {
848 clone_image=DestroyImage(clone_image);
849 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
850 }
cristy3ed852e2009-09-05 21:47:34 +0000851 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
852 sizeof(*clone_image->colormap));
853 }
Cristy36421ee2015-08-28 11:58:20 -0400854 clone_image->image_info=CloneImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +0000855 (void) CloneImageProfiles(clone_image,image);
856 (void) CloneImageProperties(clone_image,image);
857 (void) CloneImageArtifacts(clone_image,image);
858 GetTimerInfo(&clone_image->timer);
cristy3ed852e2009-09-05 21:47:34 +0000859 if (image->ascii85 != (void *) NULL)
860 Ascii85Initialize(clone_image);
861 clone_image->magick_columns=image->magick_columns;
862 clone_image->magick_rows=image->magick_rows;
863 clone_image->type=image->type;
cristy636dcb52011-08-26 13:23:49 +0000864 clone_image->channel_mask=image->channel_mask;
cristyed231572011-07-14 02:18:59 +0000865 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +0000866 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
cristy151b66d2015-04-15 10:50:31 +0000867 MagickPathExtent);
868 (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
cristy25baba02015-07-28 00:36:29 +0000869 (void) CopyMagickString(clone_image->filename,image->filename,
870 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000871 clone_image->progress_monitor=image->progress_monitor;
872 clone_image->client_data=image->client_data;
873 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000874 clone_image->next=image->next;
875 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000876 clone_image->list=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +0000877 if (detach == MagickFalse)
878 clone_image->blob=ReferenceBlob(image->blob);
879 else
cristybee00932011-01-15 20:28:27 +0000880 {
881 clone_image->next=NewImageList();
882 clone_image->previous=NewImageList();
883 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
884 }
cristy73724512010-04-12 14:43:14 +0000885 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000886 clone_image->debug=IsEventLogging();
cristy3d162a92014-02-16 14:05:06 +0000887 clone_image->semaphore=AcquireSemaphoreInfo();
cristy58a749e2014-05-25 17:36:53 +0000888 if ((columns == 0) || (rows == 0))
cristy3ed852e2009-09-05 21:47:34 +0000889 {
890 if (image->montage != (char *) NULL)
891 (void) CloneString(&clone_image->montage,image->montage);
892 if (image->directory != (char *) NULL)
893 (void) CloneString(&clone_image->directory,image->directory);
cristy3ed852e2009-09-05 21:47:34 +0000894 clone_image->cache=ReferencePixelCache(image->cache);
895 return(clone_image);
896 }
cristy51d26762014-05-26 01:29:41 +0000897 scale=1.0;
898 if (image->columns != 0)
899 scale=(double) columns/(double) image->columns;
cristybb503372010-05-27 20:51:26 +0000900 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
901 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
902 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy51d26762014-05-26 01:29:41 +0000903 scale=1.0;
904 if (image->rows != 0)
cristyee2f5d62015-07-28 13:19:43 +0000905 scale=(double) rows/(double) image->rows;
cristybb503372010-05-27 20:51:26 +0000906 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
907 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
908 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000909 clone_image->cache=ClonePixelCache(image->cache);
Cristy5777d242016-06-16 16:58:13 -0400910 if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
911 clone_image=DestroyImage(clone_image);
cristy3ed852e2009-09-05 21:47:34 +0000912 return(clone_image);
913}
914
915/*
916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917% %
918% %
919% %
920% C l o n e I m a g e I n f o %
921% %
922% %
923% %
924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925%
926% CloneImageInfo() makes a copy of the given image info structure. If
927% NULL is specified, a new image info structure is created initialized to
928% default values.
929%
930% The format of the CloneImageInfo method is:
931%
932% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
933%
934% A description of each parameter follows:
935%
936% o image_info: the image info.
937%
938*/
939MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
940{
941 ImageInfo
942 *clone_info;
943
944 clone_info=AcquireImageInfo();
945 if (image_info == (ImageInfo *) NULL)
946 return(clone_info);
947 clone_info->compression=image_info->compression;
948 clone_info->temporary=image_info->temporary;
949 clone_info->adjoin=image_info->adjoin;
950 clone_info->antialias=image_info->antialias;
951 clone_info->scene=image_info->scene;
952 clone_info->number_scenes=image_info->number_scenes;
953 clone_info->depth=image_info->depth;
anthony72feaa62012-01-17 06:46:23 +0000954 (void) CloneString(&clone_info->size,image_info->size);
955 (void) CloneString(&clone_info->extract,image_info->extract);
956 (void) CloneString(&clone_info->scenes,image_info->scenes);
957 (void) CloneString(&clone_info->page,image_info->page);
cristy3ed852e2009-09-05 21:47:34 +0000958 clone_info->interlace=image_info->interlace;
959 clone_info->endian=image_info->endian;
960 clone_info->units=image_info->units;
961 clone_info->quality=image_info->quality;
anthony72feaa62012-01-17 06:46:23 +0000962 (void) CloneString(&clone_info->sampling_factor,image_info->sampling_factor);
963 (void) CloneString(&clone_info->server_name,image_info->server_name);
964 (void) CloneString(&clone_info->font,image_info->font);
965 (void) CloneString(&clone_info->texture,image_info->texture);
966 (void) CloneString(&clone_info->density,image_info->density);
cristy3ed852e2009-09-05 21:47:34 +0000967 clone_info->pointsize=image_info->pointsize;
968 clone_info->fuzz=image_info->fuzz;
dirkb797b2c2016-02-01 22:20:32 +0100969 clone_info->alpha_color=image_info->alpha_color;
cristy3ed852e2009-09-05 21:47:34 +0000970 clone_info->background_color=image_info->background_color;
971 clone_info->border_color=image_info->border_color;
cristy3ed852e2009-09-05 21:47:34 +0000972 clone_info->transparent_color=image_info->transparent_color;
973 clone_info->dither=image_info->dither;
974 clone_info->monochrome=image_info->monochrome;
cristy3ed852e2009-09-05 21:47:34 +0000975 clone_info->colorspace=image_info->colorspace;
976 clone_info->type=image_info->type;
977 clone_info->orientation=image_info->orientation;
cristy3ed852e2009-09-05 21:47:34 +0000978 clone_info->ping=image_info->ping;
979 clone_info->verbose=image_info->verbose;
cristy3ed852e2009-09-05 21:47:34 +0000980 clone_info->progress_monitor=image_info->progress_monitor;
981 clone_info->client_data=image_info->client_data;
982 clone_info->cache=image_info->cache;
983 if (image_info->cache != (void *) NULL)
984 clone_info->cache=ReferencePixelCache(image_info->cache);
985 if (image_info->profile != (void *) NULL)
986 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
987 image_info->profile);
988 SetImageInfoFile(clone_info,image_info->file);
989 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
990 clone_info->stream=image_info->stream;
cristy957f2612015-06-21 23:51:58 +0000991 (void) CopyMagickString(clone_info->magick,image_info->magick,
992 MagickPathExtent);
993 (void) CopyMagickString(clone_info->unique,image_info->unique,
994 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000995 (void) CopyMagickString(clone_info->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +0000996 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000997 clone_info->channel=image_info->channel;
anthony1afdc7a2011-10-05 11:54:28 +0000998 (void) CloneImageOptions(clone_info,image_info);
cristy3ed852e2009-09-05 21:47:34 +0000999 clone_info->debug=IsEventLogging();
1000 clone_info->signature=image_info->signature;
1001 return(clone_info);
1002}
1003
1004/*
1005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1006% %
1007% %
1008% %
cristy957f2612015-06-21 23:51:58 +00001009% C o p y I m a g e P i x e l s %
1010% %
1011% %
1012% %
1013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014%
1015% CopyImagePixels() copies pixels from the source image as defined by the
1016% geometry the destination image at the specified offset.
1017%
1018% The format of the CopyImagePixels method is:
1019%
1020% MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
cristy17fbd722015-06-22 00:46:58 +00001021% const RectangleInfo *geometry,const OffsetInfo *offset,
1022% ExceptionInfo *exception);
cristy957f2612015-06-21 23:51:58 +00001023%
1024% A description of each parameter follows:
1025%
1026% o image: the destination image.
1027%
1028% o source_image: the source image.
1029%
1030% o geometry: define the dimensions of the source pixel rectangle.
1031%
1032% o offset: define the offset in the destination image.
1033%
cristy17fbd722015-06-22 00:46:58 +00001034% o exception: return any errors or warnings in this structure.
1035%
cristy957f2612015-06-21 23:51:58 +00001036*/
1037MagickExport MagickBooleanType CopyImagePixels(Image *image,
1038 const Image *source_image,const RectangleInfo *geometry,
cristy17fbd722015-06-22 00:46:58 +00001039 const OffsetInfo *offset,ExceptionInfo *exception)
cristy957f2612015-06-21 23:51:58 +00001040{
cristy17fbd722015-06-22 00:46:58 +00001041#define CopyImageTag "Copy/Image"
1042
1043 CacheView
1044 *image_view,
1045 *source_view;
1046
1047 MagickBooleanType
1048 status;
1049
1050 MagickOffsetType
1051 progress;
1052
1053 ssize_t
1054 y;
1055
cristy957f2612015-06-21 23:51:58 +00001056 assert(image != (Image *) NULL);
1057 if (image->debug != MagickFalse)
1058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1059 assert(source_image != (Image *) NULL);
1060 assert(geometry != (RectangleInfo *) NULL);
1061 assert(offset != (OffsetInfo *) NULL);
cristy8c4c1c42015-06-22 23:51:22 +00001062 if ((offset->x < 0) || (offset->y < 0) ||
Cristy7d049b72015-09-26 20:50:55 -04001063 ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1064 ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
cristye742cae2015-06-22 19:40:29 +00001065 ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1066 image->filename);
cristy8c4c1c42015-06-22 23:51:22 +00001067 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1068 return(MagickFalse);
cristy17fbd722015-06-22 00:46:58 +00001069 /*
1070 Copy image pixels.
1071 */
1072 status=MagickTrue;
1073 progress=0;
1074 source_view=AcquireVirtualCacheView(source_image,exception);
1075 image_view=AcquireAuthenticCacheView(image,exception);
1076#if defined(MAGICKCORE_OPENMP_SUPPORT)
1077 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristye742cae2015-06-22 19:40:29 +00001078 magick_threads(image,source_image,geometry->height,1)
cristy17fbd722015-06-22 00:46:58 +00001079#endif
cristye742cae2015-06-22 19:40:29 +00001080 for (y=0; y < (ssize_t) geometry->height; y++)
cristy17fbd722015-06-22 00:46:58 +00001081 {
1082 MagickBooleanType
1083 sync;
1084
1085 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001086 *magick_restrict p;
cristy17fbd722015-06-22 00:46:58 +00001087
1088 register ssize_t
1089 x;
1090
1091 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001092 *magick_restrict q;
cristy17fbd722015-06-22 00:46:58 +00001093
1094 if (status == MagickFalse)
1095 continue;
cristye742cae2015-06-22 19:40:29 +00001096 p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1097 geometry->width,1,exception);
1098 q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1099 geometry->width,1,exception);
cristy17fbd722015-06-22 00:46:58 +00001100 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1101 {
1102 status=MagickFalse;
1103 continue;
1104 }
cristye742cae2015-06-22 19:40:29 +00001105 for (x=0; x < (ssize_t) geometry->width; x++)
cristy17fbd722015-06-22 00:46:58 +00001106 {
1107 register ssize_t
1108 i;
1109
1110 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
Cristy0093cff2016-06-05 19:00:17 -04001111 {
cristy17fbd722015-06-22 00:46:58 +00001112 PixelChannel channel=GetPixelChannelChannel(image,i);
1113 PixelTrait traits=GetPixelChannelTraits(image,channel);
1114 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1115 if ((traits == UndefinedPixelTrait) ||
dirk5a9b26e2016-07-23 13:05:55 +02001116 ((traits & UpdatePixelTrait) == 0) ||
cristy17fbd722015-06-22 00:46:58 +00001117 (source_traits == UndefinedPixelTrait))
1118 continue;
dirkd00a0022015-07-05 09:54:39 +00001119 SetPixelChannel(image,channel,p[i],q);
cristy17fbd722015-06-22 00:46:58 +00001120 }
dirkd00a0022015-07-05 09:54:39 +00001121 p+=GetPixelChannels(source_image);
1122 q+=GetPixelChannels(image);
cristy17fbd722015-06-22 00:46:58 +00001123 }
dirkd00a0022015-07-05 09:54:39 +00001124 sync=SyncCacheViewAuthenticPixels(image_view,exception);
cristy17fbd722015-06-22 00:46:58 +00001125 if (sync == MagickFalse)
1126 status=MagickFalse;
1127 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1128 {
1129 MagickBooleanType
1130 proceed;
1131
1132#if defined(MAGICKCORE_OPENMP_SUPPORT)
1133 #pragma omp critical (MagickCore_CopyImage)
1134#endif
1135 proceed=SetImageProgress(image,CopyImageTag,progress++,image->rows);
1136 if (proceed == MagickFalse)
1137 status=MagickFalse;
1138 }
1139 }
1140 source_view=DestroyCacheView(source_view);
1141 image_view=DestroyCacheView(image_view);
1142 return(status);
cristy957f2612015-06-21 23:51:58 +00001143}
1144
1145/*
1146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147% %
1148% %
1149% %
cristy3ed852e2009-09-05 21:47:34 +00001150% D e s t r o y I m a g e %
1151% %
1152% %
1153% %
1154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155%
1156% DestroyImage() dereferences an image, deallocating memory associated with
1157% the image if the reference count becomes zero.
1158%
1159% The format of the DestroyImage method is:
1160%
1161% Image *DestroyImage(Image *image)
1162%
1163% A description of each parameter follows:
1164%
1165% o image: the image.
1166%
1167*/
1168MagickExport Image *DestroyImage(Image *image)
1169{
1170 MagickBooleanType
1171 destroy;
1172
1173 /*
1174 Dereference image.
1175 */
1176 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001177 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001178 if (image->debug != MagickFalse)
1179 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1180 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001181 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001182 image->reference_count--;
1183 if (image->reference_count == 0)
1184 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001185 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001186 if (destroy == MagickFalse)
1187 return((Image *) NULL);
1188 /*
1189 Destroy image.
1190 */
1191 DestroyImagePixels(image);
cristyed231572011-07-14 02:18:59 +00001192 image->channel_map=DestroyPixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +00001193 if (image->montage != (char *) NULL)
1194 image->montage=DestroyString(image->montage);
1195 if (image->directory != (char *) NULL)
1196 image->directory=DestroyString(image->directory);
cristy101ab702011-10-13 13:06:32 +00001197 if (image->colormap != (PixelInfo *) NULL)
1198 image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
cristy3ed852e2009-09-05 21:47:34 +00001199 if (image->geometry != (char *) NULL)
1200 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001201 DestroyImageProfiles(image);
1202 DestroyImageProperties(image);
1203 DestroyImageArtifacts(image);
Cristy36421ee2015-08-28 11:58:20 -04001204 if (image->ascii85 != (Ascii85Info *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001205 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
Cristy36421ee2015-08-28 11:58:20 -04001206 if (image->image_info != (ImageInfo *) NULL)
1207 image->image_info=DestroyImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +00001208 DestroyBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001209 if (image->semaphore != (SemaphoreInfo *) NULL)
cristy3d162a92014-02-16 14:05:06 +00001210 RelinquishSemaphoreInfo(&image->semaphore);
cristye1c94d92015-06-28 12:16:33 +00001211 image->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001212 image=(Image *) RelinquishMagickMemory(image);
1213 return(image);
1214}
1215
1216/*
1217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218% %
1219% %
1220% %
1221% D e s t r o y I m a g e I n f o %
1222% %
1223% %
1224% %
1225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1226%
1227% DestroyImageInfo() deallocates memory associated with an ImageInfo
1228% structure.
1229%
1230% The format of the DestroyImageInfo method is:
1231%
1232% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1233%
1234% A description of each parameter follows:
1235%
1236% o image_info: the image info.
1237%
1238*/
1239MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1240{
1241 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001242 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001243 if (image_info->debug != MagickFalse)
1244 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1245 image_info->filename);
1246 if (image_info->size != (char *) NULL)
1247 image_info->size=DestroyString(image_info->size);
1248 if (image_info->extract != (char *) NULL)
1249 image_info->extract=DestroyString(image_info->extract);
1250 if (image_info->scenes != (char *) NULL)
1251 image_info->scenes=DestroyString(image_info->scenes);
1252 if (image_info->page != (char *) NULL)
1253 image_info->page=DestroyString(image_info->page);
1254 if (image_info->sampling_factor != (char *) NULL)
1255 image_info->sampling_factor=DestroyString(
1256 image_info->sampling_factor);
1257 if (image_info->server_name != (char *) NULL)
1258 image_info->server_name=DestroyString(
1259 image_info->server_name);
1260 if (image_info->font != (char *) NULL)
1261 image_info->font=DestroyString(image_info->font);
1262 if (image_info->texture != (char *) NULL)
1263 image_info->texture=DestroyString(image_info->texture);
1264 if (image_info->density != (char *) NULL)
1265 image_info->density=DestroyString(image_info->density);
cristy3ed852e2009-09-05 21:47:34 +00001266 if (image_info->cache != (void *) NULL)
1267 image_info->cache=DestroyPixelCache(image_info->cache);
1268 if (image_info->profile != (StringInfo *) NULL)
1269 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1270 image_info->profile);
anthony1afdc7a2011-10-05 11:54:28 +00001271 DestroyImageOptions(image_info);
cristye1c94d92015-06-28 12:16:33 +00001272 image_info->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001273 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1274 return(image_info);
1275}
1276
1277/*
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279% %
1280% %
1281% %
1282+ D i s a s s o c i a t e I m a g e S t r e a m %
1283% %
1284% %
1285% %
1286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287%
cristy4916cb42014-09-20 00:44:37 +00001288% DisassociateImageStream() disassociates the image stream. It checks if the
1289% blob of the specified image is referenced by other images. If the reference
1290% count is higher then 1 a new blob is assigned to the specified image.
cristy3ed852e2009-09-05 21:47:34 +00001291%
1292% The format of the DisassociateImageStream method is:
1293%
dirkcfe4c1c2014-09-20 07:38:59 +00001294% void DisassociateImageStream(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001295%
1296% A description of each parameter follows:
1297%
1298% o image: the image.
1299%
1300*/
1301MagickExport void DisassociateImageStream(Image *image)
1302{
cristy4916cb42014-09-20 00:44:37 +00001303 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001304 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001305 if (image->debug != MagickFalse)
1306 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy10f10ec2014-09-20 01:00:50 +00001307 DisassociateBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001308}
1309
1310/*
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312% %
1313% %
1314% %
cristy3ed852e2009-09-05 21:47:34 +00001315% G e t I m a g e I n f o %
1316% %
1317% %
1318% %
1319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320%
1321% GetImageInfo() initializes image_info to default values.
1322%
1323% The format of the GetImageInfo method is:
1324%
1325% void GetImageInfo(ImageInfo *image_info)
1326%
1327% A description of each parameter follows:
1328%
1329% o image_info: the image info.
1330%
1331*/
1332MagickExport void GetImageInfo(ImageInfo *image_info)
1333{
cristyfa0ea942012-12-21 02:42:29 +00001334 char
1335 *synchronize;
1336
cristy3ed852e2009-09-05 21:47:34 +00001337 ExceptionInfo
1338 *exception;
1339
1340 /*
1341 File and image dimension members.
1342 */
1343 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1344 assert(image_info != (ImageInfo *) NULL);
1345 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1346 image_info->adjoin=MagickTrue;
1347 image_info->interlace=NoInterlace;
1348 image_info->channel=DefaultChannels;
1349 image_info->quality=UndefinedCompressionQuality;
1350 image_info->antialias=MagickTrue;
1351 image_info->dither=MagickTrue;
cristyfa0ea942012-12-21 02:42:29 +00001352 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1353 if (synchronize != (const char *) NULL)
1354 {
1355 image_info->synchronize=IsStringTrue(synchronize);
1356 synchronize=DestroyString(synchronize);
1357 }
cristy3ed852e2009-09-05 21:47:34 +00001358 exception=AcquireExceptionInfo();
dirkb797b2c2016-02-01 22:20:32 +01001359 (void) QueryColorCompliance(AlphaColor,AllCompliance,&image_info->alpha_color,
1360 exception);
cristy9950d572011-10-01 18:22:35 +00001361 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1362 &image_info->background_color,exception);
1363 (void) QueryColorCompliance(BorderColor,AllCompliance,
1364 &image_info->border_color,exception);
cristy9950d572011-10-01 18:22:35 +00001365 (void) QueryColorCompliance(TransparentColor,AllCompliance,
1366 &image_info->transparent_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00001367 exception=DestroyExceptionInfo(exception);
1368 image_info->debug=IsEventLogging();
cristye1c94d92015-06-28 12:16:33 +00001369 image_info->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +00001370}
1371
1372/*
1373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374% %
1375% %
1376% %
cristy15781e52009-12-05 23:05:27 +00001377% G e t I m a g e I n f o F i l e %
1378% %
1379% %
1380% %
1381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382%
1383% GetImageInfoFile() returns the image info file member.
1384%
1385% The format of the GetImageInfoFile method is:
1386%
1387% FILE *GetImageInfoFile(const ImageInfo *image_info)
1388%
1389% A description of each parameter follows:
1390%
1391% o image_info: the image info.
1392%
1393*/
1394MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1395{
1396 return(image_info->file);
1397}
1398
1399/*
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401% %
1402% %
1403% %
cristy3ed852e2009-09-05 21:47:34 +00001404% G e t I m a g e M a s k %
1405% %
1406% %
1407% %
1408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409%
1410% GetImageMask() returns the mask associated with the image.
1411%
1412% The format of the GetImageMask method is:
1413%
dirkaf131f12016-01-10 01:29:22 +01001414% Image *GetImageMask(const Image *image,const PixelMask type,
1415% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001416%
1417% A description of each parameter follows:
1418%
1419% o image: the image.
1420%
dirkaf131f12016-01-10 01:29:22 +01001421% o type: the mask type, ReadPixelMask or WritePixelMask.
1422%
cristy3ed852e2009-09-05 21:47:34 +00001423*/
dirkaf131f12016-01-10 01:29:22 +01001424MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1425 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001426{
cristy10a6c612012-01-29 21:41:05 +00001427 CacheView
1428 *mask_view,
1429 *image_view;
1430
1431 Image
1432 *mask_image;
1433
1434 MagickBooleanType
1435 status;
1436
1437 ssize_t
1438 y;
1439
1440 /*
1441 Get image mask.
1442 */
1443 assert(image != (Image *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001444 if (image->debug != MagickFalse)
1445 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001446 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00001447 mask_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1448 if (mask_image == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001449 return((Image *) NULL);
cristy10a6c612012-01-29 21:41:05 +00001450 status=MagickTrue;
dirk4a26ef62015-11-19 21:47:29 +01001451 mask_image->alpha_trait=UndefinedPixelTrait;
dirkcd1d8792015-11-19 22:46:24 +01001452 (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
Cristy0596ce22015-11-20 21:11:22 -05001453 mask_image->read_mask=MagickFalse;
cristy46ff2672012-12-14 15:32:26 +00001454 image_view=AcquireVirtualCacheView(image,exception);
1455 mask_view=AcquireAuthenticCacheView(mask_image,exception);
cristy10a6c612012-01-29 21:41:05 +00001456 for (y=0; y < (ssize_t) image->rows; y++)
1457 {
1458 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001459 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00001460
1461 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001462 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00001463
1464 register ssize_t
1465 x;
1466
1467 if (status == MagickFalse)
1468 continue;
1469 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1470 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1471 exception);
1472 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1473 {
1474 status=MagickFalse;
1475 continue;
1476 }
1477 for (x=0; x < (ssize_t) image->columns; x++)
1478 {
dirkaf131f12016-01-10 01:29:22 +01001479 switch (type)
1480 {
1481 case WritePixelMask:
1482 {
1483 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1484 break;
1485 }
1486 default:
1487 {
1488 SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1489 break;
1490 }
1491 }
cristy10a6c612012-01-29 21:41:05 +00001492 p+=GetPixelChannels(image);
1493 q+=GetPixelChannels(mask_image);
1494 }
1495 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1496 status=MagickFalse;
1497 }
1498 mask_view=DestroyCacheView(mask_view);
1499 image_view=DestroyCacheView(image_view);
cristy1c2f48d2012-12-14 01:20:55 +00001500 if (status == MagickFalse)
1501 mask_image=DestroyImage(mask_image);
cristy10a6c612012-01-29 21:41:05 +00001502 return(mask_image);
cristy3ed852e2009-09-05 21:47:34 +00001503}
1504
1505/*
1506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507% %
1508% %
1509% %
1510+ G e t I m a g e R e f e r e n c e C o u n t %
1511% %
1512% %
1513% %
1514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1515%
1516% GetImageReferenceCount() returns the image reference count.
1517%
1518% The format of the GetReferenceCount method is:
1519%
cristybb503372010-05-27 20:51:26 +00001520% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001521%
1522% A description of each parameter follows:
1523%
1524% o image: the image.
1525%
1526*/
cristybb503372010-05-27 20:51:26 +00001527MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001528{
cristybb503372010-05-27 20:51:26 +00001529 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001530 reference_count;
1531
1532 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001533 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001534 if (image->debug != MagickFalse)
1535 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001536 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001537 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001538 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001539 return(reference_count);
1540}
1541
1542/*
1543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544% %
1545% %
1546% %
cristy3ed852e2009-09-05 21:47:34 +00001547% 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 %
1548% %
1549% %
1550% %
1551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552%
1553% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1554% image. A virtual pixel is any pixel access that is outside the boundaries
1555% of the image cache.
1556%
1557% The format of the GetImageVirtualPixelMethod() method is:
1558%
1559% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1560%
1561% A description of each parameter follows:
1562%
1563% o image: the image.
1564%
1565*/
1566MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1567{
1568 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001569 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001570 if (image->debug != MagickFalse)
1571 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1572 return(GetPixelCacheVirtualMethod(image));
1573}
1574
1575/*
1576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577% %
1578% %
1579% %
1580% I n t e r p r e t I m a g e F i l e n a m e %
1581% %
1582% %
1583% %
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585%
1586% InterpretImageFilename() interprets embedded characters in an image filename.
1587% The filename length is returned.
1588%
1589% The format of the InterpretImageFilename method is:
1590%
cristyee2b1232012-03-04 02:58:28 +00001591% size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1592% const char *format,int value,char *filename,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001593%
1594% A description of each parameter follows.
1595%
1596% o image_info: the image info..
1597%
1598% o image: the image.
1599%
1600% o format: A filename describing the format to use to write the numeric
1601% argument. Only the first numeric format identifier is replaced.
1602%
1603% o value: Numeric value to substitute into format filename.
1604%
1605% o filename: return the formatted filename in this character buffer.
1606%
cristy6fccee12011-10-20 18:43:18 +00001607% o exception: return any errors or warnings in this structure.
1608%
cristy3ed852e2009-09-05 21:47:34 +00001609*/
1610MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00001611 Image *image,const char *format,int value,char *filename,
1612 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001613{
1614 char
1615 *q;
1616
1617 int
1618 c;
1619
1620 MagickBooleanType
1621 canonical;
1622
1623 register const char
1624 *p;
1625
cristyad785752011-07-27 23:13:03 +00001626 size_t
1627 length;
1628
cristy3ed852e2009-09-05 21:47:34 +00001629 canonical=MagickFalse;
cristyc7b79fc2011-07-28 00:24:17 +00001630 length=0;
cristy151b66d2015-04-15 10:50:31 +00001631 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001632 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1633 {
1634 q=(char *) p+1;
1635 if (*q == '%')
1636 {
1637 p=q+1;
1638 continue;
1639 }
1640 if (*q == '0')
1641 {
cristybb503372010-05-27 20:51:26 +00001642 ssize_t
dirk86bacde2016-03-17 22:04:25 +01001643 foo;
cristy3ed852e2009-09-05 21:47:34 +00001644
dirk86bacde2016-03-17 22:04:25 +01001645 foo=(ssize_t) strtol(q,&q,10);
1646 (void) foo;
cristy3ed852e2009-09-05 21:47:34 +00001647 }
1648 switch (*q)
1649 {
1650 case 'd':
1651 case 'o':
1652 case 'x':
1653 {
1654 q++;
1655 c=(*q);
1656 *q='\0';
cristyee2f5d62015-07-28 13:19:43 +00001657 (void) FormatLocaleString(filename+(p-format),(size_t)
1658 (MagickPathExtent-(p-format)),p,value);
cristy3ed852e2009-09-05 21:47:34 +00001659 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001660 (void) ConcatenateMagickString(filename,q,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001661 canonical=MagickTrue;
1662 if (*(q-1) != '%')
1663 break;
1664 p++;
1665 break;
1666 }
1667 case '[':
1668 {
1669 char
cristy151b66d2015-04-15 10:50:31 +00001670 pattern[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001671
1672 const char
dirk86bacde2016-03-17 22:04:25 +01001673 *option;
cristy3ed852e2009-09-05 21:47:34 +00001674
cristy3ed852e2009-09-05 21:47:34 +00001675 register char
1676 *r;
1677
cristybb503372010-05-27 20:51:26 +00001678 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001679 i;
1680
cristycb6d09b2010-06-19 01:59:36 +00001681 ssize_t
1682 depth;
1683
cristy3ed852e2009-09-05 21:47:34 +00001684 /*
1685 Image option.
1686 */
anthony2cfa1a12012-05-12 05:18:07 +00001687 /* FUTURE: Compare update with code from InterpretImageProperties()
cristy97fc9f32012-06-13 21:04:44 +00001688 Note that a 'filename:' property should not need depth recursion.
anthony2cfa1a12012-05-12 05:18:07 +00001689 */
cristy3ed852e2009-09-05 21:47:34 +00001690 if (strchr(p,']') == (char *) NULL)
1691 break;
1692 depth=1;
1693 r=q+1;
cristy151b66d2015-04-15 10:50:31 +00001694 for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
cristy3ed852e2009-09-05 21:47:34 +00001695 {
1696 if (*r == '[')
1697 depth++;
1698 if (*r == ']')
1699 depth--;
1700 if (depth <= 0)
1701 break;
1702 pattern[i]=(*r++);
1703 }
1704 pattern[i]='\0';
1705 if (LocaleNCompare(pattern,"filename:",9) != 0)
1706 break;
dirk86bacde2016-03-17 22:04:25 +01001707 option=(const char *) NULL;
anthony06762232012-04-29 11:45:40 +00001708 if (image != (Image *) NULL)
dirk86bacde2016-03-17 22:04:25 +01001709 option=GetImageProperty(image,pattern,exception);
1710 if ((option == (const char *) NULL) && (image != (Image *) NULL))
1711 option=GetImageArtifact(image,pattern);
1712 if ((option == (const char *) NULL) &&
anthony06762232012-04-29 11:45:40 +00001713 (image_info != (ImageInfo *) NULL))
dirk86bacde2016-03-17 22:04:25 +01001714 option=GetImageOption(image_info,pattern);
1715 if (option == (const char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001716 break;
1717 q--;
1718 c=(*q);
1719 *q='\0';
dirk86bacde2016-03-17 22:04:25 +01001720 (void) CopyMagickString(filename+(p-format-length),option,(size_t)
cristy151b66d2015-04-15 10:50:31 +00001721 (MagickPathExtent-(p-format-length)));
cristyad785752011-07-27 23:13:03 +00001722 length+=strlen(pattern)-1;
cristy3ed852e2009-09-05 21:47:34 +00001723 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001724 (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001725 canonical=MagickTrue;
1726 if (*(q-1) != '%')
1727 break;
1728 p++;
1729 break;
1730 }
1731 default:
1732 break;
1733 }
1734 }
1735 for (q=filename; *q != '\0'; q++)
1736 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001737 {
cristy151b66d2015-04-15 10:50:31 +00001738 (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
cristy27bf23e2011-01-10 13:35:22 +00001739 canonical=MagickTrue;
1740 }
cristy3ed852e2009-09-05 21:47:34 +00001741 if (canonical == MagickFalse)
cristy151b66d2015-04-15 10:50:31 +00001742 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001743 return(strlen(filename));
1744}
1745
1746/*
1747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748% %
1749% %
1750% %
1751% I s H i g h D y n a m i c R a n g e I m a g e %
1752% %
1753% %
1754% %
1755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756%
1757% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1758% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1759% 0..65535.
1760%
1761% The format of the IsHighDynamicRangeImage method is:
1762%
1763% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1764% ExceptionInfo *exception)
1765%
1766% A description of each parameter follows:
1767%
1768% o image: the image.
1769%
1770% o exception: return any errors or warnings in this structure.
1771%
1772*/
1773MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1774 ExceptionInfo *exception)
1775{
1776#if !defined(MAGICKCORE_HDRI_SUPPORT)
1777 (void) image;
1778 (void) exception;
1779 return(MagickFalse);
1780#else
1781 CacheView
1782 *image_view;
1783
cristy3ed852e2009-09-05 21:47:34 +00001784 MagickBooleanType
1785 status;
1786
cristycb6d09b2010-06-19 01:59:36 +00001787 ssize_t
1788 y;
1789
cristy3ed852e2009-09-05 21:47:34 +00001790 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001791 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001792 if (image->debug != MagickFalse)
1793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1794 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00001795 image_view=AcquireVirtualCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00001796#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001797 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00001798 magick_threads(image,image,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001799#endif
cristybb503372010-05-27 20:51:26 +00001800 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001801 {
cristy4c08aed2011-07-01 19:47:50 +00001802 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001803 *p;
1804
cristybb503372010-05-27 20:51:26 +00001805 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001806 x;
1807
1808 if (status == MagickFalse)
1809 continue;
1810 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001811 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001812 {
1813 status=MagickFalse;
1814 continue;
1815 }
cristybb503372010-05-27 20:51:26 +00001816 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001817 {
cristya905c052011-09-17 22:37:55 +00001818 register ssize_t
1819 i;
1820
cristy883fde12013-04-08 00:50:13 +00001821 if (GetPixelReadMask(image,p) == 0)
cristy10a6c612012-01-29 21:41:05 +00001822 {
1823 p+=GetPixelChannels(image);
1824 continue;
1825 }
cristya905c052011-09-17 22:37:55 +00001826 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1827 {
cristya19f1d72012-08-07 18:24:38 +00001828 double
cristya905c052011-09-17 22:37:55 +00001829 pixel;
1830
cristyb0a657e2012-08-29 00:45:37 +00001831 PixelTrait
1832 traits;
1833
1834 traits=GetPixelChannelTraits(image,(PixelChannel) i);
cristya905c052011-09-17 22:37:55 +00001835 if (traits == UndefinedPixelTrait)
1836 continue;
cristya19f1d72012-08-07 18:24:38 +00001837 pixel=(double) p[i];
cristya905c052011-09-17 22:37:55 +00001838 if ((pixel < 0.0) || (pixel > QuantumRange) ||
cristy569b0e32013-08-15 16:07:35 +00001839 (pixel != (double) ((QuantumAny) pixel)))
cristya905c052011-09-17 22:37:55 +00001840 break;
1841 }
cristyed231572011-07-14 02:18:59 +00001842 p+=GetPixelChannels(image);
cristya905c052011-09-17 22:37:55 +00001843 if (i < (ssize_t) GetPixelChannels(image))
1844 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001845 }
cristybb503372010-05-27 20:51:26 +00001846 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001847 status=MagickFalse;
1848 }
1849 image_view=DestroyCacheView(image_view);
1850 return(status != MagickFalse ? MagickFalse : MagickTrue);
1851#endif
1852}
1853
1854/*
1855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856% %
1857% %
1858% %
1859% I s I m a g e O b j e c t %
1860% %
1861% %
1862% %
1863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864%
1865% IsImageObject() returns MagickTrue if the image sequence contains a valid
1866% set of image objects.
1867%
1868% The format of the IsImageObject method is:
1869%
1870% MagickBooleanType IsImageObject(const Image *image)
1871%
1872% A description of each parameter follows:
1873%
1874% o image: the image.
1875%
1876*/
1877MagickExport MagickBooleanType IsImageObject(const Image *image)
1878{
1879 register const Image
1880 *p;
1881
1882 assert(image != (Image *) NULL);
1883 if (image->debug != MagickFalse)
1884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1885 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
cristye1c94d92015-06-28 12:16:33 +00001886 if (p->signature != MagickCoreSignature)
cristy3ed852e2009-09-05 21:47:34 +00001887 return(MagickFalse);
1888 return(MagickTrue);
1889}
1890
1891/*
1892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1893% %
1894% %
1895% %
1896% I s T a i n t I m a g e %
1897% %
1898% %
1899% %
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901%
1902% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1903% since it was first constituted.
1904%
1905% The format of the IsTaintImage method is:
1906%
1907% MagickBooleanType IsTaintImage(const Image *image)
1908%
1909% A description of each parameter follows:
1910%
1911% o image: the image.
1912%
1913*/
1914MagickExport MagickBooleanType IsTaintImage(const Image *image)
1915{
1916 char
cristy151b66d2015-04-15 10:50:31 +00001917 magick[MagickPathExtent],
1918 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001919
1920 register const Image
1921 *p;
1922
1923 assert(image != (Image *) NULL);
1924 if (image->debug != MagickFalse)
1925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001926 assert(image->signature == MagickCoreSignature);
cristy151b66d2015-04-15 10:50:31 +00001927 (void) CopyMagickString(magick,image->magick,MagickPathExtent);
1928 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001929 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1930 {
1931 if (p->taint != MagickFalse)
1932 return(MagickTrue);
1933 if (LocaleCompare(p->magick,magick) != 0)
1934 return(MagickTrue);
1935 if (LocaleCompare(p->filename,filename) != 0)
1936 return(MagickTrue);
1937 }
1938 return(MagickFalse);
1939}
1940
1941/*
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943% %
1944% %
1945% %
1946% M o d i f y I m a g e %
1947% %
1948% %
1949% %
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951%
1952% ModifyImage() ensures that there is only a single reference to the image
1953% to be modified, updating the provided image pointer to point to a clone of
1954% the original image if necessary.
1955%
1956% The format of the ModifyImage method is:
1957%
1958% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
1959%
1960% A description of each parameter follows:
1961%
1962% o image: the image.
1963%
1964% o exception: return any errors or warnings in this structure.
1965%
1966*/
1967MagickExport MagickBooleanType ModifyImage(Image **image,
1968 ExceptionInfo *exception)
1969{
1970 Image
1971 *clone_image;
1972
1973 assert(image != (Image **) NULL);
1974 assert(*image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001975 assert((*image)->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001976 if ((*image)->debug != MagickFalse)
1977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1978 if (GetImageReferenceCount(*image) <= 1)
1979 return(MagickTrue);
1980 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00001981 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001982 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00001983 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001984 *image=clone_image;
1985 return(MagickTrue);
1986}
1987
1988/*
1989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1990% %
1991% %
1992% %
1993% N e w M a g i c k I m a g e %
1994% %
1995% %
1996% %
1997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1998%
1999% NewMagickImage() creates a blank image canvas of the specified size and
2000% background color.
2001%
2002% The format of the NewMagickImage method is:
2003%
cristy44410ab2014-05-25 20:39:43 +00002004% Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2005% const size_t height,const PixelInfo *background,
cristy0740a982011-10-13 15:01:01 +00002006% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002007%
2008% A description of each parameter follows:
2009%
2010% o image: the image.
2011%
2012% o width: the image width.
2013%
2014% o height: the image height.
2015%
2016% o background: the image color.
2017%
cristy0740a982011-10-13 15:01:01 +00002018% o exception: return any errors or warnings in this structure.
2019%
cristy3ed852e2009-09-05 21:47:34 +00002020*/
2021MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristy0740a982011-10-13 15:01:01 +00002022 const size_t width,const size_t height,const PixelInfo *background,
2023 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002024{
2025 CacheView
2026 *image_view;
2027
cristy3ed852e2009-09-05 21:47:34 +00002028 Image
2029 *image;
2030
cristy3ed852e2009-09-05 21:47:34 +00002031 MagickBooleanType
2032 status;
2033
cristya905c052011-09-17 22:37:55 +00002034 ssize_t
2035 y;
2036
cristy3ed852e2009-09-05 21:47:34 +00002037 assert(image_info != (const ImageInfo *) NULL);
2038 if (image_info->debug != MagickFalse)
2039 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002040 assert(image_info->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002041 assert(background != (const PixelInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00002042 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002043 image->columns=width;
2044 image->rows=height;
2045 image->colorspace=background->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002046 image->alpha_trait=background->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +00002047 image->fuzz=background->fuzz;
2048 image->depth=background->depth;
2049 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002050 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00002051#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002052 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002053 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00002054#endif
cristybb503372010-05-27 20:51:26 +00002055 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002056 {
cristy4c08aed2011-07-01 19:47:50 +00002057 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002058 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002059
cristycb6d09b2010-06-19 01:59:36 +00002060 register ssize_t
2061 x;
2062
cristy48974b92009-12-19 02:36:06 +00002063 if (status == MagickFalse)
2064 continue;
cristy3ed852e2009-09-05 21:47:34 +00002065 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002066 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002067 {
2068 status=MagickFalse;
2069 continue;
2070 }
cristybb503372010-05-27 20:51:26 +00002071 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002072 {
cristy11a06d32015-01-04 12:03:27 +00002073 SetPixelViaPixelInfo(image,background,q);
cristyed231572011-07-14 02:18:59 +00002074 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002075 }
2076 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2077 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002078 }
2079 image_view=DestroyCacheView(image_view);
2080 if (status == MagickFalse)
2081 image=DestroyImage(image);
2082 return(image);
2083}
2084
2085/*
2086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2087% %
2088% %
2089% %
2090% R e f e r e n c e I m a g e %
2091% %
2092% %
2093% %
2094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095%
2096% ReferenceImage() increments the reference count associated with an image
2097% returning a pointer to the image.
2098%
2099% The format of the ReferenceImage method is:
2100%
2101% Image *ReferenceImage(Image *image)
2102%
2103% A description of each parameter follows:
2104%
2105% o image: the image.
2106%
2107*/
2108MagickExport Image *ReferenceImage(Image *image)
2109{
2110 assert(image != (Image *) NULL);
2111 if (image->debug != MagickFalse)
2112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002113 assert(image->signature == MagickCoreSignature);
cristyf84a1932010-01-03 18:00:18 +00002114 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002115 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002116 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002117 return(image);
2118}
2119
2120/*
2121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122% %
2123% %
2124% %
2125% R e s e t I m a g e P a g e %
2126% %
2127% %
2128% %
2129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2130%
2131% ResetImagePage() resets the image page canvas and position.
2132%
2133% The format of the ResetImagePage method is:
2134%
2135% MagickBooleanType ResetImagePage(Image *image,const char *page)
2136%
2137% A description of each parameter follows:
2138%
2139% o image: the image.
2140%
2141% o page: the relative page specification.
2142%
2143*/
2144MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2145{
2146 MagickStatusType
2147 flags;
2148
2149 RectangleInfo
2150 geometry;
2151
2152 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002153 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002154 if (image->debug != MagickFalse)
2155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2156 flags=ParseAbsoluteGeometry(page,&geometry);
2157 if ((flags & WidthValue) != 0)
2158 {
2159 if ((flags & HeightValue) == 0)
2160 geometry.height=geometry.width;
2161 image->page.width=geometry.width;
2162 image->page.height=geometry.height;
2163 }
2164 if ((flags & AspectValue) != 0)
2165 {
2166 if ((flags & XValue) != 0)
2167 image->page.x+=geometry.x;
2168 if ((flags & YValue) != 0)
2169 image->page.y+=geometry.y;
2170 }
2171 else
2172 {
2173 if ((flags & XValue) != 0)
2174 {
2175 image->page.x=geometry.x;
2176 if ((image->page.width == 0) && (geometry.x > 0))
2177 image->page.width=image->columns+geometry.x;
2178 }
2179 if ((flags & YValue) != 0)
2180 {
2181 image->page.y=geometry.y;
2182 if ((image->page.height == 0) && (geometry.y > 0))
2183 image->page.height=image->rows+geometry.y;
2184 }
2185 }
2186 return(MagickTrue);
2187}
2188
2189/*
2190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2191% %
2192% %
2193% %
cristy3ed852e2009-09-05 21:47:34 +00002194% S e t I m a g e B a c k g r o u n d C o l o r %
2195% %
2196% %
2197% %
2198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199%
2200% SetImageBackgroundColor() initializes the image pixels to the image
2201% background color. The background color is defined by the background_color
2202% member of the image structure.
2203%
2204% The format of the SetImage method is:
2205%
cristyea1a8aa2011-10-20 13:24:06 +00002206% MagickBooleanType SetImageBackgroundColor(Image *image,
2207% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002208%
2209% A description of each parameter follows:
2210%
2211% o image: the image.
2212%
cristyea1a8aa2011-10-20 13:24:06 +00002213% o exception: return any errors or warnings in this structure.
2214%
cristy3ed852e2009-09-05 21:47:34 +00002215*/
cristyea1a8aa2011-10-20 13:24:06 +00002216MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2217 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002218{
2219 CacheView
2220 *image_view;
2221
cristy3ed852e2009-09-05 21:47:34 +00002222 MagickBooleanType
2223 status;
2224
dirkdc896c12014-10-15 16:28:15 +00002225 PixelInfo
2226 background;
2227
cristycb6d09b2010-06-19 01:59:36 +00002228 ssize_t
2229 y;
2230
cristy3ed852e2009-09-05 21:47:34 +00002231 assert(image != (Image *) NULL);
2232 if (image->debug != MagickFalse)
2233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002234 assert(image->signature == MagickCoreSignature);
cristy574cc262011-08-05 01:23:58 +00002235 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002236 return(MagickFalse);
dirkbfdd5bc2014-11-04 19:47:44 +00002237 ConformPixelInfo(image,&image->background_color,&background,exception);
cristy3ed852e2009-09-05 21:47:34 +00002238 /*
2239 Set image background color.
2240 */
2241 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002242 image_view=AcquireAuthenticCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +00002243 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002244 {
cristy4c08aed2011-07-01 19:47:50 +00002245 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002246 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002247
cristycb6d09b2010-06-19 01:59:36 +00002248 register ssize_t
2249 x;
2250
cristy3ed852e2009-09-05 21:47:34 +00002251 if (status == MagickFalse)
2252 continue;
2253 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002254 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002255 {
2256 status=MagickFalse;
2257 continue;
2258 }
cristybb503372010-05-27 20:51:26 +00002259 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002260 {
cristy11a06d32015-01-04 12:03:27 +00002261 SetPixelViaPixelInfo(image,&background,q);
cristyed231572011-07-14 02:18:59 +00002262 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002263 }
cristy3ed852e2009-09-05 21:47:34 +00002264 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2265 status=MagickFalse;
2266 }
2267 image_view=DestroyCacheView(image_view);
2268 return(status);
2269}
2270
2271/*
2272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273% %
2274% %
2275% %
cristycf1296e2012-08-26 23:40:49 +00002276% S e t I m a g e C h a n n e l M a s k %
2277% %
2278% %
2279% %
2280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281%
2282% SetImageChannelMask() sets the image channel mask from the specified channel
2283% mask.
2284%
2285% The format of the SetImageChannelMask method is:
2286%
2287% ChannelType SetImageChannelMask(Image *image,
2288% const ChannelType channel_mask)
2289%
2290% A description of each parameter follows:
2291%
2292% o image: the image.
2293%
2294% o channel_mask: the channel mask.
2295%
2296*/
2297MagickExport ChannelType SetImageChannelMask(Image *image,
2298 const ChannelType channel_mask)
2299{
cristybcd59342015-06-07 14:07:19 +00002300 return(SetPixelChannelMask(image,channel_mask));
cristycf1296e2012-08-26 23:40:49 +00002301}
2302
2303/*
2304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305% %
2306% %
2307% %
cristya5b77cb2010-05-07 19:34:48 +00002308% S e t I m a g e C o l o r %
2309% %
2310% %
2311% %
2312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313%
2314% SetImageColor() set the entire image canvas to the specified color.
2315%
2316% The format of the SetImageColor method is:
2317%
cristye941a752011-10-15 01:52:48 +00002318% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2319% ExeptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002320%
2321% A description of each parameter follows:
2322%
2323% o image: the image.
2324%
2325% o background: the image color.
2326%
cristye941a752011-10-15 01:52:48 +00002327% o exception: return any errors or warnings in this structure.
2328%
cristya5b77cb2010-05-07 19:34:48 +00002329*/
2330MagickExport MagickBooleanType SetImageColor(Image *image,
cristye941a752011-10-15 01:52:48 +00002331 const PixelInfo *color,ExceptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002332{
2333 CacheView
2334 *image_view;
2335
cristya5b77cb2010-05-07 19:34:48 +00002336 MagickBooleanType
2337 status;
2338
cristycb6d09b2010-06-19 01:59:36 +00002339 ssize_t
2340 y;
2341
cristya5b77cb2010-05-07 19:34:48 +00002342 assert(image != (Image *) NULL);
2343 if (image->debug != MagickFalse)
2344 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002345 assert(image->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002346 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002347 image->colorspace=color->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002348 image->alpha_trait=color->alpha_trait;
cristya5b77cb2010-05-07 19:34:48 +00002349 image->fuzz=color->fuzz;
2350 image->depth=color->depth;
2351 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002352 image_view=AcquireAuthenticCacheView(image,exception);
cristya5b77cb2010-05-07 19:34:48 +00002353#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002354 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002355 magick_threads(image,image,image->rows,1)
cristya5b77cb2010-05-07 19:34:48 +00002356#endif
cristybb503372010-05-27 20:51:26 +00002357 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002358 {
cristy4c08aed2011-07-01 19:47:50 +00002359 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002360 *magick_restrict q;
cristya5b77cb2010-05-07 19:34:48 +00002361
cristycb6d09b2010-06-19 01:59:36 +00002362 register ssize_t
2363 x;
2364
cristya5b77cb2010-05-07 19:34:48 +00002365 if (status == MagickFalse)
2366 continue;
2367 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002368 if (q == (Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002369 {
2370 status=MagickFalse;
2371 continue;
2372 }
cristybb503372010-05-27 20:51:26 +00002373 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002374 {
cristy11a06d32015-01-04 12:03:27 +00002375 SetPixelViaPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002376 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002377 }
2378 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2379 status=MagickFalse;
2380 }
2381 image_view=DestroyCacheView(image_view);
2382 return(status);
2383}
2384
2385/*
2386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2387% %
2388% %
2389% %
cristy3ed852e2009-09-05 21:47:34 +00002390% S e t I m a g e S t o r a g e C l a s s %
2391% %
2392% %
2393% %
2394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395%
2396% SetImageStorageClass() sets the image class: DirectClass for true color
2397% images or PseudoClass for colormapped images.
2398%
2399% The format of the SetImageStorageClass method is:
2400%
2401% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002402% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002403%
2404% A description of each parameter follows:
2405%
2406% o image: the image.
2407%
2408% o storage_class: The image class.
2409%
cristy574cc262011-08-05 01:23:58 +00002410% o exception: return any errors or warnings in this structure.
2411%
cristy3ed852e2009-09-05 21:47:34 +00002412*/
2413MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002414 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002415{
cristy3ed852e2009-09-05 21:47:34 +00002416 image->storage_class=storage_class;
cristy6e437132011-08-12 13:02:19 +00002417 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002418}
2419
2420/*
2421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422% %
2423% %
2424% %
cristy3ed852e2009-09-05 21:47:34 +00002425% S e t I m a g e E x t e n t %
2426% %
2427% %
2428% %
2429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2430%
2431% SetImageExtent() sets the image size (i.e. columns & rows).
2432%
2433% The format of the SetImageExtent method is:
2434%
cristy08429172011-07-14 17:18:16 +00002435% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002436% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002437%
2438% A description of each parameter follows:
2439%
2440% o image: the image.
2441%
2442% o columns: The image width in pixels.
2443%
2444% o rows: The image height in pixels.
2445%
cristy63240882011-08-05 19:05:27 +00002446% o exception: return any errors or warnings in this structure.
2447%
cristy3ed852e2009-09-05 21:47:34 +00002448*/
cristy08429172011-07-14 17:18:16 +00002449MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002450 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002451{
cristy537e2722010-09-21 15:30:59 +00002452 if ((columns == 0) || (rows == 0))
Cristy852231d2016-06-24 07:18:31 -04002453 ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
cristy537e2722010-09-21 15:30:59 +00002454 image->columns=columns;
2455 image->rows=rows;
cristyda950bb2015-07-18 23:17:28 +00002456 if (image->depth > (8*sizeof(MagickSizeType)))
2457 ThrowBinaryException(ImageError,"ImageDepthNotSupported",image->filename);
cristy6e437132011-08-12 13:02:19 +00002458 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002459}
2460
2461/*
2462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463% %
2464% %
2465% %
2466+ S e t I m a g e I n f o %
2467% %
2468% %
2469% %
2470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471%
anthonye5b39652012-04-21 05:37:29 +00002472% SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
cristy3ed852e2009-09-05 21:47:34 +00002473% It is set to a type of image format based on the prefix or suffix of the
anthonye5b39652012-04-21 05:37:29 +00002474% filename. For example, 'ps:image' returns PS indicating a Postscript image.
2475% JPEG is returned for this filename: 'image.jpg'. The filename prefix has
cristy3ed852e2009-09-05 21:47:34 +00002476% precendence over the suffix. Use an optional index enclosed in brackets
2477% after a file name to specify a desired scene of a multi-resolution image
2478% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2479% indicates success.
2480%
2481% The format of the SetImageInfo method is:
2482%
2483% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002484% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002485%
2486% A description of each parameter follows:
2487%
cristyd965a422010-03-03 17:47:35 +00002488% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002489%
cristyd965a422010-03-03 17:47:35 +00002490% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002491%
2492% o exception: return any errors or warnings in this structure.
2493%
2494*/
2495MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002496 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002497{
2498 char
dirk8f681612015-04-16 21:05:08 +00002499 component[MagickPathExtent],
cristy151b66d2015-04-15 10:50:31 +00002500 magic[MagickPathExtent],
dirk8f681612015-04-16 21:05:08 +00002501 *q;
cristy3ed852e2009-09-05 21:47:34 +00002502
2503 const MagicInfo
2504 *magic_info;
2505
2506 const MagickInfo
2507 *magick_info;
2508
2509 ExceptionInfo
2510 *sans_exception;
2511
2512 Image
2513 *image;
2514
2515 MagickBooleanType
2516 status;
2517
2518 register const char
2519 *p;
2520
2521 ssize_t
2522 count;
2523
cristy3ed852e2009-09-05 21:47:34 +00002524 /*
2525 Look for 'image.format' in filename.
2526 */
2527 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002528 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002529 if (image_info->debug != MagickFalse)
2530 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2531 image_info->filename);
dirk8f681612015-04-16 21:05:08 +00002532 *component='\0';
2533 GetPathComponent(image_info->filename,SubimagePath,component);
2534 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002535 {
cristy4f96a1d2014-01-04 15:31:36 +00002536 /*
2537 Look for scene specification (e.g. img0001.pcd[4]).
2538 */
dirk8f681612015-04-16 21:05:08 +00002539 if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002540 {
dirk8f681612015-04-16 21:05:08 +00002541 if (IsGeometry(component) != MagickFalse)
2542 (void) CloneString(&image_info->extract,component);
cristy4f96a1d2014-01-04 15:31:36 +00002543 }
2544 else
2545 {
2546 size_t
2547 first,
2548 last;
cristy3ed852e2009-09-05 21:47:34 +00002549
dirk8f681612015-04-16 21:05:08 +00002550 (void) CloneString(&image_info->scenes,component);
cristy4f96a1d2014-01-04 15:31:36 +00002551 image_info->scene=StringToUnsignedLong(image_info->scenes);
2552 image_info->number_scenes=image_info->scene;
2553 p=image_info->scenes;
2554 for (q=(char *) image_info->scenes; *q != '\0'; p++)
2555 {
2556 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2557 p++;
2558 first=(size_t) strtol(p,&q,10);
2559 last=first;
2560 while (isspace((int) ((unsigned char) *q)) != 0)
2561 q++;
2562 if (*q == '-')
2563 last=(size_t) strtol(q+1,&q,10);
2564 if (first > last)
2565 Swap(first,last);
2566 if (first < image_info->scene)
2567 image_info->scene=first;
2568 if (last > image_info->number_scenes)
2569 image_info->number_scenes=last;
2570 p=q;
2571 }
2572 image_info->number_scenes-=image_info->scene-1;
cristy3ed852e2009-09-05 21:47:34 +00002573 }
2574 }
dirk8f681612015-04-16 21:05:08 +00002575 *component='\0';
cristy6f7cebf2014-12-27 12:10:39 +00002576 if (*image_info->magick == '\0')
dirk8f681612015-04-16 21:05:08 +00002577 GetPathComponent(image_info->filename,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002578#if defined(MAGICKCORE_ZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002579 if (*component != '\0')
2580 if ((LocaleCompare(component,"gz") == 0) ||
2581 (LocaleCompare(component,"Z") == 0) ||
2582 (LocaleCompare(component,"svgz") == 0) ||
2583 (LocaleCompare(component,"wmz") == 0))
cristy3ed852e2009-09-05 21:47:34 +00002584 {
2585 char
cristy151b66d2015-04-15 10:50:31 +00002586 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002587
cristy151b66d2015-04-15 10:50:31 +00002588 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002589 path[strlen(path)-strlen(component)-1]='\0';
2590 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002591 }
2592#endif
2593#if defined(MAGICKCORE_BZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002594 if (*component != '\0')
2595 if (LocaleCompare(component,"bz2") == 0)
cristy3ed852e2009-09-05 21:47:34 +00002596 {
2597 char
cristy151b66d2015-04-15 10:50:31 +00002598 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002599
cristy151b66d2015-04-15 10:50:31 +00002600 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002601 path[strlen(path)-strlen(component)-1]='\0';
2602 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002603 }
2604#endif
2605 image_info->affirm=MagickFalse;
2606 sans_exception=AcquireExceptionInfo();
dirk8f681612015-04-16 21:05:08 +00002607 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002608 {
2609 MagickFormatType
2610 format_type;
2611
cristybb503372010-05-27 20:51:26 +00002612 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002613 i;
2614
2615 static const char
2616 *format_type_formats[] =
2617 {
2618 "AUTOTRACE",
2619 "BROWSE",
2620 "DCRAW",
2621 "EDIT",
cristy3ed852e2009-09-05 21:47:34 +00002622 "LAUNCH",
2623 "MPEG:DECODE",
2624 "MPEG:ENCODE",
2625 "PRINT",
2626 "PS:ALPHA",
2627 "PS:CMYK",
2628 "PS:COLOR",
2629 "PS:GRAY",
2630 "PS:MONO",
2631 "SCAN",
2632 "SHOW",
2633 "WIN",
2634 (char *) NULL
2635 };
2636
2637 /*
2638 User specified image format.
2639 */
dirk8f681612015-04-16 21:05:08 +00002640 (void) CopyMagickString(magic,component,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002641 LocaleUpper(magic);
2642 /*
2643 Look for explicit image formats.
2644 */
2645 format_type=UndefinedFormatType;
dirk80fd8af2015-02-22 00:45:51 +00002646 magick_info=GetMagickInfo(magic,sans_exception);
2647 if ((magick_info != (const MagickInfo *) NULL) &&
2648 (magick_info->format_type != UndefinedFormatType))
2649 format_type=magick_info->format_type;
cristy3ed852e2009-09-05 21:47:34 +00002650 i=0;
cristydd9a2532010-02-20 19:26:46 +00002651 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00002652 (format_type_formats[i] != (char *) NULL))
2653 {
2654 if ((*magic == *format_type_formats[i]) &&
2655 (LocaleCompare(magic,format_type_formats[i]) == 0))
2656 format_type=ExplicitFormatType;
2657 i++;
2658 }
cristy3ed852e2009-09-05 21:47:34 +00002659 if (format_type == UndefinedFormatType)
cristy151b66d2015-04-15 10:50:31 +00002660 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002661 else
2662 if (format_type == ExplicitFormatType)
2663 {
2664 image_info->affirm=MagickTrue;
cristy151b66d2015-04-15 10:50:31 +00002665 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002666 }
2667 if (LocaleCompare(magic,"RGB") == 0)
2668 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2669 }
2670 /*
2671 Look for explicit 'format:image' in filename.
2672 */
2673 *magic='\0';
2674 GetPathComponent(image_info->filename,MagickPath,magic);
2675 if (*magic == '\0')
Cristya8079ac2016-06-02 16:07:24 -04002676 {
2677 (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2678 magick_info=GetMagickInfo(magic,sans_exception);
Cristy0093cff2016-06-05 19:00:17 -04002679 GetPathComponent(image_info->filename,CanonicalPath,component);
2680 (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
Cristya8079ac2016-06-02 16:07:24 -04002681 }
cristy3ed852e2009-09-05 21:47:34 +00002682 else
2683 {
Cristy446b7ac2016-06-06 09:18:22 -04002684 const DelegateInfo
2685 *delegate_info;
2686
cristy3ed852e2009-09-05 21:47:34 +00002687 /*
2688 User specified image format.
2689 */
2690 LocaleUpper(magic);
Cristya8079ac2016-06-02 16:07:24 -04002691 magick_info=GetMagickInfo(magic,sans_exception);
Cristy75904212016-06-06 09:28:53 -04002692 delegate_info=GetDelegateInfo(magic,"*",sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002693 if (delegate_info == (const DelegateInfo *) NULL)
Cristy75904212016-06-06 09:28:53 -04002694 delegate_info=GetDelegateInfo("*",magic,sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002695 if (((magick_info != (const MagickInfo *) NULL) ||
2696 (delegate_info != (const DelegateInfo *) NULL)) &&
Cristya8079ac2016-06-02 16:07:24 -04002697 (IsMagickConflict(magic) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002698 {
Cristyb831d902016-05-07 08:23:15 -04002699 image_info->affirm=MagickTrue;
Cristy446b7ac2016-06-06 09:18:22 -04002700 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
Cristy0093cff2016-06-05 19:00:17 -04002701 GetPathComponent(image_info->filename,CanonicalPath,component);
2702 (void) CopyMagickString(image_info->filename,component,
2703 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002704 }
2705 }
cristy3ed852e2009-09-05 21:47:34 +00002706 sans_exception=DestroyExceptionInfo(sans_exception);
2707 if ((magick_info == (const MagickInfo *) NULL) ||
2708 (GetMagickEndianSupport(magick_info) == MagickFalse))
2709 image_info->endian=UndefinedEndian;
cristyd965a422010-03-03 17:47:35 +00002710 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00002711 {
2712 /*
cristyd965a422010-03-03 17:47:35 +00002713 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00002714 */
cristyd965a422010-03-03 17:47:35 +00002715 (void) InterpretImageFilename(image_info,(Image *) NULL,
dirk8f681612015-04-16 21:05:08 +00002716 image_info->filename,(int) image_info->scene,component,exception);
2717 if ((LocaleCompare(component,image_info->filename) != 0) &&
2718 (strchr(component,'%') == (char *) NULL))
cristyd965a422010-03-03 17:47:35 +00002719 image_info->adjoin=MagickFalse;
2720 }
2721 if ((image_info->adjoin != MagickFalse) && (frames > 0))
2722 {
2723 /*
2724 Some image formats do not support multiple frames per file.
2725 */
cristy3ed852e2009-09-05 21:47:34 +00002726 magick_info=GetMagickInfo(magic,exception);
2727 if (magick_info != (const MagickInfo *) NULL)
2728 if (GetMagickAdjoin(magick_info) == MagickFalse)
2729 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002730 }
2731 if (image_info->affirm != MagickFalse)
2732 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00002733 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00002734 {
dirk8f681612015-04-16 21:05:08 +00002735 unsigned char
2736 *magick;
2737
2738 size_t
2739 magick_size;
2740
cristy3ed852e2009-09-05 21:47:34 +00002741 /*
cristyd965a422010-03-03 17:47:35 +00002742 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00002743 */
cristy4f06b882015-04-17 00:16:45 +00002744 magick_size=GetMagicPatternExtent(exception);
dirk8f681612015-04-16 21:05:08 +00002745 if (magick_size == 0)
2746 return(MagickFalse);
cristy9950d572011-10-01 18:22:35 +00002747 image=AcquireImage(image_info,exception);
cristyd965a422010-03-03 17:47:35 +00002748 (void) CopyMagickString(image->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00002749 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002750 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2751 if (status == MagickFalse)
2752 {
2753 image=DestroyImage(image);
2754 return(MagickFalse);
2755 }
cristyd965a422010-03-03 17:47:35 +00002756 if ((IsBlobSeekable(image) == MagickFalse) ||
2757 (IsBlobExempt(image) != MagickFalse))
2758 {
2759 /*
2760 Copy standard input or pipe to temporary file.
2761 */
dirk8f681612015-04-16 21:05:08 +00002762 *component='\0';
2763 status=ImageToFile(image,component,exception);
cristyd965a422010-03-03 17:47:35 +00002764 (void) CloseBlob(image);
2765 if (status == MagickFalse)
2766 {
2767 image=DestroyImage(image);
2768 return(MagickFalse);
2769 }
2770 SetImageInfoFile(image_info,(FILE *) NULL);
dirk8f681612015-04-16 21:05:08 +00002771 (void) CopyMagickString(image->filename,component,MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002772 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2773 if (status == MagickFalse)
2774 {
2775 image=DestroyImage(image);
2776 return(MagickFalse);
2777 }
cristyee2f5d62015-07-28 13:19:43 +00002778 (void) CopyMagickString(image_info->filename,component,
2779 MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002780 image_info->temporary=MagickTrue;
2781 }
dirk8f681612015-04-16 21:05:08 +00002782 magick=(unsigned char *) AcquireMagickMemory(magick_size);
2783 if (magick == (unsigned char *) NULL)
2784 {
2785 (void) CloseBlob(image);
2786 image=DestroyImage(image);
2787 return(MagickFalse);
2788 }
2789 (void) ResetMagickMemory(magick,0,magick_size);
2790 count=ReadBlob(image,magick_size,magick);
cristyae958042013-01-05 15:48:19 +00002791 (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
cristyd965a422010-03-03 17:47:35 +00002792 (void) CloseBlob(image);
2793 image=DestroyImage(image);
2794 /*
2795 Check magic.xml configuration file.
2796 */
2797 sans_exception=AcquireExceptionInfo();
2798 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
dirk8f681612015-04-16 21:05:08 +00002799 magick=(unsigned char *) RelinquishMagickMemory(magick);
cristyd965a422010-03-03 17:47:35 +00002800 if ((magic_info != (const MagicInfo *) NULL) &&
2801 (GetMagicName(magic_info) != (char *) NULL))
2802 {
dirkca89a9b2015-02-22 01:19:21 +00002803 /*
2804 Try to use magick_info that was determined earlier by the extension
2805 */
2806 if ((magick_info != (const MagickInfo *) NULL) &&
2807 (GetMagickUseExtension(magick_info) != MagickFalse) &&
2808 (LocaleCompare(magick_info->module,GetMagicName(
2809 magic_info)) == 0))
2810 (void) CopyMagickString(image_info->magick,magick_info->name,
cristy151b66d2015-04-15 10:50:31 +00002811 MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002812 else
2813 {
2814 (void) CopyMagickString(image_info->magick,GetMagicName(
cristy151b66d2015-04-15 10:50:31 +00002815 magic_info),MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002816 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2817 }
cristyd965a422010-03-03 17:47:35 +00002818 if ((magick_info == (const MagickInfo *) NULL) ||
2819 (GetMagickEndianSupport(magick_info) == MagickFalse))
2820 image_info->endian=UndefinedEndian;
2821 sans_exception=DestroyExceptionInfo(sans_exception);
2822 return(MagickTrue);
2823 }
cristy3ed852e2009-09-05 21:47:34 +00002824 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2825 if ((magick_info == (const MagickInfo *) NULL) ||
2826 (GetMagickEndianSupport(magick_info) == MagickFalse))
2827 image_info->endian=UndefinedEndian;
2828 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00002829 }
cristy3ed852e2009-09-05 21:47:34 +00002830 return(MagickTrue);
2831}
2832
2833/*
2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835% %
2836% %
2837% %
2838% S e t I m a g e I n f o B l o b %
2839% %
2840% %
2841% %
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843%
2844% SetImageInfoBlob() sets the image info blob member.
2845%
2846% The format of the SetImageInfoBlob method is:
2847%
2848% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2849% const size_t length)
2850%
2851% A description of each parameter follows:
2852%
2853% o image_info: the image info.
2854%
2855% o blob: the blob.
2856%
2857% o length: the blob length.
2858%
2859*/
2860MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2861 const size_t length)
2862{
2863 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002864 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002865 if (image_info->debug != MagickFalse)
2866 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2867 image_info->filename);
2868 image_info->blob=(void *) blob;
2869 image_info->length=length;
2870}
2871
2872/*
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874% %
2875% %
2876% %
2877% S e t I m a g e I n f o F i l e %
2878% %
2879% %
2880% %
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882%
2883% SetImageInfoFile() sets the image info file member.
2884%
2885% The format of the SetImageInfoFile method is:
2886%
2887% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2888%
2889% A description of each parameter follows:
2890%
2891% o image_info: the image info.
2892%
2893% o file: the file.
2894%
2895*/
2896MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2897{
2898 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002899 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002900 if (image_info->debug != MagickFalse)
2901 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2902 image_info->filename);
2903 image_info->file=file;
2904}
2905
2906/*
2907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2908% %
2909% %
2910% %
2911% S e t I m a g e M a s k %
2912% %
2913% %
2914% %
2915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2916%
2917% SetImageMask() associates a mask with the image. The mask must be the same
2918% dimensions as the image.
2919%
2920% The format of the SetImageMask method is:
2921%
cristyacd0d4c2015-07-25 16:12:33 +00002922% MagickBooleanType SetImageMask(Image *image,const PixelMask type,
2923% const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002924%
2925% A description of each parameter follows:
2926%
2927% o image: the image.
2928%
cristyacd0d4c2015-07-25 16:12:33 +00002929% o type: the mask type, ReadPixelMask or WritePixelMask.
2930%
cristy3ed852e2009-09-05 21:47:34 +00002931% o mask: the image mask.
2932%
cristy018f07f2011-09-04 21:15:19 +00002933% o exception: return any errors or warnings in this structure.
2934%
cristy3ed852e2009-09-05 21:47:34 +00002935*/
cristyacd0d4c2015-07-25 16:12:33 +00002936MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
2937 const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002938{
cristy10a6c612012-01-29 21:41:05 +00002939 CacheView
2940 *mask_view,
2941 *image_view;
2942
2943 MagickBooleanType
2944 status;
2945
2946 ssize_t
2947 y;
2948
2949 /*
2950 Set image mask.
2951 */
cristy3ed852e2009-09-05 21:47:34 +00002952 assert(image != (Image *) NULL);
2953 if (image->debug != MagickFalse)
2954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002955 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00002956 if (mask == (const Image *) NULL)
2957 {
cristyacd0d4c2015-07-25 16:12:33 +00002958 switch (type)
2959 {
2960 case WritePixelMask: image->write_mask=MagickFalse; break;
2961 default: image->read_mask=MagickFalse; break;
2962 }
cristyd5be1f12013-03-18 23:55:01 +00002963 return(SyncImagePixelCache(image,exception));
cristy10a6c612012-01-29 21:41:05 +00002964 }
cristyacd0d4c2015-07-25 16:12:33 +00002965 switch (type)
2966 {
2967 case WritePixelMask: image->write_mask=MagickTrue; break;
2968 default: image->read_mask=MagickTrue; break;
2969 }
cristyd5be1f12013-03-18 23:55:01 +00002970 if (SyncImagePixelCache(image,exception) == MagickFalse)
2971 return(MagickFalse);
2972 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002973 mask_view=AcquireVirtualCacheView(mask,exception);
2974 image_view=AcquireAuthenticCacheView(image,exception);
cristyd5be1f12013-03-18 23:55:01 +00002975#if defined(MAGICKCORE_OPENMP_SUPPORT)
2976 #pragma omp parallel for schedule(static,4) shared(status) \
2977 magick_threads(mask,image,1,1)
2978#endif
cristy10a6c612012-01-29 21:41:05 +00002979 for (y=0; y < (ssize_t) image->rows; y++)
2980 {
2981 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01002982 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00002983
2984 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002985 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00002986
2987 register ssize_t
2988 x;
2989
2990 if (status == MagickFalse)
2991 continue;
2992 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
2993 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2994 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2995 {
2996 status=MagickFalse;
2997 continue;
2998 }
2999 for (x=0; x < (ssize_t) image->columns; x++)
3000 {
Cristy0596ce22015-11-20 21:11:22 -05003001 MagickRealType
3002 intensity;
3003
3004 intensity=GetPixelIntensity(mask,p);
cristyacd0d4c2015-07-25 16:12:33 +00003005 switch (type)
3006 {
3007 case WritePixelMask:
3008 {
Cristy0596ce22015-11-20 21:11:22 -05003009 SetPixelWriteMask(image,ClampToQuantum(QuantumRange-intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003010 break;
3011 }
3012 default:
3013 {
Cristy0596ce22015-11-20 21:11:22 -05003014 SetPixelReadMask(image,ClampToQuantum(QuantumRange-intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003015 break;
3016 }
3017 }
cristy10a6c612012-01-29 21:41:05 +00003018 p+=GetPixelChannels(mask);
3019 q+=GetPixelChannels(image);
3020 }
3021 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3022 status=MagickFalse;
3023 }
3024 mask_view=DestroyCacheView(mask_view);
3025 image_view=DestroyCacheView(image_view);
3026 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003027}
3028
3029/*
3030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3031% %
3032% %
3033% %
cristyb6a294d2011-10-03 00:55:17 +00003034% S e t I m a g e A l p h a %
cristy3ed852e2009-09-05 21:47:34 +00003035% %
3036% %
3037% %
3038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039%
cristye941a752011-10-15 01:52:48 +00003040% SetImageAlpha() sets the alpha levels of the image.
cristy3ed852e2009-09-05 21:47:34 +00003041%
cristyb6a294d2011-10-03 00:55:17 +00003042% The format of the SetImageAlpha method is:
cristy3ed852e2009-09-05 21:47:34 +00003043%
cristye941a752011-10-15 01:52:48 +00003044% MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
3045% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003046%
3047% A description of each parameter follows:
3048%
3049% o image: the image.
3050%
cristyb6a294d2011-10-03 00:55:17 +00003051% o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
cristy3ed852e2009-09-05 21:47:34 +00003052% fully transparent.
3053%
3054*/
cristye941a752011-10-15 01:52:48 +00003055MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
3056 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003057{
3058 CacheView
3059 *image_view;
3060
cristy3ed852e2009-09-05 21:47:34 +00003061 MagickBooleanType
3062 status;
3063
cristycb6d09b2010-06-19 01:59:36 +00003064 ssize_t
3065 y;
3066
cristy3ed852e2009-09-05 21:47:34 +00003067 assert(image != (Image *) NULL);
3068 if (image->debug != MagickFalse)
3069 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003070 assert(image->signature == MagickCoreSignature);
cristy8a46d822012-08-28 23:32:39 +00003071 image->alpha_trait=BlendPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +00003072 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003073 image_view=AcquireAuthenticCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00003074#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003075 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00003076 magick_threads(image,image,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00003077#endif
cristybb503372010-05-27 20:51:26 +00003078 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003079 {
cristy4c08aed2011-07-01 19:47:50 +00003080 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003081 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003082
cristycb6d09b2010-06-19 01:59:36 +00003083 register ssize_t
3084 x;
3085
cristy3ed852e2009-09-05 21:47:34 +00003086 if (status == MagickFalse)
3087 continue;
3088 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003089 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003090 {
3091 status=MagickFalse;
3092 continue;
3093 }
cristybb503372010-05-27 20:51:26 +00003094 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003095 {
dirk8ce24462015-11-15 16:39:28 +01003096 if (GetPixelReadMask(image,q) != 0)
3097 SetPixelAlpha(image,alpha,q);
cristyed231572011-07-14 02:18:59 +00003098 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003099 }
3100 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3101 status=MagickFalse;
3102 }
3103 image_view=DestroyCacheView(image_view);
3104 return(status);
3105}
3106
3107/*
3108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3109% %
3110% %
3111% %
cristy3ed852e2009-09-05 21:47:34 +00003112% 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 %
3113% %
3114% %
3115% %
3116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117%
3118% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3119% image and returns the previous setting. A virtual pixel is any pixel access
3120% that is outside the boundaries of the image cache.
3121%
3122% The format of the SetImageVirtualPixelMethod() method is:
3123%
cristy387430f2012-02-07 13:09:46 +00003124% VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3125% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003126%
3127% A description of each parameter follows:
3128%
3129% o image: the image.
3130%
3131% o virtual_pixel_method: choose the type of virtual pixel.
3132%
cristy387430f2012-02-07 13:09:46 +00003133% o exception: return any errors or warnings in this structure.
3134%
cristy3ed852e2009-09-05 21:47:34 +00003135*/
cristy387430f2012-02-07 13:09:46 +00003136MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3137 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003138{
3139 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003140 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003141 if (image->debug != MagickFalse)
3142 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy387430f2012-02-07 13:09:46 +00003143 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
cristy3ed852e2009-09-05 21:47:34 +00003144}
3145
3146/*
3147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3148% %
3149% %
3150% %
cristy4285d782011-02-09 20:12:28 +00003151% S m u s h I m a g e s %
3152% %
3153% %
3154% %
3155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3156%
3157% SmushImages() takes all images from the current image pointer to the end
3158% of the image list and smushes them to each other top-to-bottom if the
3159% stack parameter is true, otherwise left-to-right.
3160%
3161% The current gravity setting now effects how the image is justified in the
3162% final image.
3163%
3164% The format of the SmushImages method is:
3165%
cristy4ca38e22011-02-10 02:57:49 +00003166% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003167% ExceptionInfo *exception)
3168%
3169% A description of each parameter follows:
3170%
cristy4ca38e22011-02-10 02:57:49 +00003171% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003172%
3173% o stack: A value other than 0 stacks the images top-to-bottom.
3174%
3175% o offset: minimum distance in pixels between images.
3176%
3177% o exception: return any errors or warnings in this structure.
3178%
3179*/
cristy4ca38e22011-02-10 02:57:49 +00003180
cristy7c6dc152011-02-11 14:10:55 +00003181static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003182 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003183{
cristy4d727152011-02-10 19:57:21 +00003184 CacheView
3185 *left_view,
3186 *right_view;
3187
3188 const Image
3189 *left_image,
3190 *right_image;
3191
cristy4d727152011-02-10 19:57:21 +00003192 RectangleInfo
3193 left_geometry,
3194 right_geometry;
3195
cristy4c08aed2011-07-01 19:47:50 +00003196 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003197 *p;
3198
cristy4d727152011-02-10 19:57:21 +00003199 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003200 i,
cristy4d727152011-02-10 19:57:21 +00003201 y;
3202
cristy7c6dc152011-02-11 14:10:55 +00003203 size_t
3204 gap;
3205
cristy4d727152011-02-10 19:57:21 +00003206 ssize_t
cristy4d727152011-02-10 19:57:21 +00003207 x;
3208
3209 if (images->previous == (Image *) NULL)
3210 return(0);
3211 right_image=images;
3212 SetGeometry(smush_image,&right_geometry);
3213 GravityAdjustGeometry(right_image->columns,right_image->rows,
3214 right_image->gravity,&right_geometry);
3215 left_image=images->previous;
3216 SetGeometry(smush_image,&left_geometry);
3217 GravityAdjustGeometry(left_image->columns,left_image->rows,
3218 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003219 gap=right_image->columns;
cristy46ff2672012-12-14 15:32:26 +00003220 left_view=AcquireVirtualCacheView(left_image,exception);
3221 right_view=AcquireVirtualCacheView(right_image,exception);
cristy4d727152011-02-10 19:57:21 +00003222 for (y=0; y < (ssize_t) smush_image->rows; y++)
3223 {
3224 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3225 {
cristydab7e912011-02-11 18:19:24 +00003226 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003227 if ((p == (const Quantum *) NULL) ||
3228 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003229 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003230 break;
3231 }
cristy4ef6f062011-02-10 20:30:22 +00003232 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003233 for (x=0; x < (ssize_t) right_image->columns; x++)
3234 {
cristydab7e912011-02-11 18:19:24 +00003235 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003236 exception);
cristy4c08aed2011-07-01 19:47:50 +00003237 if ((p == (const Quantum *) NULL) ||
3238 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3239 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003240 break;
3241 }
cristy7c6dc152011-02-11 14:10:55 +00003242 if ((x+i) < (ssize_t) gap)
3243 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003244 }
3245 right_view=DestroyCacheView(right_view);
3246 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003247 if (y < (ssize_t) smush_image->rows)
3248 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003249 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003250}
3251
cristy7c6dc152011-02-11 14:10:55 +00003252static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003253 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003254{
cristy4d727152011-02-10 19:57:21 +00003255 CacheView
3256 *bottom_view,
3257 *top_view;
3258
3259 const Image
3260 *bottom_image,
3261 *top_image;
3262
cristy4d727152011-02-10 19:57:21 +00003263 RectangleInfo
3264 bottom_geometry,
3265 top_geometry;
3266
cristy4c08aed2011-07-01 19:47:50 +00003267 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003268 *p;
3269
cristy4d727152011-02-10 19:57:21 +00003270 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003271 i,
cristy4d727152011-02-10 19:57:21 +00003272 x;
3273
cristy7c6dc152011-02-11 14:10:55 +00003274 size_t
3275 gap;
3276
cristy4d727152011-02-10 19:57:21 +00003277 ssize_t
cristy4d727152011-02-10 19:57:21 +00003278 y;
3279
3280 if (images->previous == (Image *) NULL)
3281 return(0);
3282 bottom_image=images;
3283 SetGeometry(smush_image,&bottom_geometry);
3284 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3285 bottom_image->gravity,&bottom_geometry);
3286 top_image=images->previous;
3287 SetGeometry(smush_image,&top_geometry);
3288 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3289 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003290 gap=bottom_image->rows;
cristy46ff2672012-12-14 15:32:26 +00003291 top_view=AcquireVirtualCacheView(top_image,exception);
3292 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
cristy4d727152011-02-10 19:57:21 +00003293 for (x=0; x < (ssize_t) smush_image->columns; x++)
3294 {
3295 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3296 {
cristydab7e912011-02-11 18:19:24 +00003297 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003298 if ((p == (const Quantum *) NULL) ||
3299 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3300 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003301 break;
3302 }
cristy4ef6f062011-02-10 20:30:22 +00003303 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003304 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3305 {
cristydab7e912011-02-11 18:19:24 +00003306 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3307 exception);
cristy4c08aed2011-07-01 19:47:50 +00003308 if ((p == (const Quantum *) NULL) ||
3309 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3310 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003311 break;
3312 }
cristy7c6dc152011-02-11 14:10:55 +00003313 if ((y+i) < (ssize_t) gap)
3314 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003315 }
3316 bottom_view=DestroyCacheView(bottom_view);
3317 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003318 if (x < (ssize_t) smush_image->columns)
3319 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003320 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003321}
3322
3323MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003324 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3325{
3326#define SmushImageTag "Smush/Image"
3327
cristy4ca38e22011-02-10 02:57:49 +00003328 const Image
3329 *image;
3330
cristy4285d782011-02-09 20:12:28 +00003331 Image
3332 *smush_image;
3333
3334 MagickBooleanType
cristy4285d782011-02-09 20:12:28 +00003335 proceed,
3336 status;
3337
3338 MagickOffsetType
3339 n;
3340
cristy5a5e4d92012-08-29 00:06:25 +00003341 PixelTrait
3342 alpha_trait;
3343
cristy4285d782011-02-09 20:12:28 +00003344 RectangleInfo
3345 geometry;
3346
3347 register const Image
3348 *next;
3349
3350 size_t
3351 height,
3352 number_images,
3353 width;
3354
3355 ssize_t
3356 x_offset,
cristy4285d782011-02-09 20:12:28 +00003357 y_offset;
3358
3359 /*
cristy7c6dc152011-02-11 14:10:55 +00003360 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003361 */
cristy4ca38e22011-02-10 02:57:49 +00003362 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003363 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003364 if (images->debug != MagickFalse)
3365 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003366 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003367 assert(exception->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003368 image=images;
cristy5a5e4d92012-08-29 00:06:25 +00003369 alpha_trait=image->alpha_trait;
cristy4285d782011-02-09 20:12:28 +00003370 number_images=1;
3371 width=image->columns;
3372 height=image->rows;
3373 next=GetNextImageInList(image);
3374 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3375 {
cristy17f11b02014-12-20 19:37:04 +00003376 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +00003377 alpha_trait=BlendPixelTrait;
cristy4285d782011-02-09 20:12:28 +00003378 number_images++;
3379 if (stack != MagickFalse)
3380 {
3381 if (next->columns > width)
3382 width=next->columns;
3383 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003384 if (next->previous != (Image *) NULL)
3385 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003386 continue;
3387 }
3388 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003389 if (next->previous != (Image *) NULL)
3390 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003391 if (next->rows > height)
3392 height=next->rows;
3393 }
3394 /*
cristy7c6dc152011-02-11 14:10:55 +00003395 Smush images.
cristy4285d782011-02-09 20:12:28 +00003396 */
3397 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3398 if (smush_image == (Image *) NULL)
3399 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003400 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003401 {
cristy4285d782011-02-09 20:12:28 +00003402 smush_image=DestroyImage(smush_image);
3403 return((Image *) NULL);
3404 }
cristy5a5e4d92012-08-29 00:06:25 +00003405 smush_image->alpha_trait=alpha_trait;
cristyea1a8aa2011-10-20 13:24:06 +00003406 (void) SetImageBackgroundColor(smush_image,exception);
cristy4285d782011-02-09 20:12:28 +00003407 status=MagickTrue;
3408 x_offset=0;
3409 y_offset=0;
cristy4285d782011-02-09 20:12:28 +00003410 for (n=0; n < (MagickOffsetType) number_images; n++)
3411 {
3412 SetGeometry(smush_image,&geometry);
3413 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3414 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003415 {
3416 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003417 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003418 }
cristy4285d782011-02-09 20:12:28 +00003419 else
cristy4ca38e22011-02-10 02:57:49 +00003420 {
cristy7c6dc152011-02-11 14:10:55 +00003421 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003422 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00003423 }
cristy39172402012-03-30 13:04:39 +00003424 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3425 y_offset,exception);
cristy4285d782011-02-09 20:12:28 +00003426 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3427 if (proceed == MagickFalse)
3428 break;
3429 if (stack == MagickFalse)
3430 {
3431 x_offset+=(ssize_t) image->columns;
3432 y_offset=0;
3433 }
3434 else
3435 {
3436 x_offset=0;
3437 y_offset+=(ssize_t) image->rows;
3438 }
3439 image=GetNextImageInList(image);
3440 }
cristy4ef6f062011-02-10 20:30:22 +00003441 if (stack == MagickFalse)
3442 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00003443 else
cristy4ef6f062011-02-10 20:30:22 +00003444 smush_image->rows=(size_t) y_offset;
cristy4285d782011-02-09 20:12:28 +00003445 if (status == MagickFalse)
3446 smush_image=DestroyImage(smush_image);
3447 return(smush_image);
3448}
3449
3450/*
3451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3452% %
3453% %
3454% %
cristy3ed852e2009-09-05 21:47:34 +00003455% S t r i p I m a g e %
3456% %
3457% %
3458% %
3459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3460%
cristy376bda92009-12-22 21:15:23 +00003461% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00003462%
3463% The format of the StripImage method is:
3464%
cristye941a752011-10-15 01:52:48 +00003465% MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003466%
3467% A description of each parameter follows:
3468%
3469% o image: the image.
3470%
cristye941a752011-10-15 01:52:48 +00003471% o exception: return any errors or warnings in this structure.
3472%
cristy3ed852e2009-09-05 21:47:34 +00003473*/
cristye941a752011-10-15 01:52:48 +00003474MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003475{
cristye941a752011-10-15 01:52:48 +00003476 MagickBooleanType
3477 status;
3478
cristy3ed852e2009-09-05 21:47:34 +00003479 assert(image != (Image *) NULL);
3480 if (image->debug != MagickFalse)
3481 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye941a752011-10-15 01:52:48 +00003482 (void) exception;
cristy3ed852e2009-09-05 21:47:34 +00003483 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00003484 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00003485 (void) DeleteImageProperty(image,"date:create");
3486 (void) DeleteImageProperty(image,"date:modify");
cristy42e14902014-05-01 22:40:40 +00003487 status=SetImageArtifact(image,"png:exclude-chunk",
Cristy8c2e6b42016-04-02 10:14:03 -04003488 "bKGD,cHRM,EXIF,gAMA,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
cristye941a752011-10-15 01:52:48 +00003489 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003490}
3491
3492/*
3493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3494% %
3495% %
3496% %
3497+ S y n c I m a g e %
3498% %
3499% %
3500% %
3501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3502%
3503% SyncImage() initializes the red, green, and blue intensities of each pixel
3504% as defined by the colormap index.
3505%
3506% The format of the SyncImage method is:
3507%
cristyea1a8aa2011-10-20 13:24:06 +00003508% MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003509%
3510% A description of each parameter follows:
3511%
3512% o image: the image.
3513%
cristyea1a8aa2011-10-20 13:24:06 +00003514% o exception: return any errors or warnings in this structure.
3515%
cristy3ed852e2009-09-05 21:47:34 +00003516*/
3517
cristyaedc0312012-01-08 01:07:37 +00003518static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3519 MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00003520{
cristyc8d63672012-01-11 13:03:13 +00003521 if ((size_t) index < image->colors)
cristyaedc0312012-01-08 01:07:37 +00003522 return(index);
cristy3ed852e2009-09-05 21:47:34 +00003523 *range_exception=MagickTrue;
cristyd9657d22012-08-23 14:25:31 +00003524 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00003525}
3526
cristyea1a8aa2011-10-20 13:24:06 +00003527MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003528{
3529 CacheView
3530 *image_view;
3531
cristy3ed852e2009-09-05 21:47:34 +00003532 MagickBooleanType
3533 range_exception,
dirkf5cb0472014-10-24 20:10:14 +00003534 status,
3535 taint;
cristy3ed852e2009-09-05 21:47:34 +00003536
cristycb6d09b2010-06-19 01:59:36 +00003537 ssize_t
3538 y;
3539
cristy3ed852e2009-09-05 21:47:34 +00003540 assert(image != (Image *) NULL);
3541 if (image->debug != MagickFalse)
3542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003543 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003544 if (image->storage_class == DirectClass)
3545 return(MagickFalse);
3546 range_exception=MagickFalse;
3547 status=MagickTrue;
dirkf5cb0472014-10-24 20:10:14 +00003548 taint=image->taint;
cristy46ff2672012-12-14 15:32:26 +00003549 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00003550#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003551 #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
cristy5e6b2592012-12-19 14:08:11 +00003552 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00003553#endif
cristybb503372010-05-27 20:51:26 +00003554 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003555 {
cristy4c08aed2011-07-01 19:47:50 +00003556 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003557 index;
3558
cristy4c08aed2011-07-01 19:47:50 +00003559 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003560 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003561
cristycb6d09b2010-06-19 01:59:36 +00003562 register ssize_t
3563 x;
3564
cristy48974b92009-12-19 02:36:06 +00003565 if (status == MagickFalse)
3566 continue;
cristy3ed852e2009-09-05 21:47:34 +00003567 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003568 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003569 {
3570 status=MagickFalse;
3571 continue;
3572 }
cristybb503372010-05-27 20:51:26 +00003573 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003574 {
cristyaedc0312012-01-08 01:07:37 +00003575 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
cristy11a06d32015-01-04 12:03:27 +00003576 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00003577 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003578 }
3579 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3580 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003581 }
3582 image_view=DestroyCacheView(image_view);
dirkf5cb0472014-10-24 20:10:14 +00003583 image->taint=taint;
cristycaf45802012-06-16 18:28:54 +00003584 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
dirkb081bb22016-01-27 12:56:48 +01003585 (void) ThrowMagickException(exception,GetMagickModule(),
3586 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003587 return(status);
3588}
cristy1626d332009-11-10 16:58:17 +00003589
3590/*
3591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3592% %
3593% %
3594% %
3595% S y n c I m a g e S e t t i n g s %
3596% %
3597% %
3598% %
3599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3600%
anthony5f78bca2012-10-05 06:51:00 +00003601% SyncImageSettings() syncs any image_info global options into per-image
3602% attributes.
3603%
anthonyc7994672012-11-17 05:33:27 +00003604% Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
anthony5f78bca2012-10-05 06:51:00 +00003605% that operations and coders can find such settings. In IMv7 if a desired
3606% per-image artifact is not set, then it will directly look for a global
anthonyc7994672012-11-17 05:33:27 +00003607% option as a fallback, as such this copy is no longer needed, only the
3608% link set up.
cristy1626d332009-11-10 16:58:17 +00003609%
3610% The format of the SyncImageSettings method is:
3611%
3612% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003613% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003614% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003615% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003616%
3617% A description of each parameter follows:
3618%
3619% o image_info: the image info.
3620%
3621% o image: the image.
3622%
cristy6fccee12011-10-20 18:43:18 +00003623% o exception: return any errors or warnings in this structure.
3624%
cristy1626d332009-11-10 16:58:17 +00003625*/
3626
3627MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003628 Image *images,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003629{
3630 Image
3631 *image;
3632
3633 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003634 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003635 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003636 assert(images->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003637 if (images->debug != MagickFalse)
3638 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3639 image=images;
3640 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
cristy6fccee12011-10-20 18:43:18 +00003641 (void) SyncImageSettings(image_info,image,exception);
cristy1626d332009-11-10 16:58:17 +00003642 (void) DeleteImageOption(image_info,"page");
3643 return(MagickTrue);
3644}
3645
3646MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003647 Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003648{
cristy1626d332009-11-10 16:58:17 +00003649 const char
cristy202c1482012-10-05 23:47:57 +00003650 *option;
cristy1626d332009-11-10 16:58:17 +00003651
3652 GeometryInfo
3653 geometry_info;
3654
3655 MagickStatusType
3656 flags;
3657
cristy19eb6412010-04-23 14:42:29 +00003658 ResolutionType
3659 units;
3660
cristy1626d332009-11-10 16:58:17 +00003661 /*
3662 Sync image options.
3663 */
3664 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003665 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003666 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003667 assert(image->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003668 if (image->debug != MagickFalse)
3669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
dirkb797b2c2016-02-01 22:20:32 +01003670 option=GetImageOption(image_info,"alpha-color");
3671 if (option != (const char *) NULL)
3672 (void) QueryColorCompliance(option,AllCompliance,&image->alpha_color,
3673 exception);
cristy1626d332009-11-10 16:58:17 +00003674 option=GetImageOption(image_info,"background");
3675 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003676 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
cristy6fccee12011-10-20 18:43:18 +00003677 exception);
cristy1626d332009-11-10 16:58:17 +00003678 option=GetImageOption(image_info,"black-point-compensation");
3679 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003680 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003681 MagickBooleanOptions,MagickFalse,option);
3682 option=GetImageOption(image_info,"blue-primary");
3683 if (option != (const char *) NULL)
3684 {
3685 flags=ParseGeometry(option,&geometry_info);
3686 image->chromaticity.blue_primary.x=geometry_info.rho;
3687 image->chromaticity.blue_primary.y=geometry_info.sigma;
3688 if ((flags & SigmaValue) == 0)
3689 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3690 }
3691 option=GetImageOption(image_info,"bordercolor");
3692 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003693 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
cristy6fccee12011-10-20 18:43:18 +00003694 exception);
anthony72feaa62012-01-17 06:46:23 +00003695 /* FUTURE: do not sync compose to per-image compose setting here */
cristy1626d332009-11-10 16:58:17 +00003696 option=GetImageOption(image_info,"compose");
3697 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003698 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00003699 MagickFalse,option);
anthony72feaa62012-01-17 06:46:23 +00003700 /* -- */
cristy1626d332009-11-10 16:58:17 +00003701 option=GetImageOption(image_info,"compress");
3702 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003703 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003704 MagickCompressOptions,MagickFalse,option);
3705 option=GetImageOption(image_info,"debug");
3706 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003707 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003708 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00003709 option=GetImageOption(image_info,"density");
3710 if (option != (const char *) NULL)
3711 {
3712 GeometryInfo
3713 geometry_info;
3714
cristydd5f5912010-07-31 23:37:23 +00003715 flags=ParseGeometry(option,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +00003716 image->resolution.x=geometry_info.rho;
3717 image->resolution.y=geometry_info.sigma;
cristydd5f5912010-07-31 23:37:23 +00003718 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +00003719 image->resolution.y=image->resolution.x;
cristydd5f5912010-07-31 23:37:23 +00003720 }
cristy1626d332009-11-10 16:58:17 +00003721 option=GetImageOption(image_info,"depth");
3722 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003723 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003724 option=GetImageOption(image_info,"endian");
3725 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003726 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00003727 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003728 option=GetImageOption(image_info,"filter");
3729 if (option != (const char *) NULL)
dirk8b9f21c2016-02-01 22:30:19 +01003730 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00003731 MagickFalse,option);
3732 option=GetImageOption(image_info,"fuzz");
3733 if (option != (const char *) NULL)
cristydbdd0e32011-11-04 23:29:40 +00003734 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
cristy1626d332009-11-10 16:58:17 +00003735 option=GetImageOption(image_info,"gravity");
3736 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003737 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00003738 MagickFalse,option);
3739 option=GetImageOption(image_info,"green-primary");
3740 if (option != (const char *) NULL)
3741 {
3742 flags=ParseGeometry(option,&geometry_info);
3743 image->chromaticity.green_primary.x=geometry_info.rho;
3744 image->chromaticity.green_primary.y=geometry_info.sigma;
3745 if ((flags & SigmaValue) == 0)
3746 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
3747 }
3748 option=GetImageOption(image_info,"intent");
3749 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003750 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003751 MagickIntentOptions,MagickFalse,option);
cristy313634e2013-03-26 00:52:19 +00003752 option=GetImageOption(image_info,"intensity");
3753 if (option != (const char *) NULL)
3754 image->intensity=(PixelIntensityMethod) ParseCommandOption(
3755 MagickPixelIntensityOptions,MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003756 option=GetImageOption(image_info,"interlace");
3757 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003758 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00003759 MagickFalse,option);
3760 option=GetImageOption(image_info,"interpolate");
3761 if (option != (const char *) NULL)
cristy5c4e2582011-09-11 19:21:03 +00003762 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003763 MagickInterpolateOptions,MagickFalse,option);
3764 option=GetImageOption(image_info,"loop");
3765 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003766 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003767 option=GetImageOption(image_info,"orient");
3768 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003769 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003770 MagickOrientationOptions,MagickFalse,option);
cristy14ed6a22013-12-28 23:48:05 +00003771 option=GetImageOption(image_info,"page");
3772 if (option != (const char *) NULL)
3773 {
3774 char
3775 *geometry;
3776
3777 geometry=GetPageGeometry(option);
3778 flags=ParseAbsoluteGeometry(geometry,&image->page);
3779 geometry=DestroyString(geometry);
3780 }
cristy1626d332009-11-10 16:58:17 +00003781 option=GetImageOption(image_info,"quality");
3782 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003783 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003784 option=GetImageOption(image_info,"red-primary");
3785 if (option != (const char *) NULL)
3786 {
3787 flags=ParseGeometry(option,&geometry_info);
3788 image->chromaticity.red_primary.x=geometry_info.rho;
3789 image->chromaticity.red_primary.y=geometry_info.sigma;
3790 if ((flags & SigmaValue) == 0)
3791 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
3792 }
3793 if (image_info->quality != UndefinedCompressionQuality)
3794 image->quality=image_info->quality;
3795 option=GetImageOption(image_info,"scene");
3796 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003797 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003798 option=GetImageOption(image_info,"taint");
3799 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003800 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003801 MagickFalse,option);
3802 option=GetImageOption(image_info,"tile-offset");
3803 if (option != (const char *) NULL)
3804 {
3805 char
3806 *geometry;
3807
3808 geometry=GetPageGeometry(option);
3809 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
3810 geometry=DestroyString(geometry);
3811 }
3812 option=GetImageOption(image_info,"transparent-color");
3813 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003814 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
cristy6fccee12011-10-20 18:43:18 +00003815 exception);
cristy1626d332009-11-10 16:58:17 +00003816 option=GetImageOption(image_info,"type");
3817 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003818 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00003819 option);
3820 option=GetImageOption(image_info,"units");
cristyc8d63672012-01-11 13:03:13 +00003821 units=image_info->units;
cristy1626d332009-11-10 16:58:17 +00003822 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003823 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00003824 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00003825 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00003826 {
cristy19eb6412010-04-23 14:42:29 +00003827 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00003828 switch (image->units)
3829 {
3830 case PixelsPerInchResolution:
3831 {
cristy19eb6412010-04-23 14:42:29 +00003832 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00003833 {
cristy2a11bef2011-10-28 18:33:11 +00003834 image->resolution.x/=2.54;
3835 image->resolution.y/=2.54;
cristy1626d332009-11-10 16:58:17 +00003836 }
3837 break;
3838 }
3839 case PixelsPerCentimeterResolution:
3840 {
cristy19eb6412010-04-23 14:42:29 +00003841 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00003842 {
cristy2a11bef2011-10-28 18:33:11 +00003843 image->resolution.x=(double) ((size_t) (100.0*2.54*
3844 image->resolution.x+0.5))/100.0;
3845 image->resolution.y=(double) ((size_t) (100.0*2.54*
3846 image->resolution.y+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00003847 }
3848 break;
3849 }
3850 default:
3851 break;
3852 }
cristy19eb6412010-04-23 14:42:29 +00003853 image->units=units;
cristy1626d332009-11-10 16:58:17 +00003854 }
anthonyfd706f92012-01-19 04:22:02 +00003855 option=GetImageOption(image_info,"virtual-pixel");
3856 if (option != (const char *) NULL)
cristy387430f2012-02-07 13:09:46 +00003857 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
3858 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
3859 exception);
cristy1626d332009-11-10 16:58:17 +00003860 option=GetImageOption(image_info,"white-point");
3861 if (option != (const char *) NULL)
3862 {
3863 flags=ParseGeometry(option,&geometry_info);
3864 image->chromaticity.white_point.x=geometry_info.rho;
3865 image->chromaticity.white_point.y=geometry_info.sigma;
3866 if ((flags & SigmaValue) == 0)
3867 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
3868 }
Cristy9c282cc2015-08-29 17:37:22 -04003869 /*
3870 Pointer to allow the lookup of pre-image artifact will fallback to a global
3871 option setting/define. This saves a lot of duplication of global options
3872 into per-image artifacts, while ensuring only specifically set per-image
3873 artifacts are preserved when parenthesis ends.
anthony643c6132012-11-07 14:50:28 +00003874 */
dirk98d3e1c2015-08-28 21:09:11 +02003875 if (image->image_info != (ImageInfo *) NULL)
3876 image->image_info=DestroyImageInfo(image->image_info);
Cristy36421ee2015-08-28 11:58:20 -04003877 image->image_info=CloneImageInfo(image_info);
cristy1626d332009-11-10 16:58:17 +00003878 return(MagickTrue);
3879}