blob: e3ae09672cf0ae2779563f05758cd1d355e12465 [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 {
Cristydf5e8b12016-12-02 17:26:39 -0500579 if (GetPixelWriteMask(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);
Cristy4da63352016-12-03 08:59:32 -0500750 (void) SetImageMask(image,WritePixelMask,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 {
Cristydf5e8b12016-12-02 17:26:39 -05001488 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
dirkaf131f12016-01-10 01:29:22 +01001489 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
Cristydf5e8b12016-12-02 17:26:39 -05001821 if (GetPixelWriteMask(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% %
Cristy03811ea2016-07-27 20:32:47 -04002911% S e t I m a g e A l p h a %
2912% %
2913% %
2914% %
2915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2916%
2917% SetImageAlpha() sets the alpha levels of the image.
2918%
2919% The format of the SetImageAlpha method is:
2920%
2921% MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2922% ExceptionInfo *exception)
2923%
2924% A description of each parameter follows:
2925%
2926% o image: the image.
2927%
2928% o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
2929% fully transparent.
2930%
2931*/
2932MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2933 ExceptionInfo *exception)
2934{
2935 CacheView
2936 *image_view;
2937
2938 MagickBooleanType
2939 status;
2940
2941 ssize_t
2942 y;
2943
2944 assert(image != (Image *) NULL);
2945 if (image->debug != MagickFalse)
2946 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2947 assert(image->signature == MagickCoreSignature);
2948 image->alpha_trait=BlendPixelTrait;
2949 status=MagickTrue;
2950 image_view=AcquireAuthenticCacheView(image,exception);
2951#if defined(MAGICKCORE_OPENMP_SUPPORT)
2952 #pragma omp parallel for schedule(static,4) shared(status) \
2953 magick_threads(image,image,image->rows,1)
2954#endif
2955 for (y=0; y < (ssize_t) image->rows; y++)
2956 {
2957 register Quantum
2958 *magick_restrict q;
2959
2960 register ssize_t
2961 x;
2962
2963 if (status == MagickFalse)
2964 continue;
2965 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2966 if (q == (Quantum *) NULL)
2967 {
2968 status=MagickFalse;
2969 continue;
2970 }
2971 for (x=0; x < (ssize_t) image->columns; x++)
2972 {
Cristydf5e8b12016-12-02 17:26:39 -05002973 if (GetPixelWriteMask(image,q) != 0)
Cristy03811ea2016-07-27 20:32:47 -04002974 SetPixelAlpha(image,alpha,q);
2975 q+=GetPixelChannels(image);
2976 }
2977 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2978 status=MagickFalse;
2979 }
2980 image_view=DestroyCacheView(image_view);
2981 return(status);
2982}
2983
2984/*
2985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2986% %
2987% %
2988% %
cristy3ed852e2009-09-05 21:47:34 +00002989% S e t I m a g e M a s k %
2990% %
2991% %
2992% %
2993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994%
2995% SetImageMask() associates a mask with the image. The mask must be the same
2996% dimensions as the image.
2997%
2998% The format of the SetImageMask method is:
2999%
cristyacd0d4c2015-07-25 16:12:33 +00003000% MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3001% const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003002%
3003% A description of each parameter follows:
3004%
3005% o image: the image.
3006%
cristyacd0d4c2015-07-25 16:12:33 +00003007% o type: the mask type, ReadPixelMask or WritePixelMask.
3008%
cristy3ed852e2009-09-05 21:47:34 +00003009% o mask: the image mask.
3010%
cristy018f07f2011-09-04 21:15:19 +00003011% o exception: return any errors or warnings in this structure.
3012%
cristy3ed852e2009-09-05 21:47:34 +00003013*/
cristyacd0d4c2015-07-25 16:12:33 +00003014MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3015 const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003016{
cristy10a6c612012-01-29 21:41:05 +00003017 CacheView
3018 *mask_view,
3019 *image_view;
3020
3021 MagickBooleanType
3022 status;
3023
3024 ssize_t
3025 y;
3026
3027 /*
3028 Set image mask.
3029 */
cristy3ed852e2009-09-05 21:47:34 +00003030 assert(image != (Image *) NULL);
3031 if (image->debug != MagickFalse)
3032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003033 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00003034 if (mask == (const Image *) NULL)
3035 {
cristyacd0d4c2015-07-25 16:12:33 +00003036 switch (type)
3037 {
3038 case WritePixelMask: image->write_mask=MagickFalse; break;
3039 default: image->read_mask=MagickFalse; break;
3040 }
cristyd5be1f12013-03-18 23:55:01 +00003041 return(SyncImagePixelCache(image,exception));
cristy10a6c612012-01-29 21:41:05 +00003042 }
cristyacd0d4c2015-07-25 16:12:33 +00003043 switch (type)
3044 {
3045 case WritePixelMask: image->write_mask=MagickTrue; break;
3046 default: image->read_mask=MagickTrue; break;
3047 }
cristyd5be1f12013-03-18 23:55:01 +00003048 if (SyncImagePixelCache(image,exception) == MagickFalse)
3049 return(MagickFalse);
3050 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003051 mask_view=AcquireVirtualCacheView(mask,exception);
3052 image_view=AcquireAuthenticCacheView(image,exception);
cristyd5be1f12013-03-18 23:55:01 +00003053#if defined(MAGICKCORE_OPENMP_SUPPORT)
3054 #pragma omp parallel for schedule(static,4) shared(status) \
3055 magick_threads(mask,image,1,1)
3056#endif
cristy10a6c612012-01-29 21:41:05 +00003057 for (y=0; y < (ssize_t) image->rows; y++)
3058 {
3059 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003060 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00003061
3062 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003063 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00003064
3065 register ssize_t
3066 x;
3067
3068 if (status == MagickFalse)
3069 continue;
3070 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3071 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3072 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3073 {
3074 status=MagickFalse;
3075 continue;
3076 }
3077 for (x=0; x < (ssize_t) image->columns; x++)
3078 {
Cristy0596ce22015-11-20 21:11:22 -05003079 MagickRealType
3080 intensity;
3081
Cristy4da63352016-12-03 08:59:32 -05003082 intensity=0.0;
3083 if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3084 intensity=GetPixelIntensity(mask,p);
cristyacd0d4c2015-07-25 16:12:33 +00003085 switch (type)
3086 {
3087 case WritePixelMask:
3088 {
Cristyd60923b2016-12-02 19:37:09 -05003089 SetPixelWriteMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003090 break;
3091 }
3092 default:
3093 {
Cristyd60923b2016-12-02 19:37:09 -05003094 SetPixelReadMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003095 break;
3096 }
3097 }
cristy10a6c612012-01-29 21:41:05 +00003098 p+=GetPixelChannels(mask);
3099 q+=GetPixelChannels(image);
3100 }
3101 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3102 status=MagickFalse;
3103 }
3104 mask_view=DestroyCacheView(mask_view);
3105 image_view=DestroyCacheView(image_view);
3106 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003107}
3108
3109/*
3110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3111% %
3112% %
3113% %
Cristy03811ea2016-07-27 20:32:47 -04003114% S e t I m a g e R e g i o n M a s k %
cristy3ed852e2009-09-05 21:47:34 +00003115% %
3116% %
3117% %
3118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119%
Cristyd47057b2016-07-28 18:57:46 -04003120% SetImageRegionMask() associates a mask with the image as defined by the
3121% specified region.
cristy3ed852e2009-09-05 21:47:34 +00003122%
Cristy03811ea2016-07-27 20:32:47 -04003123% The format of the SetImageRegionMask method is:
cristy3ed852e2009-09-05 21:47:34 +00003124%
Cristy03811ea2016-07-27 20:32:47 -04003125% MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3126% const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003127%
3128% A description of each parameter follows:
3129%
3130% o image: the image.
3131%
Cristy03811ea2016-07-27 20:32:47 -04003132% o type: the mask type, ReadPixelMask or WritePixelMask.
3133%
3134% o geometry: the mask region.
3135%
3136% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00003137%
3138*/
Cristy03811ea2016-07-27 20:32:47 -04003139MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3140 const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003141{
3142 CacheView
3143 *image_view;
3144
cristy3ed852e2009-09-05 21:47:34 +00003145 MagickBooleanType
3146 status;
3147
cristycb6d09b2010-06-19 01:59:36 +00003148 ssize_t
3149 y;
3150
Cristy03811ea2016-07-27 20:32:47 -04003151 /*
3152 Set image mask as defined by the region.
3153 */
cristy3ed852e2009-09-05 21:47:34 +00003154 assert(image != (Image *) NULL);
3155 if (image->debug != MagickFalse)
3156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003157 assert(image->signature == MagickCoreSignature);
Cristy03811ea2016-07-27 20:32:47 -04003158 if (region == (const RectangleInfo *) NULL)
3159 {
3160 switch (type)
3161 {
3162 case WritePixelMask: image->write_mask=MagickFalse; break;
3163 default: image->read_mask=MagickFalse; break;
3164 }
3165 return(SyncImagePixelCache(image,exception));
3166 }
3167 switch (type)
3168 {
3169 case WritePixelMask: image->write_mask=MagickTrue; break;
3170 default: image->read_mask=MagickTrue; break;
3171 }
3172 if (SyncImagePixelCache(image,exception) == MagickFalse)
3173 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00003174 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003175 image_view=AcquireAuthenticCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00003176#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003177 #pragma omp parallel for schedule(static,4) shared(status) \
Cristy03811ea2016-07-27 20:32:47 -04003178 magick_threads(image,image,1,1)
cristy3ed852e2009-09-05 21:47:34 +00003179#endif
cristybb503372010-05-27 20:51:26 +00003180 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003181 {
cristy4c08aed2011-07-01 19:47:50 +00003182 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003183 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003184
cristycb6d09b2010-06-19 01:59:36 +00003185 register ssize_t
3186 x;
3187
cristy3ed852e2009-09-05 21:47:34 +00003188 if (status == MagickFalse)
3189 continue;
3190 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003191 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003192 {
3193 status=MagickFalse;
3194 continue;
3195 }
cristybb503372010-05-27 20:51:26 +00003196 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003197 {
Cristy36610622016-07-28 17:41:37 -04003198 Quantum
3199 pixel;
Cristy03811ea2016-07-27 20:32:47 -04003200
Cristy36610622016-07-28 17:41:37 -04003201 pixel=0;
3202 if (((x >= region->x) && (x < (region->x+region->width))) &&
3203 ((y >= region->y) && (y < (region->y+region->height))))
3204 pixel=QuantumRange;
Cristy03811ea2016-07-27 20:32:47 -04003205 switch (type)
3206 {
3207 case WritePixelMask:
3208 {
Cristy36610622016-07-28 17:41:37 -04003209 SetPixelWriteMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003210 break;
3211 }
3212 default:
3213 {
Cristy36610622016-07-28 17:41:37 -04003214 SetPixelReadMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003215 break;
3216 }
3217 }
cristyed231572011-07-14 02:18:59 +00003218 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003219 }
3220 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3221 status=MagickFalse;
3222 }
3223 image_view=DestroyCacheView(image_view);
3224 return(status);
3225}
3226
3227/*
3228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3229% %
3230% %
3231% %
cristy3ed852e2009-09-05 21:47:34 +00003232% 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 %
3233% %
3234% %
3235% %
3236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3237%
3238% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3239% image and returns the previous setting. A virtual pixel is any pixel access
3240% that is outside the boundaries of the image cache.
3241%
3242% The format of the SetImageVirtualPixelMethod() method is:
3243%
cristy387430f2012-02-07 13:09:46 +00003244% VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3245% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003246%
3247% A description of each parameter follows:
3248%
3249% o image: the image.
3250%
3251% o virtual_pixel_method: choose the type of virtual pixel.
3252%
cristy387430f2012-02-07 13:09:46 +00003253% o exception: return any errors or warnings in this structure.
3254%
cristy3ed852e2009-09-05 21:47:34 +00003255*/
cristy387430f2012-02-07 13:09:46 +00003256MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3257 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003258{
3259 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003260 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003261 if (image->debug != MagickFalse)
3262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy387430f2012-02-07 13:09:46 +00003263 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
cristy3ed852e2009-09-05 21:47:34 +00003264}
3265
3266/*
3267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3268% %
3269% %
3270% %
cristy4285d782011-02-09 20:12:28 +00003271% S m u s h I m a g e s %
3272% %
3273% %
3274% %
3275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3276%
3277% SmushImages() takes all images from the current image pointer to the end
3278% of the image list and smushes them to each other top-to-bottom if the
3279% stack parameter is true, otherwise left-to-right.
3280%
3281% The current gravity setting now effects how the image is justified in the
3282% final image.
3283%
3284% The format of the SmushImages method is:
3285%
cristy4ca38e22011-02-10 02:57:49 +00003286% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003287% ExceptionInfo *exception)
3288%
3289% A description of each parameter follows:
3290%
cristy4ca38e22011-02-10 02:57:49 +00003291% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003292%
3293% o stack: A value other than 0 stacks the images top-to-bottom.
3294%
3295% o offset: minimum distance in pixels between images.
3296%
3297% o exception: return any errors or warnings in this structure.
3298%
3299*/
cristy4ca38e22011-02-10 02:57:49 +00003300
cristy7c6dc152011-02-11 14:10:55 +00003301static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003302 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003303{
cristy4d727152011-02-10 19:57:21 +00003304 CacheView
3305 *left_view,
3306 *right_view;
3307
3308 const Image
3309 *left_image,
3310 *right_image;
3311
cristy4d727152011-02-10 19:57:21 +00003312 RectangleInfo
3313 left_geometry,
3314 right_geometry;
3315
cristy4c08aed2011-07-01 19:47:50 +00003316 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003317 *p;
3318
cristy4d727152011-02-10 19:57:21 +00003319 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003320 i,
cristy4d727152011-02-10 19:57:21 +00003321 y;
3322
cristy7c6dc152011-02-11 14:10:55 +00003323 size_t
3324 gap;
3325
cristy4d727152011-02-10 19:57:21 +00003326 ssize_t
cristy4d727152011-02-10 19:57:21 +00003327 x;
3328
3329 if (images->previous == (Image *) NULL)
3330 return(0);
3331 right_image=images;
3332 SetGeometry(smush_image,&right_geometry);
3333 GravityAdjustGeometry(right_image->columns,right_image->rows,
3334 right_image->gravity,&right_geometry);
3335 left_image=images->previous;
3336 SetGeometry(smush_image,&left_geometry);
3337 GravityAdjustGeometry(left_image->columns,left_image->rows,
3338 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003339 gap=right_image->columns;
cristy46ff2672012-12-14 15:32:26 +00003340 left_view=AcquireVirtualCacheView(left_image,exception);
3341 right_view=AcquireVirtualCacheView(right_image,exception);
cristy4d727152011-02-10 19:57:21 +00003342 for (y=0; y < (ssize_t) smush_image->rows; y++)
3343 {
3344 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3345 {
cristydab7e912011-02-11 18:19:24 +00003346 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003347 if ((p == (const Quantum *) NULL) ||
3348 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003349 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003350 break;
3351 }
cristy4ef6f062011-02-10 20:30:22 +00003352 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003353 for (x=0; x < (ssize_t) right_image->columns; x++)
3354 {
cristydab7e912011-02-11 18:19:24 +00003355 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003356 exception);
cristy4c08aed2011-07-01 19:47:50 +00003357 if ((p == (const Quantum *) NULL) ||
3358 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3359 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003360 break;
3361 }
cristy7c6dc152011-02-11 14:10:55 +00003362 if ((x+i) < (ssize_t) gap)
3363 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003364 }
3365 right_view=DestroyCacheView(right_view);
3366 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003367 if (y < (ssize_t) smush_image->rows)
3368 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003369 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003370}
3371
cristy7c6dc152011-02-11 14:10:55 +00003372static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003373 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003374{
cristy4d727152011-02-10 19:57:21 +00003375 CacheView
3376 *bottom_view,
3377 *top_view;
3378
3379 const Image
3380 *bottom_image,
3381 *top_image;
3382
cristy4d727152011-02-10 19:57:21 +00003383 RectangleInfo
3384 bottom_geometry,
3385 top_geometry;
3386
cristy4c08aed2011-07-01 19:47:50 +00003387 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003388 *p;
3389
cristy4d727152011-02-10 19:57:21 +00003390 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003391 i,
cristy4d727152011-02-10 19:57:21 +00003392 x;
3393
cristy7c6dc152011-02-11 14:10:55 +00003394 size_t
3395 gap;
3396
cristy4d727152011-02-10 19:57:21 +00003397 ssize_t
cristy4d727152011-02-10 19:57:21 +00003398 y;
3399
3400 if (images->previous == (Image *) NULL)
3401 return(0);
3402 bottom_image=images;
3403 SetGeometry(smush_image,&bottom_geometry);
3404 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3405 bottom_image->gravity,&bottom_geometry);
3406 top_image=images->previous;
3407 SetGeometry(smush_image,&top_geometry);
3408 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3409 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003410 gap=bottom_image->rows;
cristy46ff2672012-12-14 15:32:26 +00003411 top_view=AcquireVirtualCacheView(top_image,exception);
3412 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
cristy4d727152011-02-10 19:57:21 +00003413 for (x=0; x < (ssize_t) smush_image->columns; x++)
3414 {
3415 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3416 {
cristydab7e912011-02-11 18:19:24 +00003417 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003418 if ((p == (const Quantum *) NULL) ||
3419 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3420 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003421 break;
3422 }
cristy4ef6f062011-02-10 20:30:22 +00003423 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003424 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3425 {
cristydab7e912011-02-11 18:19:24 +00003426 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3427 exception);
cristy4c08aed2011-07-01 19:47:50 +00003428 if ((p == (const Quantum *) NULL) ||
3429 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3430 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003431 break;
3432 }
cristy7c6dc152011-02-11 14:10:55 +00003433 if ((y+i) < (ssize_t) gap)
3434 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003435 }
3436 bottom_view=DestroyCacheView(bottom_view);
3437 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003438 if (x < (ssize_t) smush_image->columns)
3439 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003440 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003441}
3442
3443MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003444 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3445{
3446#define SmushImageTag "Smush/Image"
3447
cristy4ca38e22011-02-10 02:57:49 +00003448 const Image
3449 *image;
3450
cristy4285d782011-02-09 20:12:28 +00003451 Image
3452 *smush_image;
3453
3454 MagickBooleanType
cristy4285d782011-02-09 20:12:28 +00003455 proceed,
3456 status;
3457
3458 MagickOffsetType
3459 n;
3460
cristy5a5e4d92012-08-29 00:06:25 +00003461 PixelTrait
3462 alpha_trait;
3463
cristy4285d782011-02-09 20:12:28 +00003464 RectangleInfo
3465 geometry;
3466
3467 register const Image
3468 *next;
3469
3470 size_t
3471 height,
3472 number_images,
3473 width;
3474
3475 ssize_t
3476 x_offset,
cristy4285d782011-02-09 20:12:28 +00003477 y_offset;
3478
3479 /*
cristy7c6dc152011-02-11 14:10:55 +00003480 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003481 */
cristy4ca38e22011-02-10 02:57:49 +00003482 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003483 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003484 if (images->debug != MagickFalse)
3485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003486 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003487 assert(exception->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003488 image=images;
cristy5a5e4d92012-08-29 00:06:25 +00003489 alpha_trait=image->alpha_trait;
cristy4285d782011-02-09 20:12:28 +00003490 number_images=1;
3491 width=image->columns;
3492 height=image->rows;
3493 next=GetNextImageInList(image);
3494 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3495 {
cristy17f11b02014-12-20 19:37:04 +00003496 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +00003497 alpha_trait=BlendPixelTrait;
cristy4285d782011-02-09 20:12:28 +00003498 number_images++;
3499 if (stack != MagickFalse)
3500 {
3501 if (next->columns > width)
3502 width=next->columns;
3503 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003504 if (next->previous != (Image *) NULL)
3505 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003506 continue;
3507 }
3508 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003509 if (next->previous != (Image *) NULL)
3510 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003511 if (next->rows > height)
3512 height=next->rows;
3513 }
3514 /*
cristy7c6dc152011-02-11 14:10:55 +00003515 Smush images.
cristy4285d782011-02-09 20:12:28 +00003516 */
3517 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3518 if (smush_image == (Image *) NULL)
3519 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003520 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003521 {
cristy4285d782011-02-09 20:12:28 +00003522 smush_image=DestroyImage(smush_image);
3523 return((Image *) NULL);
3524 }
cristy5a5e4d92012-08-29 00:06:25 +00003525 smush_image->alpha_trait=alpha_trait;
cristyea1a8aa2011-10-20 13:24:06 +00003526 (void) SetImageBackgroundColor(smush_image,exception);
cristy4285d782011-02-09 20:12:28 +00003527 status=MagickTrue;
3528 x_offset=0;
3529 y_offset=0;
cristy4285d782011-02-09 20:12:28 +00003530 for (n=0; n < (MagickOffsetType) number_images; n++)
3531 {
3532 SetGeometry(smush_image,&geometry);
3533 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3534 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003535 {
3536 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003537 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003538 }
cristy4285d782011-02-09 20:12:28 +00003539 else
cristy4ca38e22011-02-10 02:57:49 +00003540 {
cristy7c6dc152011-02-11 14:10:55 +00003541 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003542 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00003543 }
cristy39172402012-03-30 13:04:39 +00003544 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3545 y_offset,exception);
cristy4285d782011-02-09 20:12:28 +00003546 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3547 if (proceed == MagickFalse)
3548 break;
3549 if (stack == MagickFalse)
3550 {
3551 x_offset+=(ssize_t) image->columns;
3552 y_offset=0;
3553 }
3554 else
3555 {
3556 x_offset=0;
3557 y_offset+=(ssize_t) image->rows;
3558 }
3559 image=GetNextImageInList(image);
3560 }
cristy4ef6f062011-02-10 20:30:22 +00003561 if (stack == MagickFalse)
3562 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00003563 else
cristy4ef6f062011-02-10 20:30:22 +00003564 smush_image->rows=(size_t) y_offset;
cristy4285d782011-02-09 20:12:28 +00003565 if (status == MagickFalse)
3566 smush_image=DestroyImage(smush_image);
3567 return(smush_image);
3568}
3569
3570/*
3571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3572% %
3573% %
3574% %
cristy3ed852e2009-09-05 21:47:34 +00003575% S t r i p I m a g e %
3576% %
3577% %
3578% %
3579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580%
cristy376bda92009-12-22 21:15:23 +00003581% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00003582%
3583% The format of the StripImage method is:
3584%
cristye941a752011-10-15 01:52:48 +00003585% MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003586%
3587% A description of each parameter follows:
3588%
3589% o image: the image.
3590%
cristye941a752011-10-15 01:52:48 +00003591% o exception: return any errors or warnings in this structure.
3592%
cristy3ed852e2009-09-05 21:47:34 +00003593*/
cristye941a752011-10-15 01:52:48 +00003594MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003595{
cristye941a752011-10-15 01:52:48 +00003596 MagickBooleanType
3597 status;
3598
cristy3ed852e2009-09-05 21:47:34 +00003599 assert(image != (Image *) NULL);
3600 if (image->debug != MagickFalse)
3601 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye941a752011-10-15 01:52:48 +00003602 (void) exception;
cristy3ed852e2009-09-05 21:47:34 +00003603 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00003604 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00003605 (void) DeleteImageProperty(image,"date:create");
3606 (void) DeleteImageProperty(image,"date:modify");
cristy42e14902014-05-01 22:40:40 +00003607 status=SetImageArtifact(image,"png:exclude-chunk",
Cristy8c2e6b42016-04-02 10:14:03 -04003608 "bKGD,cHRM,EXIF,gAMA,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
cristye941a752011-10-15 01:52:48 +00003609 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003610}
3611
3612/*
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614% %
3615% %
3616% %
3617+ S y n c I m a g e %
3618% %
3619% %
3620% %
3621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3622%
3623% SyncImage() initializes the red, green, and blue intensities of each pixel
3624% as defined by the colormap index.
3625%
3626% The format of the SyncImage method is:
3627%
cristyea1a8aa2011-10-20 13:24:06 +00003628% MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003629%
3630% A description of each parameter follows:
3631%
3632% o image: the image.
3633%
cristyea1a8aa2011-10-20 13:24:06 +00003634% o exception: return any errors or warnings in this structure.
3635%
cristy3ed852e2009-09-05 21:47:34 +00003636*/
3637
cristyaedc0312012-01-08 01:07:37 +00003638static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3639 MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00003640{
cristyc8d63672012-01-11 13:03:13 +00003641 if ((size_t) index < image->colors)
cristyaedc0312012-01-08 01:07:37 +00003642 return(index);
cristy3ed852e2009-09-05 21:47:34 +00003643 *range_exception=MagickTrue;
cristyd9657d22012-08-23 14:25:31 +00003644 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00003645}
3646
cristyea1a8aa2011-10-20 13:24:06 +00003647MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003648{
3649 CacheView
3650 *image_view;
3651
cristy3ed852e2009-09-05 21:47:34 +00003652 MagickBooleanType
3653 range_exception,
dirkf5cb0472014-10-24 20:10:14 +00003654 status,
3655 taint;
cristy3ed852e2009-09-05 21:47:34 +00003656
cristycb6d09b2010-06-19 01:59:36 +00003657 ssize_t
3658 y;
3659
cristy3ed852e2009-09-05 21:47:34 +00003660 assert(image != (Image *) NULL);
3661 if (image->debug != MagickFalse)
3662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003663 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003664 if (image->storage_class == DirectClass)
3665 return(MagickFalse);
3666 range_exception=MagickFalse;
3667 status=MagickTrue;
dirkf5cb0472014-10-24 20:10:14 +00003668 taint=image->taint;
cristy46ff2672012-12-14 15:32:26 +00003669 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00003670#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003671 #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
cristy5e6b2592012-12-19 14:08:11 +00003672 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00003673#endif
cristybb503372010-05-27 20:51:26 +00003674 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003675 {
cristy4c08aed2011-07-01 19:47:50 +00003676 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003677 index;
3678
cristy4c08aed2011-07-01 19:47:50 +00003679 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003680 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003681
cristycb6d09b2010-06-19 01:59:36 +00003682 register ssize_t
3683 x;
3684
cristy48974b92009-12-19 02:36:06 +00003685 if (status == MagickFalse)
3686 continue;
cristy3ed852e2009-09-05 21:47:34 +00003687 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003688 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003689 {
3690 status=MagickFalse;
3691 continue;
3692 }
cristybb503372010-05-27 20:51:26 +00003693 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003694 {
cristyaedc0312012-01-08 01:07:37 +00003695 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
cristy11a06d32015-01-04 12:03:27 +00003696 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00003697 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003698 }
3699 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3700 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003701 }
3702 image_view=DestroyCacheView(image_view);
dirkf5cb0472014-10-24 20:10:14 +00003703 image->taint=taint;
cristycaf45802012-06-16 18:28:54 +00003704 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
dirkb081bb22016-01-27 12:56:48 +01003705 (void) ThrowMagickException(exception,GetMagickModule(),
3706 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003707 return(status);
3708}
cristy1626d332009-11-10 16:58:17 +00003709
3710/*
3711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3712% %
3713% %
3714% %
3715% S y n c I m a g e S e t t i n g s %
3716% %
3717% %
3718% %
3719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3720%
anthony5f78bca2012-10-05 06:51:00 +00003721% SyncImageSettings() syncs any image_info global options into per-image
3722% attributes.
3723%
anthonyc7994672012-11-17 05:33:27 +00003724% Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
anthony5f78bca2012-10-05 06:51:00 +00003725% that operations and coders can find such settings. In IMv7 if a desired
3726% per-image artifact is not set, then it will directly look for a global
anthonyc7994672012-11-17 05:33:27 +00003727% option as a fallback, as such this copy is no longer needed, only the
3728% link set up.
cristy1626d332009-11-10 16:58:17 +00003729%
3730% The format of the SyncImageSettings method is:
3731%
3732% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003733% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003734% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003735% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003736%
3737% A description of each parameter follows:
3738%
3739% o image_info: the image info.
3740%
3741% o image: the image.
3742%
cristy6fccee12011-10-20 18:43:18 +00003743% o exception: return any errors or warnings in this structure.
3744%
cristy1626d332009-11-10 16:58:17 +00003745*/
3746
3747MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003748 Image *images,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003749{
3750 Image
3751 *image;
3752
3753 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003754 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003755 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003756 assert(images->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003757 if (images->debug != MagickFalse)
3758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3759 image=images;
3760 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
cristy6fccee12011-10-20 18:43:18 +00003761 (void) SyncImageSettings(image_info,image,exception);
cristy1626d332009-11-10 16:58:17 +00003762 (void) DeleteImageOption(image_info,"page");
3763 return(MagickTrue);
3764}
3765
3766MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003767 Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003768{
cristy1626d332009-11-10 16:58:17 +00003769 const char
cristy202c1482012-10-05 23:47:57 +00003770 *option;
cristy1626d332009-11-10 16:58:17 +00003771
3772 GeometryInfo
3773 geometry_info;
3774
3775 MagickStatusType
3776 flags;
3777
cristy19eb6412010-04-23 14:42:29 +00003778 ResolutionType
3779 units;
3780
cristy1626d332009-11-10 16:58:17 +00003781 /*
3782 Sync image options.
3783 */
3784 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003785 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003786 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003787 assert(image->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003788 if (image->debug != MagickFalse)
3789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
dirkb797b2c2016-02-01 22:20:32 +01003790 option=GetImageOption(image_info,"alpha-color");
3791 if (option != (const char *) NULL)
3792 (void) QueryColorCompliance(option,AllCompliance,&image->alpha_color,
3793 exception);
cristy1626d332009-11-10 16:58:17 +00003794 option=GetImageOption(image_info,"background");
3795 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003796 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
cristy6fccee12011-10-20 18:43:18 +00003797 exception);
cristy1626d332009-11-10 16:58:17 +00003798 option=GetImageOption(image_info,"black-point-compensation");
3799 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003800 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003801 MagickBooleanOptions,MagickFalse,option);
3802 option=GetImageOption(image_info,"blue-primary");
3803 if (option != (const char *) NULL)
3804 {
3805 flags=ParseGeometry(option,&geometry_info);
3806 image->chromaticity.blue_primary.x=geometry_info.rho;
3807 image->chromaticity.blue_primary.y=geometry_info.sigma;
3808 if ((flags & SigmaValue) == 0)
3809 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3810 }
3811 option=GetImageOption(image_info,"bordercolor");
3812 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003813 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
cristy6fccee12011-10-20 18:43:18 +00003814 exception);
anthony72feaa62012-01-17 06:46:23 +00003815 /* FUTURE: do not sync compose to per-image compose setting here */
cristy1626d332009-11-10 16:58:17 +00003816 option=GetImageOption(image_info,"compose");
3817 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003818 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00003819 MagickFalse,option);
anthony72feaa62012-01-17 06:46:23 +00003820 /* -- */
cristy1626d332009-11-10 16:58:17 +00003821 option=GetImageOption(image_info,"compress");
3822 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003823 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003824 MagickCompressOptions,MagickFalse,option);
3825 option=GetImageOption(image_info,"debug");
3826 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003827 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003828 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00003829 option=GetImageOption(image_info,"density");
3830 if (option != (const char *) NULL)
3831 {
cristydd5f5912010-07-31 23:37:23 +00003832 flags=ParseGeometry(option,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +00003833 image->resolution.x=geometry_info.rho;
3834 image->resolution.y=geometry_info.sigma;
cristydd5f5912010-07-31 23:37:23 +00003835 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +00003836 image->resolution.y=image->resolution.x;
cristydd5f5912010-07-31 23:37:23 +00003837 }
cristy1626d332009-11-10 16:58:17 +00003838 option=GetImageOption(image_info,"depth");
3839 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003840 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003841 option=GetImageOption(image_info,"endian");
3842 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003843 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00003844 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003845 option=GetImageOption(image_info,"filter");
3846 if (option != (const char *) NULL)
dirk8b9f21c2016-02-01 22:30:19 +01003847 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00003848 MagickFalse,option);
3849 option=GetImageOption(image_info,"fuzz");
3850 if (option != (const char *) NULL)
cristydbdd0e32011-11-04 23:29:40 +00003851 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
cristy1626d332009-11-10 16:58:17 +00003852 option=GetImageOption(image_info,"gravity");
3853 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003854 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00003855 MagickFalse,option);
3856 option=GetImageOption(image_info,"green-primary");
3857 if (option != (const char *) NULL)
3858 {
3859 flags=ParseGeometry(option,&geometry_info);
3860 image->chromaticity.green_primary.x=geometry_info.rho;
3861 image->chromaticity.green_primary.y=geometry_info.sigma;
3862 if ((flags & SigmaValue) == 0)
3863 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
3864 }
3865 option=GetImageOption(image_info,"intent");
3866 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003867 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003868 MagickIntentOptions,MagickFalse,option);
cristy313634e2013-03-26 00:52:19 +00003869 option=GetImageOption(image_info,"intensity");
3870 if (option != (const char *) NULL)
3871 image->intensity=(PixelIntensityMethod) ParseCommandOption(
3872 MagickPixelIntensityOptions,MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003873 option=GetImageOption(image_info,"interlace");
3874 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003875 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00003876 MagickFalse,option);
3877 option=GetImageOption(image_info,"interpolate");
3878 if (option != (const char *) NULL)
cristy5c4e2582011-09-11 19:21:03 +00003879 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003880 MagickInterpolateOptions,MagickFalse,option);
3881 option=GetImageOption(image_info,"loop");
3882 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003883 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003884 option=GetImageOption(image_info,"orient");
3885 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003886 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003887 MagickOrientationOptions,MagickFalse,option);
cristy14ed6a22013-12-28 23:48:05 +00003888 option=GetImageOption(image_info,"page");
3889 if (option != (const char *) NULL)
3890 {
3891 char
3892 *geometry;
3893
3894 geometry=GetPageGeometry(option);
3895 flags=ParseAbsoluteGeometry(geometry,&image->page);
3896 geometry=DestroyString(geometry);
3897 }
cristy1626d332009-11-10 16:58:17 +00003898 option=GetImageOption(image_info,"quality");
3899 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003900 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003901 option=GetImageOption(image_info,"red-primary");
3902 if (option != (const char *) NULL)
3903 {
3904 flags=ParseGeometry(option,&geometry_info);
3905 image->chromaticity.red_primary.x=geometry_info.rho;
3906 image->chromaticity.red_primary.y=geometry_info.sigma;
3907 if ((flags & SigmaValue) == 0)
3908 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
3909 }
3910 if (image_info->quality != UndefinedCompressionQuality)
3911 image->quality=image_info->quality;
3912 option=GetImageOption(image_info,"scene");
3913 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003914 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003915 option=GetImageOption(image_info,"taint");
3916 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003917 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003918 MagickFalse,option);
3919 option=GetImageOption(image_info,"tile-offset");
3920 if (option != (const char *) NULL)
3921 {
3922 char
3923 *geometry;
3924
3925 geometry=GetPageGeometry(option);
3926 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
3927 geometry=DestroyString(geometry);
3928 }
3929 option=GetImageOption(image_info,"transparent-color");
3930 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003931 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
cristy6fccee12011-10-20 18:43:18 +00003932 exception);
cristy1626d332009-11-10 16:58:17 +00003933 option=GetImageOption(image_info,"type");
3934 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003935 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00003936 option);
3937 option=GetImageOption(image_info,"units");
cristyc8d63672012-01-11 13:03:13 +00003938 units=image_info->units;
cristy1626d332009-11-10 16:58:17 +00003939 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003940 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00003941 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00003942 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00003943 {
cristy19eb6412010-04-23 14:42:29 +00003944 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00003945 switch (image->units)
3946 {
3947 case PixelsPerInchResolution:
3948 {
cristy19eb6412010-04-23 14:42:29 +00003949 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00003950 {
cristy2a11bef2011-10-28 18:33:11 +00003951 image->resolution.x/=2.54;
3952 image->resolution.y/=2.54;
cristy1626d332009-11-10 16:58:17 +00003953 }
3954 break;
3955 }
3956 case PixelsPerCentimeterResolution:
3957 {
cristy19eb6412010-04-23 14:42:29 +00003958 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00003959 {
cristy2a11bef2011-10-28 18:33:11 +00003960 image->resolution.x=(double) ((size_t) (100.0*2.54*
3961 image->resolution.x+0.5))/100.0;
3962 image->resolution.y=(double) ((size_t) (100.0*2.54*
3963 image->resolution.y+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00003964 }
3965 break;
3966 }
3967 default:
3968 break;
3969 }
cristy19eb6412010-04-23 14:42:29 +00003970 image->units=units;
cristy1626d332009-11-10 16:58:17 +00003971 }
anthonyfd706f92012-01-19 04:22:02 +00003972 option=GetImageOption(image_info,"virtual-pixel");
3973 if (option != (const char *) NULL)
cristy387430f2012-02-07 13:09:46 +00003974 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
3975 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
3976 exception);
cristy1626d332009-11-10 16:58:17 +00003977 option=GetImageOption(image_info,"white-point");
3978 if (option != (const char *) NULL)
3979 {
3980 flags=ParseGeometry(option,&geometry_info);
3981 image->chromaticity.white_point.x=geometry_info.rho;
3982 image->chromaticity.white_point.y=geometry_info.sigma;
3983 if ((flags & SigmaValue) == 0)
3984 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
3985 }
Cristy9c282cc2015-08-29 17:37:22 -04003986 /*
3987 Pointer to allow the lookup of pre-image artifact will fallback to a global
3988 option setting/define. This saves a lot of duplication of global options
3989 into per-image artifacts, while ensuring only specifically set per-image
3990 artifacts are preserved when parenthesis ends.
anthony643c6132012-11-07 14:50:28 +00003991 */
dirk98d3e1c2015-08-28 21:09:11 +02003992 if (image->image_info != (ImageInfo *) NULL)
3993 image->image_info=DestroyImageInfo(image->image_info);
Cristy36421ee2015-08-28 11:58:20 -04003994 image->image_info=CloneImageInfo(image_info);
cristy1626d332009-11-10 16:58:17 +00003995 return(MagickTrue);
3996}