blob: a7058da6b0ee0537f7fec66d34e5c3cc18c34e33 [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% %
Cristyf6ff9ea2016-12-05 09:53:35 -050020% Copyright 1999-2017 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"
Cristya739e8f2016-12-09 10:40:04 -050052#include "MagickCore/channel.h"
cristy4c08aed2011-07-01 19:47:50 +000053#include "MagickCore/client.h"
54#include "MagickCore/color.h"
55#include "MagickCore/color-private.h"
56#include "MagickCore/colormap.h"
57#include "MagickCore/colorspace.h"
58#include "MagickCore/colorspace-private.h"
59#include "MagickCore/composite.h"
60#include "MagickCore/composite-private.h"
61#include "MagickCore/compress.h"
62#include "MagickCore/constitute.h"
Cristy446b7ac2016-06-06 09:18:22 -040063#include "MagickCore/delegate.h"
cristy4c08aed2011-07-01 19:47:50 +000064#include "MagickCore/display.h"
65#include "MagickCore/draw.h"
66#include "MagickCore/enhance.h"
67#include "MagickCore/exception.h"
68#include "MagickCore/exception-private.h"
69#include "MagickCore/gem.h"
70#include "MagickCore/geometry.h"
71#include "MagickCore/histogram.h"
72#include "MagickCore/image-private.h"
73#include "MagickCore/list.h"
74#include "MagickCore/magic.h"
75#include "MagickCore/magick.h"
cristy7832dc22011-09-05 01:21:53 +000076#include "MagickCore/magick-private.h"
cristy4c08aed2011-07-01 19:47:50 +000077#include "MagickCore/memory_.h"
78#include "MagickCore/module.h"
79#include "MagickCore/monitor.h"
80#include "MagickCore/monitor-private.h"
81#include "MagickCore/option.h"
82#include "MagickCore/paint.h"
83#include "MagickCore/pixel-accessor.h"
84#include "MagickCore/profile.h"
85#include "MagickCore/property.h"
86#include "MagickCore/quantize.h"
87#include "MagickCore/random_.h"
cristyac245f82012-05-05 17:13:57 +000088#include "MagickCore/resource_.h"
cristy4c08aed2011-07-01 19:47:50 +000089#include "MagickCore/segment.h"
90#include "MagickCore/semaphore.h"
91#include "MagickCore/signature-private.h"
92#include "MagickCore/statistic.h"
93#include "MagickCore/string_.h"
94#include "MagickCore/string-private.h"
95#include "MagickCore/thread-private.h"
96#include "MagickCore/threshold.h"
97#include "MagickCore/timer.h"
cristy63a81872012-03-22 15:52:52 +000098#include "MagickCore/token.h"
cristy4c08aed2011-07-01 19:47:50 +000099#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +0000100#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +0000101#include "MagickCore/version.h"
102#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +0000103
104/*
105 Constant declaration.
106*/
cristy94b11832011-09-08 19:46:03 +0000107const char
dirkb797b2c2016-02-01 22:20:32 +0100108 AlphaColor[] = "#bdbdbd", /* gray */
cristy7138c592009-09-08 13:58:52 +0000109 BackgroundColor[] = "#ffffff", /* white */
110 BorderColor[] = "#dfdfdf", /* gray */
cristy9639ba32011-09-05 15:09:42 +0000111 DefaultTileFrame[] = "15x15+3+3",
cristy7138c592009-09-08 13:58:52 +0000112 DefaultTileGeometry[] = "120x120+4+3>",
113 DefaultTileLabel[] = "%f\n%G\n%b",
cristy94b11832011-09-08 19:46:03 +0000114 ForegroundColor[] = "#000", /* black */
cristy7138c592009-09-08 13:58:52 +0000115 LoadImageTag[] = "Load/Image",
116 LoadImagesTag[] = "Load/Images",
cristy7138c592009-09-08 13:58:52 +0000117 PSDensityGeometry[] = "72.0x72.0",
118 PSPageGeometry[] = "612x792",
119 SaveImageTag[] = "Save/Image",
120 SaveImagesTag[] = "Save/Images",
121 TransparentColor[] = "#00000000"; /* transparent black */
cristy3ed852e2009-09-05 21:47:34 +0000122
cristy94b11832011-09-08 19:46:03 +0000123const double
cristy3ed852e2009-09-05 21:47:34 +0000124 DefaultResolution = 72.0;
125
126/*
127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128% %
129% %
130% %
131% A c q u i r e I m a g e %
132% %
133% %
134% %
135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136%
137% AcquireImage() returns a pointer to an image structure initialized to
138% default values.
139%
140% The format of the AcquireImage method is:
141%
cristy9950d572011-10-01 18:22:35 +0000142% Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000143%
144% A description of each parameter follows:
145%
146% o image_info: Many of the image default values are set from this
147% structure. For example, filename, compression, depth, background color,
148% and others.
149%
cristy9950d572011-10-01 18:22:35 +0000150% o exception: return any errors or warnings in this structure.
151%
cristy3ed852e2009-09-05 21:47:34 +0000152*/
cristy9950d572011-10-01 18:22:35 +0000153MagickExport Image *AcquireImage(const ImageInfo *image_info,
154 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000155{
cristye412c892010-07-26 12:31:36 +0000156 const char
cristyf3a660a2010-07-26 14:17:52 +0000157 *option;
cristye412c892010-07-26 12:31:36 +0000158
cristy3ed852e2009-09-05 21:47:34 +0000159 Image
160 *image;
161
162 MagickStatusType
163 flags;
164
165 /*
166 Allocate image structure.
167 */
168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy73bd4a52010-10-05 11:24:23 +0000169 image=(Image *) AcquireMagickMemory(sizeof(*image));
cristy3ed852e2009-09-05 21:47:34 +0000170 if (image == (Image *) NULL)
171 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
172 (void) ResetMagickMemory(image,0,sizeof(*image));
173 /*
174 Initialize Image structure.
175 */
cristy151b66d2015-04-15 10:50:31 +0000176 (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000177 image->storage_class=DirectClass;
178 image->depth=MAGICKCORE_QUANTUM_DEPTH;
cristy8d951092012-02-08 18:54:56 +0000179 image->colorspace=sRGBColorspace;
cristye540eb42012-04-16 12:50:34 +0000180 image->rendering_intent=PerceptualIntent;
cristy6b221892012-05-03 01:21:35 +0000181 image->gamma=1.000f/2.200f;
182 image->chromaticity.red_primary.x=0.6400f;
183 image->chromaticity.red_primary.y=0.3300f;
cristyf767ec92012-05-03 01:27:21 +0000184 image->chromaticity.red_primary.z=0.0300f;
cristy6b221892012-05-03 01:21:35 +0000185 image->chromaticity.green_primary.x=0.3000f;
186 image->chromaticity.green_primary.y=0.6000f;
cristyf767ec92012-05-03 01:27:21 +0000187 image->chromaticity.green_primary.z=0.1000f;
cristy6b221892012-05-03 01:21:35 +0000188 image->chromaticity.blue_primary.x=0.1500f;
189 image->chromaticity.blue_primary.y=0.0600f;
cristyf767ec92012-05-03 01:27:21 +0000190 image->chromaticity.blue_primary.z=0.7900f;
cristy6b221892012-05-03 01:21:35 +0000191 image->chromaticity.white_point.x=0.3127f;
192 image->chromaticity.white_point.y=0.3290f;
cristyf767ec92012-05-03 01:27:21 +0000193 image->chromaticity.white_point.z=0.3583f;
cristy3ed852e2009-09-05 21:47:34 +0000194 image->interlace=NoInterlace;
195 image->ticks_per_second=UndefinedTicksPerSecond;
196 image->compose=OverCompositeOp;
dirkb797b2c2016-02-01 22:20:32 +0100197 (void) QueryColorCompliance(AlphaColor,AllCompliance,&image->alpha_color,
198 exception);
cristy9950d572011-10-01 18:22:35 +0000199 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
200 &image->background_color,exception);
201 (void) QueryColorCompliance(BorderColor,AllCompliance,&image->border_color,
202 exception);
cristy9950d572011-10-01 18:22:35 +0000203 (void) QueryColorCompliance(TransparentColor,AllCompliance,
204 &image->transparent_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000205 GetTimerInfo(&image->timer);
206 image->cache=AcquirePixelCache(0);
cristybd5a96c2011-08-21 00:04:26 +0000207 image->channel_mask=DefaultChannels;
cristyed231572011-07-14 02:18:59 +0000208 image->channel_map=AcquirePixelChannelMap();
cristy3ed852e2009-09-05 21:47:34 +0000209 image->blob=CloneBlobInfo((BlobInfo *) NULL);
cristybd686c62013-02-03 19:01:05 +0000210 image->timestamp=time((time_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000211 image->debug=IsEventLogging();
212 image->reference_count=1;
cristy3d162a92014-02-16 14:05:06 +0000213 image->semaphore=AcquireSemaphoreInfo();
cristye1c94d92015-06-28 12:16:33 +0000214 image->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +0000215 if (image_info == (ImageInfo *) NULL)
216 return(image);
217 /*
218 Transfer image info.
219 */
220 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
221 MagickFalse);
cristyee2f5d62015-07-28 13:19:43 +0000222 (void) CopyMagickString(image->filename,image_info->filename,
223 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000224 (void) CopyMagickString(image->magick_filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +0000225 MagickPathExtent);
226 (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000227 if (image_info->size != (char *) NULL)
228 {
229 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
230 image->columns=image->extract_info.width;
231 image->rows=image->extract_info.height;
232 image->offset=image->extract_info.x;
233 image->extract_info.x=0;
234 image->extract_info.y=0;
235 }
236 if (image_info->extract != (char *) NULL)
237 {
238 RectangleInfo
239 geometry;
240
241 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
242 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
243 {
244 image->extract_info=geometry;
245 Swap(image->columns,image->extract_info.width);
246 Swap(image->rows,image->extract_info.height);
247 }
248 }
249 image->compression=image_info->compression;
250 image->quality=image_info->quality;
251 image->endian=image_info->endian;
252 image->interlace=image_info->interlace;
253 image->units=image_info->units;
254 if (image_info->density != (char *) NULL)
255 {
256 GeometryInfo
257 geometry_info;
258
259 flags=ParseGeometry(image_info->density,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000260 image->resolution.x=geometry_info.rho;
261 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000262 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000263 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000264 }
265 if (image_info->page != (char *) NULL)
266 {
267 char
268 *geometry;
269
270 image->page=image->extract_info;
271 geometry=GetPageGeometry(image_info->page);
272 (void) ParseAbsoluteGeometry(geometry,&image->page);
273 geometry=DestroyString(geometry);
274 }
275 if (image_info->depth != 0)
276 image->depth=image_info->depth;
277 image->dither=image_info->dither;
dirkb797b2c2016-02-01 22:20:32 +0100278 image->alpha_color=image_info->alpha_color;
cristy3ed852e2009-09-05 21:47:34 +0000279 image->background_color=image_info->background_color;
280 image->border_color=image_info->border_color;
cristy3ed852e2009-09-05 21:47:34 +0000281 image->transparent_color=image_info->transparent_color;
cristy73724512010-04-12 14:43:14 +0000282 image->ping=image_info->ping;
cristy3ed852e2009-09-05 21:47:34 +0000283 image->progress_monitor=image_info->progress_monitor;
284 image->client_data=image_info->client_data;
285 if (image_info->cache != (void *) NULL)
286 ClonePixelCacheMethods(image->cache,image_info->cache);
cristy1a780952013-02-10 17:15:30 +0000287 /*
288 Set all global options that map to per-image settings.
289 */
cristy6fccee12011-10-20 18:43:18 +0000290 (void) SyncImageSettings(image_info,image,exception);
cristy1a780952013-02-10 17:15:30 +0000291 /*
292 Global options that are only set for new images.
293 */
cristye412c892010-07-26 12:31:36 +0000294 option=GetImageOption(image_info,"delay");
295 if (option != (const char *) NULL)
296 {
297 GeometryInfo
298 geometry_info;
299
300 flags=ParseGeometry(option,&geometry_info);
301 if ((flags & GreaterValue) != 0)
302 {
303 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
304 image->delay=(size_t) floor(geometry_info.rho+0.5);
305 }
306 else
307 if ((flags & LessValue) != 0)
308 {
309 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
310 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
311 }
312 else
313 image->delay=(size_t) floor(geometry_info.rho+0.5);
314 if ((flags & SigmaValue) != 0)
315 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
316 }
317 option=GetImageOption(image_info,"dispose");
318 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000319 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
cristye412c892010-07-26 12:31:36 +0000320 MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000321 return(image);
322}
323
324/*
325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326% %
327% %
328% %
cristy3ed852e2009-09-05 21:47:34 +0000329% A c q u i r e I m a g e I n f o %
330% %
331% %
332% %
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334%
335% AcquireImageInfo() allocates the ImageInfo structure.
336%
337% The format of the AcquireImageInfo method is:
338%
339% ImageInfo *AcquireImageInfo(void)
340%
341*/
342MagickExport ImageInfo *AcquireImageInfo(void)
343{
344 ImageInfo
345 *image_info;
346
cristy73bd4a52010-10-05 11:24:23 +0000347 image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
cristy3ed852e2009-09-05 21:47:34 +0000348 if (image_info == (ImageInfo *) NULL)
349 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
350 GetImageInfo(image_info);
351 return(image_info);
352}
353
354/*
355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356% %
357% %
358% %
359% A c q u i r e N e x t I m a g e %
360% %
361% %
362% %
363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364%
365% AcquireNextImage() initializes the next image in a sequence to
366% default values. The next member of image points to the newly allocated
367% image. If there is a memory shortage, next is assigned NULL.
368%
369% The format of the AcquireNextImage method is:
370%
cristy9950d572011-10-01 18:22:35 +0000371% void AcquireNextImage(const ImageInfo *image_info,Image *image,
372% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000373%
374% A description of each parameter follows:
375%
376% o image_info: Many of the image default values are set from this
377% structure. For example, filename, compression, depth, background color,
378% and others.
379%
380% o image: the image.
381%
cristy9950d572011-10-01 18:22:35 +0000382% o exception: return any errors or warnings in this structure.
383%
cristy3ed852e2009-09-05 21:47:34 +0000384*/
cristy9950d572011-10-01 18:22:35 +0000385MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
386 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000387{
388 /*
389 Allocate image structure.
390 */
391 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000392 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000393 if (image->debug != MagickFalse)
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy9950d572011-10-01 18:22:35 +0000395 image->next=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000396 if (GetNextImageInList(image) == (Image *) NULL)
397 return;
398 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
cristy151b66d2015-04-15 10:50:31 +0000399 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000400 if (image_info != (ImageInfo *) NULL)
401 (void) CopyMagickString(GetNextImageInList(image)->filename,
cristy151b66d2015-04-15 10:50:31 +0000402 image_info->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000403 DestroyBlob(GetNextImageInList(image));
404 image->next->blob=ReferenceBlob(image->blob);
405 image->next->endian=image->endian;
406 image->next->scene=image->scene+1;
407 image->next->previous=image;
408}
409
410/*
411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412% %
413% %
414% %
415% A p p e n d I m a g e s %
416% %
417% %
418% %
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420%
421% AppendImages() takes all images from the current image pointer to the end
422% of the image list and appends them to each other top-to-bottom if the
423% stack parameter is true, otherwise left-to-right.
424%
anthony7bcfe7f2012-03-30 14:01:22 +0000425% The current gravity setting effects how the image is justified in the
cristy3ed852e2009-09-05 21:47:34 +0000426% final image.
427%
428% The format of the AppendImages method is:
429%
cristy4ca38e22011-02-10 02:57:49 +0000430% Image *AppendImages(const Image *images,const MagickBooleanType stack,
cristy3ed852e2009-09-05 21:47:34 +0000431% ExceptionInfo *exception)
432%
433% A description of each parameter follows:
434%
cristy4ca38e22011-02-10 02:57:49 +0000435% o images: the image sequence.
cristy3ed852e2009-09-05 21:47:34 +0000436%
437% o stack: A value other than 0 stacks the images top-to-bottom.
438%
439% o exception: return any errors or warnings in this structure.
440%
441*/
cristy4ca38e22011-02-10 02:57:49 +0000442MagickExport Image *AppendImages(const Image *images,
cristy3ed852e2009-09-05 21:47:34 +0000443 const MagickBooleanType stack,ExceptionInfo *exception)
444{
445#define AppendImageTag "Append/Image"
446
447 CacheView
cristyeeebdde2012-04-14 16:29:34 +0000448 *append_view;
cristy4ca38e22011-02-10 02:57:49 +0000449
cristy3ed852e2009-09-05 21:47:34 +0000450 Image
451 *append_image;
452
cristy3ed852e2009-09-05 21:47:34 +0000453 MagickBooleanType
Cristyefe9ade2016-12-07 18:11:51 -0500454 homogeneous_colorspace,
cristy3ed852e2009-09-05 21:47:34 +0000455 status;
456
cristybb503372010-05-27 20:51:26 +0000457 MagickOffsetType
458 n;
459
cristy5a5e4d92012-08-29 00:06:25 +0000460 PixelTrait
461 alpha_trait;
462
cristy3ed852e2009-09-05 21:47:34 +0000463 RectangleInfo
464 geometry;
465
466 register const Image
467 *next;
468
cristybb503372010-05-27 20:51:26 +0000469 size_t
Cristya38b4562015-12-28 08:47:22 -0500470 depth,
cristy3ed852e2009-09-05 21:47:34 +0000471 height,
472 number_images,
473 width;
474
cristybb503372010-05-27 20:51:26 +0000475 ssize_t
476 x_offset,
477 y,
478 y_offset;
479
cristy3ed852e2009-09-05 21:47:34 +0000480 /*
cristy7c6dc152011-02-11 14:10:55 +0000481 Compute maximum area of appended area.
cristy3ed852e2009-09-05 21:47:34 +0000482 */
cristy4ca38e22011-02-10 02:57:49 +0000483 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000484 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +0000485 if (images->debug != MagickFalse)
486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy3ed852e2009-09-05 21:47:34 +0000487 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000488 assert(exception->signature == MagickCoreSignature);
cristy5a5e4d92012-08-29 00:06:25 +0000489 alpha_trait=images->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +0000490 number_images=1;
cristyeeebdde2012-04-14 16:29:34 +0000491 width=images->columns;
492 height=images->rows;
Cristya38b4562015-12-28 08:47:22 -0500493 depth=images->depth;
Cristyefe9ade2016-12-07 18:11:51 -0500494 homogeneous_colorspace=MagickTrue;
cristyeeebdde2012-04-14 16:29:34 +0000495 next=GetNextImageInList(images);
cristy3ed852e2009-09-05 21:47:34 +0000496 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
497 {
Cristya38b4562015-12-28 08:47:22 -0500498 if (next->depth > depth)
499 depth=next->depth;
Cristyefe9ade2016-12-07 18:11:51 -0500500 if (next->colorspace != images->colorspace)
501 homogeneous_colorspace=MagickFalse;
cristy17f11b02014-12-20 19:37:04 +0000502 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +0000503 alpha_trait=BlendPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000504 number_images++;
505 if (stack != MagickFalse)
506 {
507 if (next->columns > width)
508 width=next->columns;
509 height+=next->rows;
510 continue;
511 }
512 width+=next->columns;
513 if (next->rows > height)
514 height=next->rows;
515 }
516 /*
cristy7c6dc152011-02-11 14:10:55 +0000517 Append images.
cristy3ed852e2009-09-05 21:47:34 +0000518 */
cristyeeebdde2012-04-14 16:29:34 +0000519 append_image=CloneImage(images,width,height,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000520 if (append_image == (Image *) NULL)
521 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +0000522 if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000523 {
cristy3ed852e2009-09-05 21:47:34 +0000524 append_image=DestroyImage(append_image);
525 return((Image *) NULL);
526 }
Cristyefe9ade2016-12-07 18:11:51 -0500527 if (homogeneous_colorspace == MagickFalse)
528 (void) SetImageColorspace(append_image,sRGBColorspace,exception);
Cristya38b4562015-12-28 08:47:22 -0500529 append_image->depth=depth;
cristy5a5e4d92012-08-29 00:06:25 +0000530 append_image->alpha_trait=alpha_trait;
Cristy02b01702016-12-21 16:50:36 -0500531 append_image->page=images->page;
cristyea1a8aa2011-10-20 13:24:06 +0000532 (void) SetImageBackgroundColor(append_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000533 status=MagickTrue;
534 x_offset=0;
535 y_offset=0;
cristyeeebdde2012-04-14 16:29:34 +0000536 next=images;
cristy46ff2672012-12-14 15:32:26 +0000537 append_view=AcquireAuthenticCacheView(append_image,exception);
cristybb503372010-05-27 20:51:26 +0000538 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000539 {
cristyeeebdde2012-04-14 16:29:34 +0000540 CacheView
541 *image_view;
542
cristy9eed59f2013-02-19 15:26:48 +0000543 MagickBooleanType
544 proceed;
545
cristy3ed852e2009-09-05 21:47:34 +0000546 SetGeometry(append_image,&geometry);
Cristyc1e19262016-02-05 07:54:16 -0500547 GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
cristy3ed852e2009-09-05 21:47:34 +0000548 if (stack != MagickFalse)
549 x_offset-=geometry.x;
550 else
551 y_offset-=geometry.y;
Cristyc1e19262016-02-05 07:54:16 -0500552 image_view=AcquireVirtualCacheView(next,exception);
cristyb5d5f722009-11-04 03:03:49 +0000553#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000554 #pragma omp parallel for schedule(static,4) shared(status) \
Cristyc1e19262016-02-05 07:54:16 -0500555 magick_threads(next,next,next->rows,1)
cristy3ed852e2009-09-05 21:47:34 +0000556#endif
Cristyc1e19262016-02-05 07:54:16 -0500557 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000558 {
559 MagickBooleanType
560 sync;
561
cristye14e3202012-04-11 18:48:17 +0000562 PixelInfo
563 pixel;
564
cristy4c08aed2011-07-01 19:47:50 +0000565 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +0100566 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000567
cristy4c08aed2011-07-01 19:47:50 +0000568 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100569 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000570
cristycb6d09b2010-06-19 01:59:36 +0000571 register ssize_t
572 x;
573
cristy3ed852e2009-09-05 21:47:34 +0000574 if (status == MagickFalse)
575 continue;
Cristyc1e19262016-02-05 07:54:16 -0500576 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000577 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
Cristyc1e19262016-02-05 07:54:16 -0500578 next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000579 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000580 {
581 status=MagickFalse;
582 continue;
583 }
Cristyc1e19262016-02-05 07:54:16 -0500584 GetPixelInfo(next,&pixel);
585 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000586 {
Cristydf5e8b12016-12-02 17:26:39 -0500587 if (GetPixelWriteMask(next,p) == 0)
cristy10a6c612012-01-29 21:41:05 +0000588 {
cristyc3a58022013-10-09 23:22:42 +0000589 SetPixelBackgoundColor(append_image,q);
Cristyc1e19262016-02-05 07:54:16 -0500590 p+=GetPixelChannels(next);
cristy10a6c612012-01-29 21:41:05 +0000591 q+=GetPixelChannels(append_image);
592 continue;
593 }
Cristyc1e19262016-02-05 07:54:16 -0500594 GetPixelInfoPixel(next,p,&pixel);
cristy11a06d32015-01-04 12:03:27 +0000595 SetPixelViaPixelInfo(append_image,&pixel,q);
Cristyc1e19262016-02-05 07:54:16 -0500596 p+=GetPixelChannels(next);
cristyed231572011-07-14 02:18:59 +0000597 q+=GetPixelChannels(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000598 }
599 sync=SyncCacheViewAuthenticPixels(append_view,exception);
600 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000601 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000602 }
603 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000604 if (stack == MagickFalse)
605 {
Cristyc1e19262016-02-05 07:54:16 -0500606 x_offset+=(ssize_t) next->columns;
cristy3ed852e2009-09-05 21:47:34 +0000607 y_offset=0;
608 }
609 else
610 {
611 x_offset=0;
Cristyc1e19262016-02-05 07:54:16 -0500612 y_offset+=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000613 }
cristyeeebdde2012-04-14 16:29:34 +0000614 proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
615 if (proceed == MagickFalse)
616 break;
617 next=GetNextImageInList(next);
cristy3ed852e2009-09-05 21:47:34 +0000618 }
619 append_view=DestroyCacheView(append_view);
620 if (status == MagickFalse)
621 append_image=DestroyImage(append_image);
622 return(append_image);
623}
624
625/*
626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627% %
628% %
629% %
cristy3ed852e2009-09-05 21:47:34 +0000630% C a t c h I m a g e E x c e p t i o n %
631% %
632% %
633% %
634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635%
636% CatchImageException() returns if no exceptions are found in the image
637% sequence, otherwise it determines the most severe exception and reports
638% it as a warning or error depending on the severity.
639%
640% The format of the CatchImageException method is:
641%
642% ExceptionType CatchImageException(Image *image)
643%
644% A description of each parameter follows:
645%
646% o image: An image sequence.
647%
648*/
649MagickExport ExceptionType CatchImageException(Image *image)
650{
651 ExceptionInfo
652 *exception;
653
654 ExceptionType
655 severity;
656
657 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000658 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000659 if (image->debug != MagickFalse)
660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
661 exception=AcquireExceptionInfo();
cristy3ed852e2009-09-05 21:47:34 +0000662 CatchException(exception);
663 severity=exception->severity;
664 exception=DestroyExceptionInfo(exception);
665 return(severity);
666}
667
668/*
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670% %
671% %
672% %
673% C l i p I m a g e P a t h %
674% %
675% %
676% %
677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678%
679% ClipImagePath() sets the image clip mask based any clipping path information
680% if it exists.
681%
682% The format of the ClipImagePath method is:
683%
684% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000685% const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000686%
687% A description of each parameter follows:
688%
689% o image: the image.
690%
691% o pathname: name of clipping path resource. If name is preceded by #, use
692% clipping path numbered by name.
693%
694% o inside: if non-zero, later operations take effect inside clipping path.
695% Otherwise later operations take effect outside clipping path.
696%
cristy018f07f2011-09-04 21:15:19 +0000697% o exception: return any errors or warnings in this structure.
698%
cristy3ed852e2009-09-05 21:47:34 +0000699*/
700
cristy018f07f2011-09-04 21:15:19 +0000701MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000702{
cristy018f07f2011-09-04 21:15:19 +0000703 return(ClipImagePath(image,"#1",MagickTrue,exception));
cristy3ed852e2009-09-05 21:47:34 +0000704}
705
706MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000707 const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000708{
709#define ClipImagePathTag "ClipPath/Image"
710
711 char
712 *property;
713
714 const char
715 *value;
716
717 Image
718 *clip_mask;
719
720 ImageInfo
721 *image_info;
722
723 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000724 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000725 if (image->debug != MagickFalse)
726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
727 assert(pathname != NULL);
728 property=AcquireString(pathname);
cristy151b66d2015-04-15 10:50:31 +0000729 (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000730 pathname);
cristyd15e6592011-10-15 00:13:06 +0000731 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +0000732 property=DestroyString(property);
733 if (value == (const char *) NULL)
734 {
cristy6fccee12011-10-20 18:43:18 +0000735 ThrowFileException(exception,OptionError,"NoClipPathDefined",
cristy3ed852e2009-09-05 21:47:34 +0000736 image->filename);
737 return(MagickFalse);
738 }
739 image_info=AcquireImageInfo();
cristyee2f5d62015-07-28 13:19:43 +0000740 (void) CopyMagickString(image_info->filename,image->filename,
741 MagickPathExtent);
742 (void) ConcatenateMagickString(image_info->filename,pathname,
743 MagickPathExtent);
cristy6fccee12011-10-20 18:43:18 +0000744 clip_mask=BlobToImage(image_info,value,strlen(value),exception);
cristy3ed852e2009-09-05 21:47:34 +0000745 image_info=DestroyImageInfo(image_info);
746 if (clip_mask == (Image *) NULL)
747 return(MagickFalse);
748 if (clip_mask->storage_class == PseudoClass)
749 {
cristyea1a8aa2011-10-20 13:24:06 +0000750 (void) SyncImage(clip_mask,exception);
cristy6fccee12011-10-20 18:43:18 +0000751 if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000752 return(MagickFalse);
753 }
754 if (inside == MagickFalse)
cristy6fccee12011-10-20 18:43:18 +0000755 (void) NegateImage(clip_mask,MagickFalse,exception);
cristy151b66d2015-04-15 10:50:31 +0000756 (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000757 "8BIM:1999,2998:%s\nPS",pathname);
Cristy4da63352016-12-03 08:59:32 -0500758 (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
cristy3ed852e2009-09-05 21:47:34 +0000759 clip_mask=DestroyImage(clip_mask);
760 return(MagickTrue);
761}
762
763/*
764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765% %
766% %
767% %
768% C l o n e I m a g e %
769% %
770% %
771% %
772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773%
774% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000775%
cristy3ed852e2009-09-05 21:47:34 +0000776% If the specified columns and rows is 0, an exact copy of the image is
777% returned, otherwise the pixel data is undefined and must be initialized
778% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
779% failure, a NULL image is returned and exception describes the reason for the
780% failure.
781%
782% The format of the CloneImage method is:
783%
cristybb503372010-05-27 20:51:26 +0000784% Image *CloneImage(const Image *image,const size_t columns,
785% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000786% ExceptionInfo *exception)
787%
788% A description of each parameter follows:
789%
790% o image: the image.
791%
792% o columns: the number of columns in the cloned image.
793%
794% o rows: the number of rows in the cloned image.
795%
796% o detach: With a value other than 0, the cloned image is detached from
797% its parent I/O stream.
798%
799% o exception: return any errors or warnings in this structure.
800%
801*/
cristybb503372010-05-27 20:51:26 +0000802MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000803 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000804{
805 Image
806 *clone_image;
807
cristya19f1d72012-08-07 18:24:38 +0000808 double
cristy3ed852e2009-09-05 21:47:34 +0000809 scale;
810
811 size_t
812 length;
813
814 /*
815 Clone the image.
816 */
817 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000818 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000819 if (image->debug != MagickFalse)
820 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
821 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000822 assert(exception->signature == MagickCoreSignature);
cristybe1cfca2014-10-21 14:00:29 +0000823 if ((image->columns == 0) || (image->rows == 0))
824 {
825 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
826 "NegativeOrZeroImageSize","`%s'",image->filename);
827 return((Image *) NULL);
828 }
cristy73bd4a52010-10-05 11:24:23 +0000829 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000830 if (clone_image == (Image *) NULL)
831 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
832 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
cristye1c94d92015-06-28 12:16:33 +0000833 clone_image->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +0000834 clone_image->storage_class=image->storage_class;
cristyed231572011-07-14 02:18:59 +0000835 clone_image->number_channels=image->number_channels;
cristyb3a73b52011-07-26 01:34:43 +0000836 clone_image->number_meta_channels=image->number_meta_channels;
cristy4c08aed2011-07-01 19:47:50 +0000837 clone_image->metacontent_extent=image->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +0000838 clone_image->colorspace=image->colorspace;
cristy883fde12013-04-08 00:50:13 +0000839 clone_image->read_mask=image->read_mask;
840 clone_image->write_mask=image->write_mask;
cristy8a46d822012-08-28 23:32:39 +0000841 clone_image->alpha_trait=image->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +0000842 clone_image->columns=image->columns;
843 clone_image->rows=image->rows;
844 clone_image->dither=image->dither;
cristy101ab702011-10-13 13:06:32 +0000845 if (image->colormap != (PixelInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000846 {
847 /*
848 Allocate and copy the image colormap.
849 */
850 clone_image->colors=image->colors;
851 length=(size_t) image->colors;
cristy101ab702011-10-13 13:06:32 +0000852 clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length,
cristy3ed852e2009-09-05 21:47:34 +0000853 sizeof(*clone_image->colormap));
cristy101ab702011-10-13 13:06:32 +0000854 if (clone_image->colormap == (PixelInfo *) NULL)
Cristyaecd0ad2016-05-16 16:05:02 -0400855 {
856 clone_image=DestroyImage(clone_image);
857 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
858 }
cristy3ed852e2009-09-05 21:47:34 +0000859 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
860 sizeof(*clone_image->colormap));
861 }
Cristy36421ee2015-08-28 11:58:20 -0400862 clone_image->image_info=CloneImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +0000863 (void) CloneImageProfiles(clone_image,image);
864 (void) CloneImageProperties(clone_image,image);
865 (void) CloneImageArtifacts(clone_image,image);
866 GetTimerInfo(&clone_image->timer);
cristy3ed852e2009-09-05 21:47:34 +0000867 if (image->ascii85 != (void *) NULL)
868 Ascii85Initialize(clone_image);
869 clone_image->magick_columns=image->magick_columns;
870 clone_image->magick_rows=image->magick_rows;
871 clone_image->type=image->type;
cristy636dcb52011-08-26 13:23:49 +0000872 clone_image->channel_mask=image->channel_mask;
cristyed231572011-07-14 02:18:59 +0000873 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +0000874 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
cristy151b66d2015-04-15 10:50:31 +0000875 MagickPathExtent);
876 (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
cristy25baba02015-07-28 00:36:29 +0000877 (void) CopyMagickString(clone_image->filename,image->filename,
878 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000879 clone_image->progress_monitor=image->progress_monitor;
880 clone_image->client_data=image->client_data;
881 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000882 clone_image->next=image->next;
883 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000884 clone_image->list=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +0000885 if (detach == MagickFalse)
886 clone_image->blob=ReferenceBlob(image->blob);
887 else
cristybee00932011-01-15 20:28:27 +0000888 {
889 clone_image->next=NewImageList();
890 clone_image->previous=NewImageList();
891 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
892 }
cristy73724512010-04-12 14:43:14 +0000893 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000894 clone_image->debug=IsEventLogging();
cristy3d162a92014-02-16 14:05:06 +0000895 clone_image->semaphore=AcquireSemaphoreInfo();
cristy58a749e2014-05-25 17:36:53 +0000896 if ((columns == 0) || (rows == 0))
cristy3ed852e2009-09-05 21:47:34 +0000897 {
898 if (image->montage != (char *) NULL)
899 (void) CloneString(&clone_image->montage,image->montage);
900 if (image->directory != (char *) NULL)
901 (void) CloneString(&clone_image->directory,image->directory);
cristy3ed852e2009-09-05 21:47:34 +0000902 clone_image->cache=ReferencePixelCache(image->cache);
903 return(clone_image);
904 }
cristy51d26762014-05-26 01:29:41 +0000905 scale=1.0;
906 if (image->columns != 0)
907 scale=(double) columns/(double) image->columns;
cristybb503372010-05-27 20:51:26 +0000908 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
Cristy02b01702016-12-21 16:50:36 -0500909 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
910 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy51d26762014-05-26 01:29:41 +0000911 scale=1.0;
912 if (image->rows != 0)
cristyee2f5d62015-07-28 13:19:43 +0000913 scale=(double) rows/(double) image->rows;
cristybb503372010-05-27 20:51:26 +0000914 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
Cristy02b01702016-12-21 16:50:36 -0500915 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
916 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000917 clone_image->cache=ClonePixelCache(image->cache);
Cristy5777d242016-06-16 16:58:13 -0400918 if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
919 clone_image=DestroyImage(clone_image);
cristy3ed852e2009-09-05 21:47:34 +0000920 return(clone_image);
921}
922
923/*
924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925% %
926% %
927% %
928% C l o n e I m a g e I n f o %
929% %
930% %
931% %
932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933%
934% CloneImageInfo() makes a copy of the given image info structure. If
935% NULL is specified, a new image info structure is created initialized to
936% default values.
937%
938% The format of the CloneImageInfo method is:
939%
940% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
941%
942% A description of each parameter follows:
943%
944% o image_info: the image info.
945%
946*/
947MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
948{
949 ImageInfo
950 *clone_info;
951
952 clone_info=AcquireImageInfo();
953 if (image_info == (ImageInfo *) NULL)
954 return(clone_info);
955 clone_info->compression=image_info->compression;
956 clone_info->temporary=image_info->temporary;
957 clone_info->adjoin=image_info->adjoin;
958 clone_info->antialias=image_info->antialias;
959 clone_info->scene=image_info->scene;
960 clone_info->number_scenes=image_info->number_scenes;
961 clone_info->depth=image_info->depth;
anthony72feaa62012-01-17 06:46:23 +0000962 (void) CloneString(&clone_info->size,image_info->size);
963 (void) CloneString(&clone_info->extract,image_info->extract);
964 (void) CloneString(&clone_info->scenes,image_info->scenes);
965 (void) CloneString(&clone_info->page,image_info->page);
cristy3ed852e2009-09-05 21:47:34 +0000966 clone_info->interlace=image_info->interlace;
967 clone_info->endian=image_info->endian;
968 clone_info->units=image_info->units;
969 clone_info->quality=image_info->quality;
anthony72feaa62012-01-17 06:46:23 +0000970 (void) CloneString(&clone_info->sampling_factor,image_info->sampling_factor);
971 (void) CloneString(&clone_info->server_name,image_info->server_name);
972 (void) CloneString(&clone_info->font,image_info->font);
973 (void) CloneString(&clone_info->texture,image_info->texture);
974 (void) CloneString(&clone_info->density,image_info->density);
cristy3ed852e2009-09-05 21:47:34 +0000975 clone_info->pointsize=image_info->pointsize;
976 clone_info->fuzz=image_info->fuzz;
dirkb797b2c2016-02-01 22:20:32 +0100977 clone_info->alpha_color=image_info->alpha_color;
cristy3ed852e2009-09-05 21:47:34 +0000978 clone_info->background_color=image_info->background_color;
979 clone_info->border_color=image_info->border_color;
cristy3ed852e2009-09-05 21:47:34 +0000980 clone_info->transparent_color=image_info->transparent_color;
981 clone_info->dither=image_info->dither;
982 clone_info->monochrome=image_info->monochrome;
cristy3ed852e2009-09-05 21:47:34 +0000983 clone_info->colorspace=image_info->colorspace;
984 clone_info->type=image_info->type;
985 clone_info->orientation=image_info->orientation;
cristy3ed852e2009-09-05 21:47:34 +0000986 clone_info->ping=image_info->ping;
987 clone_info->verbose=image_info->verbose;
cristy3ed852e2009-09-05 21:47:34 +0000988 clone_info->progress_monitor=image_info->progress_monitor;
989 clone_info->client_data=image_info->client_data;
990 clone_info->cache=image_info->cache;
991 if (image_info->cache != (void *) NULL)
992 clone_info->cache=ReferencePixelCache(image_info->cache);
993 if (image_info->profile != (void *) NULL)
994 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
995 image_info->profile);
996 SetImageInfoFile(clone_info,image_info->file);
997 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
998 clone_info->stream=image_info->stream;
Cristy93452f02017-02-01 09:23:15 -0500999 clone_info->custom_stream=image_info->custom_stream;
cristy957f2612015-06-21 23:51:58 +00001000 (void) CopyMagickString(clone_info->magick,image_info->magick,
1001 MagickPathExtent);
1002 (void) CopyMagickString(clone_info->unique,image_info->unique,
1003 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001004 (void) CopyMagickString(clone_info->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00001005 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001006 clone_info->channel=image_info->channel;
anthony1afdc7a2011-10-05 11:54:28 +00001007 (void) CloneImageOptions(clone_info,image_info);
cristy3ed852e2009-09-05 21:47:34 +00001008 clone_info->debug=IsEventLogging();
1009 clone_info->signature=image_info->signature;
1010 return(clone_info);
1011}
1012
1013/*
1014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015% %
1016% %
1017% %
cristy957f2612015-06-21 23:51:58 +00001018% C o p y I m a g e P i x e l s %
1019% %
1020% %
1021% %
1022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023%
1024% CopyImagePixels() copies pixels from the source image as defined by the
1025% geometry the destination image at the specified offset.
1026%
1027% The format of the CopyImagePixels method is:
1028%
1029% MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
cristy17fbd722015-06-22 00:46:58 +00001030% const RectangleInfo *geometry,const OffsetInfo *offset,
1031% ExceptionInfo *exception);
cristy957f2612015-06-21 23:51:58 +00001032%
1033% A description of each parameter follows:
1034%
1035% o image: the destination image.
1036%
1037% o source_image: the source image.
1038%
1039% o geometry: define the dimensions of the source pixel rectangle.
1040%
1041% o offset: define the offset in the destination image.
1042%
cristy17fbd722015-06-22 00:46:58 +00001043% o exception: return any errors or warnings in this structure.
1044%
cristy957f2612015-06-21 23:51:58 +00001045*/
1046MagickExport MagickBooleanType CopyImagePixels(Image *image,
1047 const Image *source_image,const RectangleInfo *geometry,
cristy17fbd722015-06-22 00:46:58 +00001048 const OffsetInfo *offset,ExceptionInfo *exception)
cristy957f2612015-06-21 23:51:58 +00001049{
cristy17fbd722015-06-22 00:46:58 +00001050#define CopyImageTag "Copy/Image"
1051
1052 CacheView
1053 *image_view,
1054 *source_view;
1055
1056 MagickBooleanType
1057 status;
1058
1059 MagickOffsetType
1060 progress;
1061
1062 ssize_t
1063 y;
1064
cristy957f2612015-06-21 23:51:58 +00001065 assert(image != (Image *) NULL);
1066 if (image->debug != MagickFalse)
1067 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1068 assert(source_image != (Image *) NULL);
1069 assert(geometry != (RectangleInfo *) NULL);
1070 assert(offset != (OffsetInfo *) NULL);
cristy8c4c1c42015-06-22 23:51:22 +00001071 if ((offset->x < 0) || (offset->y < 0) ||
Cristy7d049b72015-09-26 20:50:55 -04001072 ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1073 ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
cristye742cae2015-06-22 19:40:29 +00001074 ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1075 image->filename);
cristy8c4c1c42015-06-22 23:51:22 +00001076 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1077 return(MagickFalse);
cristy17fbd722015-06-22 00:46:58 +00001078 /*
1079 Copy image pixels.
1080 */
1081 status=MagickTrue;
1082 progress=0;
1083 source_view=AcquireVirtualCacheView(source_image,exception);
1084 image_view=AcquireAuthenticCacheView(image,exception);
1085#if defined(MAGICKCORE_OPENMP_SUPPORT)
1086 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristye742cae2015-06-22 19:40:29 +00001087 magick_threads(image,source_image,geometry->height,1)
cristy17fbd722015-06-22 00:46:58 +00001088#endif
cristye742cae2015-06-22 19:40:29 +00001089 for (y=0; y < (ssize_t) geometry->height; y++)
cristy17fbd722015-06-22 00:46:58 +00001090 {
1091 MagickBooleanType
1092 sync;
1093
1094 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001095 *magick_restrict p;
cristy17fbd722015-06-22 00:46:58 +00001096
1097 register ssize_t
1098 x;
1099
1100 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001101 *magick_restrict q;
cristy17fbd722015-06-22 00:46:58 +00001102
1103 if (status == MagickFalse)
1104 continue;
cristye742cae2015-06-22 19:40:29 +00001105 p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1106 geometry->width,1,exception);
1107 q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1108 geometry->width,1,exception);
cristy17fbd722015-06-22 00:46:58 +00001109 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1110 {
1111 status=MagickFalse;
1112 continue;
1113 }
cristye742cae2015-06-22 19:40:29 +00001114 for (x=0; x < (ssize_t) geometry->width; x++)
cristy17fbd722015-06-22 00:46:58 +00001115 {
1116 register ssize_t
1117 i;
1118
1119 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
Cristy0093cff2016-06-05 19:00:17 -04001120 {
cristy17fbd722015-06-22 00:46:58 +00001121 PixelChannel channel=GetPixelChannelChannel(image,i);
1122 PixelTrait traits=GetPixelChannelTraits(image,channel);
1123 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1124 if ((traits == UndefinedPixelTrait) ||
dirk5a9b26e2016-07-23 13:05:55 +02001125 ((traits & UpdatePixelTrait) == 0) ||
cristy17fbd722015-06-22 00:46:58 +00001126 (source_traits == UndefinedPixelTrait))
1127 continue;
dirkd00a0022015-07-05 09:54:39 +00001128 SetPixelChannel(image,channel,p[i],q);
cristy17fbd722015-06-22 00:46:58 +00001129 }
dirkd00a0022015-07-05 09:54:39 +00001130 p+=GetPixelChannels(source_image);
1131 q+=GetPixelChannels(image);
cristy17fbd722015-06-22 00:46:58 +00001132 }
dirkd00a0022015-07-05 09:54:39 +00001133 sync=SyncCacheViewAuthenticPixels(image_view,exception);
cristy17fbd722015-06-22 00:46:58 +00001134 if (sync == MagickFalse)
1135 status=MagickFalse;
1136 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1137 {
1138 MagickBooleanType
1139 proceed;
1140
1141#if defined(MAGICKCORE_OPENMP_SUPPORT)
1142 #pragma omp critical (MagickCore_CopyImage)
1143#endif
1144 proceed=SetImageProgress(image,CopyImageTag,progress++,image->rows);
1145 if (proceed == MagickFalse)
1146 status=MagickFalse;
1147 }
1148 }
1149 source_view=DestroyCacheView(source_view);
1150 image_view=DestroyCacheView(image_view);
1151 return(status);
cristy957f2612015-06-21 23:51:58 +00001152}
1153
1154/*
1155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156% %
1157% %
1158% %
cristy3ed852e2009-09-05 21:47:34 +00001159% D e s t r o y I m a g e %
1160% %
1161% %
1162% %
1163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164%
1165% DestroyImage() dereferences an image, deallocating memory associated with
1166% the image if the reference count becomes zero.
1167%
1168% The format of the DestroyImage method is:
1169%
1170% Image *DestroyImage(Image *image)
1171%
1172% A description of each parameter follows:
1173%
1174% o image: the image.
1175%
1176*/
1177MagickExport Image *DestroyImage(Image *image)
1178{
1179 MagickBooleanType
1180 destroy;
1181
1182 /*
1183 Dereference image.
1184 */
1185 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001186 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001187 if (image->debug != MagickFalse)
1188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1189 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001190 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001191 image->reference_count--;
1192 if (image->reference_count == 0)
1193 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001194 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001195 if (destroy == MagickFalse)
1196 return((Image *) NULL);
1197 /*
1198 Destroy image.
1199 */
1200 DestroyImagePixels(image);
cristyed231572011-07-14 02:18:59 +00001201 image->channel_map=DestroyPixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +00001202 if (image->montage != (char *) NULL)
1203 image->montage=DestroyString(image->montage);
1204 if (image->directory != (char *) NULL)
1205 image->directory=DestroyString(image->directory);
cristy101ab702011-10-13 13:06:32 +00001206 if (image->colormap != (PixelInfo *) NULL)
1207 image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
cristy3ed852e2009-09-05 21:47:34 +00001208 if (image->geometry != (char *) NULL)
1209 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001210 DestroyImageProfiles(image);
1211 DestroyImageProperties(image);
1212 DestroyImageArtifacts(image);
Cristy36421ee2015-08-28 11:58:20 -04001213 if (image->ascii85 != (Ascii85Info *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001214 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
Cristy36421ee2015-08-28 11:58:20 -04001215 if (image->image_info != (ImageInfo *) NULL)
1216 image->image_info=DestroyImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +00001217 DestroyBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001218 if (image->semaphore != (SemaphoreInfo *) NULL)
cristy3d162a92014-02-16 14:05:06 +00001219 RelinquishSemaphoreInfo(&image->semaphore);
cristye1c94d92015-06-28 12:16:33 +00001220 image->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001221 image=(Image *) RelinquishMagickMemory(image);
1222 return(image);
1223}
1224
1225/*
1226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227% %
1228% %
1229% %
1230% D e s t r o y I m a g e I n f o %
1231% %
1232% %
1233% %
1234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235%
1236% DestroyImageInfo() deallocates memory associated with an ImageInfo
1237% structure.
1238%
1239% The format of the DestroyImageInfo method is:
1240%
1241% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1242%
1243% A description of each parameter follows:
1244%
1245% o image_info: the image info.
1246%
1247*/
1248MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1249{
1250 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001251 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001252 if (image_info->debug != MagickFalse)
1253 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1254 image_info->filename);
1255 if (image_info->size != (char *) NULL)
1256 image_info->size=DestroyString(image_info->size);
1257 if (image_info->extract != (char *) NULL)
1258 image_info->extract=DestroyString(image_info->extract);
1259 if (image_info->scenes != (char *) NULL)
1260 image_info->scenes=DestroyString(image_info->scenes);
1261 if (image_info->page != (char *) NULL)
1262 image_info->page=DestroyString(image_info->page);
1263 if (image_info->sampling_factor != (char *) NULL)
1264 image_info->sampling_factor=DestroyString(
1265 image_info->sampling_factor);
1266 if (image_info->server_name != (char *) NULL)
1267 image_info->server_name=DestroyString(
1268 image_info->server_name);
1269 if (image_info->font != (char *) NULL)
1270 image_info->font=DestroyString(image_info->font);
1271 if (image_info->texture != (char *) NULL)
1272 image_info->texture=DestroyString(image_info->texture);
1273 if (image_info->density != (char *) NULL)
1274 image_info->density=DestroyString(image_info->density);
cristy3ed852e2009-09-05 21:47:34 +00001275 if (image_info->cache != (void *) NULL)
1276 image_info->cache=DestroyPixelCache(image_info->cache);
1277 if (image_info->profile != (StringInfo *) NULL)
1278 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1279 image_info->profile);
anthony1afdc7a2011-10-05 11:54:28 +00001280 DestroyImageOptions(image_info);
cristye1c94d92015-06-28 12:16:33 +00001281 image_info->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001282 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1283 return(image_info);
1284}
1285
1286/*
1287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288% %
1289% %
1290% %
1291+ D i s a s s o c i a t e I m a g e S t r e a m %
1292% %
1293% %
1294% %
1295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296%
cristy4916cb42014-09-20 00:44:37 +00001297% DisassociateImageStream() disassociates the image stream. It checks if the
1298% blob of the specified image is referenced by other images. If the reference
1299% count is higher then 1 a new blob is assigned to the specified image.
cristy3ed852e2009-09-05 21:47:34 +00001300%
1301% The format of the DisassociateImageStream method is:
1302%
dirkcfe4c1c2014-09-20 07:38:59 +00001303% void DisassociateImageStream(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001304%
1305% A description of each parameter follows:
1306%
1307% o image: the image.
1308%
1309*/
1310MagickExport void DisassociateImageStream(Image *image)
1311{
cristy4916cb42014-09-20 00:44:37 +00001312 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001313 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001314 if (image->debug != MagickFalse)
1315 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy10f10ec2014-09-20 01:00:50 +00001316 DisassociateBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001317}
1318
1319/*
1320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321% %
1322% %
1323% %
cristy3ed852e2009-09-05 21:47:34 +00001324% G e t I m a g e I n f o %
1325% %
1326% %
1327% %
1328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329%
1330% GetImageInfo() initializes image_info to default values.
1331%
1332% The format of the GetImageInfo method is:
1333%
1334% void GetImageInfo(ImageInfo *image_info)
1335%
1336% A description of each parameter follows:
1337%
1338% o image_info: the image info.
1339%
1340*/
1341MagickExport void GetImageInfo(ImageInfo *image_info)
1342{
cristyfa0ea942012-12-21 02:42:29 +00001343 char
1344 *synchronize;
1345
cristy3ed852e2009-09-05 21:47:34 +00001346 ExceptionInfo
1347 *exception;
1348
1349 /*
1350 File and image dimension members.
1351 */
1352 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1353 assert(image_info != (ImageInfo *) NULL);
1354 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1355 image_info->adjoin=MagickTrue;
1356 image_info->interlace=NoInterlace;
1357 image_info->channel=DefaultChannels;
1358 image_info->quality=UndefinedCompressionQuality;
1359 image_info->antialias=MagickTrue;
1360 image_info->dither=MagickTrue;
cristyfa0ea942012-12-21 02:42:29 +00001361 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1362 if (synchronize != (const char *) NULL)
1363 {
1364 image_info->synchronize=IsStringTrue(synchronize);
1365 synchronize=DestroyString(synchronize);
1366 }
cristy3ed852e2009-09-05 21:47:34 +00001367 exception=AcquireExceptionInfo();
dirkb797b2c2016-02-01 22:20:32 +01001368 (void) QueryColorCompliance(AlphaColor,AllCompliance,&image_info->alpha_color,
1369 exception);
cristy9950d572011-10-01 18:22:35 +00001370 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1371 &image_info->background_color,exception);
1372 (void) QueryColorCompliance(BorderColor,AllCompliance,
1373 &image_info->border_color,exception);
cristy9950d572011-10-01 18:22:35 +00001374 (void) QueryColorCompliance(TransparentColor,AllCompliance,
1375 &image_info->transparent_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00001376 exception=DestroyExceptionInfo(exception);
1377 image_info->debug=IsEventLogging();
cristye1c94d92015-06-28 12:16:33 +00001378 image_info->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
1381/*
1382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383% %
1384% %
1385% %
cristy15781e52009-12-05 23:05:27 +00001386% G e t I m a g e I n f o F i l e %
1387% %
1388% %
1389% %
1390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391%
1392% GetImageInfoFile() returns the image info file member.
1393%
1394% The format of the GetImageInfoFile method is:
1395%
1396% FILE *GetImageInfoFile(const ImageInfo *image_info)
1397%
1398% A description of each parameter follows:
1399%
1400% o image_info: the image info.
1401%
1402*/
1403MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1404{
1405 return(image_info->file);
1406}
1407
1408/*
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410% %
1411% %
1412% %
cristy3ed852e2009-09-05 21:47:34 +00001413% G e t I m a g e M a s k %
1414% %
1415% %
1416% %
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418%
1419% GetImageMask() returns the mask associated with the image.
1420%
1421% The format of the GetImageMask method is:
1422%
dirkaf131f12016-01-10 01:29:22 +01001423% Image *GetImageMask(const Image *image,const PixelMask type,
1424% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001425%
1426% A description of each parameter follows:
1427%
1428% o image: the image.
1429%
dirkaf131f12016-01-10 01:29:22 +01001430% o type: the mask type, ReadPixelMask or WritePixelMask.
1431%
cristy3ed852e2009-09-05 21:47:34 +00001432*/
dirkaf131f12016-01-10 01:29:22 +01001433MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1434 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001435{
cristy10a6c612012-01-29 21:41:05 +00001436 CacheView
1437 *mask_view,
1438 *image_view;
1439
1440 Image
1441 *mask_image;
1442
1443 MagickBooleanType
1444 status;
1445
1446 ssize_t
1447 y;
1448
1449 /*
1450 Get image mask.
1451 */
1452 assert(image != (Image *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001453 if (image->debug != MagickFalse)
1454 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001455 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00001456 mask_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1457 if (mask_image == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001458 return((Image *) NULL);
cristy10a6c612012-01-29 21:41:05 +00001459 status=MagickTrue;
dirk4a26ef62015-11-19 21:47:29 +01001460 mask_image->alpha_trait=UndefinedPixelTrait;
dirkcd1d8792015-11-19 22:46:24 +01001461 (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
Cristy0596ce22015-11-20 21:11:22 -05001462 mask_image->read_mask=MagickFalse;
cristy46ff2672012-12-14 15:32:26 +00001463 image_view=AcquireVirtualCacheView(image,exception);
1464 mask_view=AcquireAuthenticCacheView(mask_image,exception);
cristy10a6c612012-01-29 21:41:05 +00001465 for (y=0; y < (ssize_t) image->rows; y++)
1466 {
1467 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001468 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00001469
1470 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001471 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00001472
1473 register ssize_t
1474 x;
1475
1476 if (status == MagickFalse)
1477 continue;
1478 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1479 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1480 exception);
1481 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1482 {
1483 status=MagickFalse;
1484 continue;
1485 }
1486 for (x=0; x < (ssize_t) image->columns; x++)
1487 {
dirkaf131f12016-01-10 01:29:22 +01001488 switch (type)
1489 {
1490 case WritePixelMask:
1491 {
1492 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1493 break;
1494 }
1495 default:
1496 {
Dirk Lemstra633b2e92016-12-03 16:18:40 +01001497 SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
dirkaf131f12016-01-10 01:29:22 +01001498 break;
1499 }
1500 }
cristy10a6c612012-01-29 21:41:05 +00001501 p+=GetPixelChannels(image);
1502 q+=GetPixelChannels(mask_image);
1503 }
1504 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1505 status=MagickFalse;
1506 }
1507 mask_view=DestroyCacheView(mask_view);
1508 image_view=DestroyCacheView(image_view);
cristy1c2f48d2012-12-14 01:20:55 +00001509 if (status == MagickFalse)
1510 mask_image=DestroyImage(mask_image);
cristy10a6c612012-01-29 21:41:05 +00001511 return(mask_image);
cristy3ed852e2009-09-05 21:47:34 +00001512}
1513
1514/*
1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516% %
1517% %
1518% %
1519+ G e t I m a g e R e f e r e n c e C o u n t %
1520% %
1521% %
1522% %
1523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524%
1525% GetImageReferenceCount() returns the image reference count.
1526%
1527% The format of the GetReferenceCount method is:
1528%
cristybb503372010-05-27 20:51:26 +00001529% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001530%
1531% A description of each parameter follows:
1532%
1533% o image: the image.
1534%
1535*/
cristybb503372010-05-27 20:51:26 +00001536MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001537{
cristybb503372010-05-27 20:51:26 +00001538 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001539 reference_count;
1540
1541 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001542 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001543 if (image->debug != MagickFalse)
1544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001545 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001546 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001547 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001548 return(reference_count);
1549}
1550
1551/*
1552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553% %
1554% %
1555% %
cristy3ed852e2009-09-05 21:47:34 +00001556% 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 %
1557% %
1558% %
1559% %
1560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561%
1562% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1563% image. A virtual pixel is any pixel access that is outside the boundaries
1564% of the image cache.
1565%
1566% The format of the GetImageVirtualPixelMethod() method is:
1567%
1568% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1569%
1570% A description of each parameter follows:
1571%
1572% o image: the image.
1573%
1574*/
1575MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1576{
1577 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001578 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001579 if (image->debug != MagickFalse)
1580 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1581 return(GetPixelCacheVirtualMethod(image));
1582}
1583
1584/*
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586% %
1587% %
1588% %
1589% I n t e r p r e t I m a g e F i l e n a m e %
1590% %
1591% %
1592% %
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594%
1595% InterpretImageFilename() interprets embedded characters in an image filename.
1596% The filename length is returned.
1597%
1598% The format of the InterpretImageFilename method is:
1599%
cristyee2b1232012-03-04 02:58:28 +00001600% size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1601% const char *format,int value,char *filename,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001602%
1603% A description of each parameter follows.
1604%
1605% o image_info: the image info..
1606%
1607% o image: the image.
1608%
1609% o format: A filename describing the format to use to write the numeric
1610% argument. Only the first numeric format identifier is replaced.
1611%
1612% o value: Numeric value to substitute into format filename.
1613%
1614% o filename: return the formatted filename in this character buffer.
1615%
cristy6fccee12011-10-20 18:43:18 +00001616% o exception: return any errors or warnings in this structure.
1617%
cristy3ed852e2009-09-05 21:47:34 +00001618*/
1619MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00001620 Image *image,const char *format,int value,char *filename,
1621 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001622{
1623 char
1624 *q;
1625
1626 int
1627 c;
1628
1629 MagickBooleanType
1630 canonical;
1631
1632 register const char
1633 *p;
1634
cristyad785752011-07-27 23:13:03 +00001635 size_t
1636 length;
1637
cristy3ed852e2009-09-05 21:47:34 +00001638 canonical=MagickFalse;
cristyc7b79fc2011-07-28 00:24:17 +00001639 length=0;
cristy151b66d2015-04-15 10:50:31 +00001640 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001641 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1642 {
1643 q=(char *) p+1;
1644 if (*q == '%')
1645 {
1646 p=q+1;
1647 continue;
1648 }
1649 if (*q == '0')
1650 {
cristybb503372010-05-27 20:51:26 +00001651 ssize_t
dirk86bacde2016-03-17 22:04:25 +01001652 foo;
cristy3ed852e2009-09-05 21:47:34 +00001653
dirk86bacde2016-03-17 22:04:25 +01001654 foo=(ssize_t) strtol(q,&q,10);
1655 (void) foo;
cristy3ed852e2009-09-05 21:47:34 +00001656 }
1657 switch (*q)
1658 {
1659 case 'd':
1660 case 'o':
1661 case 'x':
1662 {
1663 q++;
1664 c=(*q);
1665 *q='\0';
cristyee2f5d62015-07-28 13:19:43 +00001666 (void) FormatLocaleString(filename+(p-format),(size_t)
1667 (MagickPathExtent-(p-format)),p,value);
cristy3ed852e2009-09-05 21:47:34 +00001668 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001669 (void) ConcatenateMagickString(filename,q,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001670 canonical=MagickTrue;
1671 if (*(q-1) != '%')
1672 break;
1673 p++;
1674 break;
1675 }
1676 case '[':
1677 {
1678 char
cristy151b66d2015-04-15 10:50:31 +00001679 pattern[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001680
1681 const char
dirk86bacde2016-03-17 22:04:25 +01001682 *option;
cristy3ed852e2009-09-05 21:47:34 +00001683
cristy3ed852e2009-09-05 21:47:34 +00001684 register char
1685 *r;
1686
cristybb503372010-05-27 20:51:26 +00001687 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001688 i;
1689
cristycb6d09b2010-06-19 01:59:36 +00001690 ssize_t
1691 depth;
1692
cristy3ed852e2009-09-05 21:47:34 +00001693 /*
1694 Image option.
1695 */
anthony2cfa1a12012-05-12 05:18:07 +00001696 /* FUTURE: Compare update with code from InterpretImageProperties()
cristy97fc9f32012-06-13 21:04:44 +00001697 Note that a 'filename:' property should not need depth recursion.
anthony2cfa1a12012-05-12 05:18:07 +00001698 */
cristy3ed852e2009-09-05 21:47:34 +00001699 if (strchr(p,']') == (char *) NULL)
1700 break;
1701 depth=1;
1702 r=q+1;
cristy151b66d2015-04-15 10:50:31 +00001703 for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
cristy3ed852e2009-09-05 21:47:34 +00001704 {
1705 if (*r == '[')
1706 depth++;
1707 if (*r == ']')
1708 depth--;
1709 if (depth <= 0)
1710 break;
1711 pattern[i]=(*r++);
1712 }
1713 pattern[i]='\0';
1714 if (LocaleNCompare(pattern,"filename:",9) != 0)
1715 break;
dirk86bacde2016-03-17 22:04:25 +01001716 option=(const char *) NULL;
anthony06762232012-04-29 11:45:40 +00001717 if (image != (Image *) NULL)
dirk86bacde2016-03-17 22:04:25 +01001718 option=GetImageProperty(image,pattern,exception);
1719 if ((option == (const char *) NULL) && (image != (Image *) NULL))
1720 option=GetImageArtifact(image,pattern);
1721 if ((option == (const char *) NULL) &&
anthony06762232012-04-29 11:45:40 +00001722 (image_info != (ImageInfo *) NULL))
dirk86bacde2016-03-17 22:04:25 +01001723 option=GetImageOption(image_info,pattern);
1724 if (option == (const char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001725 break;
1726 q--;
1727 c=(*q);
1728 *q='\0';
dirk86bacde2016-03-17 22:04:25 +01001729 (void) CopyMagickString(filename+(p-format-length),option,(size_t)
cristy151b66d2015-04-15 10:50:31 +00001730 (MagickPathExtent-(p-format-length)));
cristyad785752011-07-27 23:13:03 +00001731 length+=strlen(pattern)-1;
cristy3ed852e2009-09-05 21:47:34 +00001732 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001733 (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001734 canonical=MagickTrue;
1735 if (*(q-1) != '%')
1736 break;
1737 p++;
1738 break;
1739 }
1740 default:
1741 break;
1742 }
1743 }
1744 for (q=filename; *q != '\0'; q++)
1745 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001746 {
cristy151b66d2015-04-15 10:50:31 +00001747 (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
cristy27bf23e2011-01-10 13:35:22 +00001748 canonical=MagickTrue;
1749 }
cristy3ed852e2009-09-05 21:47:34 +00001750 if (canonical == MagickFalse)
cristy151b66d2015-04-15 10:50:31 +00001751 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001752 return(strlen(filename));
1753}
1754
1755/*
1756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1757% %
1758% %
1759% %
1760% I s H i g h D y n a m i c R a n g e I m a g e %
1761% %
1762% %
1763% %
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765%
1766% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1767% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1768% 0..65535.
1769%
1770% The format of the IsHighDynamicRangeImage method is:
1771%
1772% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1773% ExceptionInfo *exception)
1774%
1775% A description of each parameter follows:
1776%
1777% o image: the image.
1778%
1779% o exception: return any errors or warnings in this structure.
1780%
1781*/
1782MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1783 ExceptionInfo *exception)
1784{
1785#if !defined(MAGICKCORE_HDRI_SUPPORT)
1786 (void) image;
1787 (void) exception;
1788 return(MagickFalse);
1789#else
1790 CacheView
1791 *image_view;
1792
cristy3ed852e2009-09-05 21:47:34 +00001793 MagickBooleanType
1794 status;
1795
cristycb6d09b2010-06-19 01:59:36 +00001796 ssize_t
1797 y;
1798
cristy3ed852e2009-09-05 21:47:34 +00001799 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001800 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001801 if (image->debug != MagickFalse)
1802 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1803 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00001804 image_view=AcquireVirtualCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00001805#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001806 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00001807 magick_threads(image,image,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001808#endif
cristybb503372010-05-27 20:51:26 +00001809 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001810 {
cristy4c08aed2011-07-01 19:47:50 +00001811 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001812 *p;
1813
cristybb503372010-05-27 20:51:26 +00001814 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001815 x;
1816
1817 if (status == MagickFalse)
1818 continue;
1819 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001820 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001821 {
1822 status=MagickFalse;
1823 continue;
1824 }
cristybb503372010-05-27 20:51:26 +00001825 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001826 {
cristya905c052011-09-17 22:37:55 +00001827 register ssize_t
1828 i;
1829
Cristydf5e8b12016-12-02 17:26:39 -05001830 if (GetPixelWriteMask(image,p) == 0)
cristy10a6c612012-01-29 21:41:05 +00001831 {
1832 p+=GetPixelChannels(image);
1833 continue;
1834 }
cristya905c052011-09-17 22:37:55 +00001835 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1836 {
cristya19f1d72012-08-07 18:24:38 +00001837 double
cristya905c052011-09-17 22:37:55 +00001838 pixel;
1839
cristyb0a657e2012-08-29 00:45:37 +00001840 PixelTrait
1841 traits;
1842
1843 traits=GetPixelChannelTraits(image,(PixelChannel) i);
cristya905c052011-09-17 22:37:55 +00001844 if (traits == UndefinedPixelTrait)
1845 continue;
cristya19f1d72012-08-07 18:24:38 +00001846 pixel=(double) p[i];
cristya905c052011-09-17 22:37:55 +00001847 if ((pixel < 0.0) || (pixel > QuantumRange) ||
cristy569b0e32013-08-15 16:07:35 +00001848 (pixel != (double) ((QuantumAny) pixel)))
cristya905c052011-09-17 22:37:55 +00001849 break;
1850 }
cristyed231572011-07-14 02:18:59 +00001851 p+=GetPixelChannels(image);
cristya905c052011-09-17 22:37:55 +00001852 if (i < (ssize_t) GetPixelChannels(image))
1853 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001854 }
cristybb503372010-05-27 20:51:26 +00001855 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001856 status=MagickFalse;
1857 }
1858 image_view=DestroyCacheView(image_view);
1859 return(status != MagickFalse ? MagickFalse : MagickTrue);
1860#endif
1861}
1862
1863/*
1864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865% %
1866% %
1867% %
1868% I s I m a g e O b j e c t %
1869% %
1870% %
1871% %
1872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1873%
1874% IsImageObject() returns MagickTrue if the image sequence contains a valid
1875% set of image objects.
1876%
1877% The format of the IsImageObject method is:
1878%
1879% MagickBooleanType IsImageObject(const Image *image)
1880%
1881% A description of each parameter follows:
1882%
1883% o image: the image.
1884%
1885*/
1886MagickExport MagickBooleanType IsImageObject(const Image *image)
1887{
1888 register const Image
1889 *p;
1890
1891 assert(image != (Image *) NULL);
1892 if (image->debug != MagickFalse)
1893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1894 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
cristye1c94d92015-06-28 12:16:33 +00001895 if (p->signature != MagickCoreSignature)
cristy3ed852e2009-09-05 21:47:34 +00001896 return(MagickFalse);
1897 return(MagickTrue);
1898}
1899
1900/*
1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902% %
1903% %
1904% %
1905% I s T a i n t I m a g e %
1906% %
1907% %
1908% %
1909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910%
1911% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1912% since it was first constituted.
1913%
1914% The format of the IsTaintImage method is:
1915%
1916% MagickBooleanType IsTaintImage(const Image *image)
1917%
1918% A description of each parameter follows:
1919%
1920% o image: the image.
1921%
1922*/
1923MagickExport MagickBooleanType IsTaintImage(const Image *image)
1924{
1925 char
cristy151b66d2015-04-15 10:50:31 +00001926 magick[MagickPathExtent],
1927 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001928
1929 register const Image
1930 *p;
1931
1932 assert(image != (Image *) NULL);
1933 if (image->debug != MagickFalse)
1934 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001935 assert(image->signature == MagickCoreSignature);
cristy151b66d2015-04-15 10:50:31 +00001936 (void) CopyMagickString(magick,image->magick,MagickPathExtent);
1937 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001938 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1939 {
1940 if (p->taint != MagickFalse)
1941 return(MagickTrue);
1942 if (LocaleCompare(p->magick,magick) != 0)
1943 return(MagickTrue);
1944 if (LocaleCompare(p->filename,filename) != 0)
1945 return(MagickTrue);
1946 }
1947 return(MagickFalse);
1948}
1949
1950/*
1951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1952% %
1953% %
1954% %
1955% M o d i f y I m a g e %
1956% %
1957% %
1958% %
1959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960%
1961% ModifyImage() ensures that there is only a single reference to the image
1962% to be modified, updating the provided image pointer to point to a clone of
1963% the original image if necessary.
1964%
1965% The format of the ModifyImage method is:
1966%
1967% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
1968%
1969% A description of each parameter follows:
1970%
1971% o image: the image.
1972%
1973% o exception: return any errors or warnings in this structure.
1974%
1975*/
1976MagickExport MagickBooleanType ModifyImage(Image **image,
1977 ExceptionInfo *exception)
1978{
1979 Image
1980 *clone_image;
1981
1982 assert(image != (Image **) NULL);
1983 assert(*image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001984 assert((*image)->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001985 if ((*image)->debug != MagickFalse)
1986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1987 if (GetImageReferenceCount(*image) <= 1)
1988 return(MagickTrue);
1989 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00001990 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001991 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00001992 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001993 *image=clone_image;
1994 return(MagickTrue);
1995}
1996
1997/*
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999% %
2000% %
2001% %
2002% N e w M a g i c k I m a g e %
2003% %
2004% %
2005% %
2006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007%
2008% NewMagickImage() creates a blank image canvas of the specified size and
2009% background color.
2010%
2011% The format of the NewMagickImage method is:
2012%
cristy44410ab2014-05-25 20:39:43 +00002013% Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2014% const size_t height,const PixelInfo *background,
cristy0740a982011-10-13 15:01:01 +00002015% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002016%
2017% A description of each parameter follows:
2018%
2019% o image: the image.
2020%
2021% o width: the image width.
2022%
2023% o height: the image height.
2024%
2025% o background: the image color.
2026%
cristy0740a982011-10-13 15:01:01 +00002027% o exception: return any errors or warnings in this structure.
2028%
cristy3ed852e2009-09-05 21:47:34 +00002029*/
2030MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristy0740a982011-10-13 15:01:01 +00002031 const size_t width,const size_t height,const PixelInfo *background,
2032 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002033{
2034 CacheView
2035 *image_view;
2036
cristy3ed852e2009-09-05 21:47:34 +00002037 Image
2038 *image;
2039
cristy3ed852e2009-09-05 21:47:34 +00002040 MagickBooleanType
2041 status;
2042
cristya905c052011-09-17 22:37:55 +00002043 ssize_t
2044 y;
2045
cristy3ed852e2009-09-05 21:47:34 +00002046 assert(image_info != (const ImageInfo *) NULL);
2047 if (image_info->debug != MagickFalse)
2048 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002049 assert(image_info->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002050 assert(background != (const PixelInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00002051 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002052 image->columns=width;
2053 image->rows=height;
2054 image->colorspace=background->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002055 image->alpha_trait=background->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +00002056 image->fuzz=background->fuzz;
2057 image->depth=background->depth;
2058 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002059 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00002060#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002061 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002062 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00002063#endif
cristybb503372010-05-27 20:51:26 +00002064 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002065 {
cristy4c08aed2011-07-01 19:47:50 +00002066 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002067 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002068
cristycb6d09b2010-06-19 01:59:36 +00002069 register ssize_t
2070 x;
2071
cristy48974b92009-12-19 02:36:06 +00002072 if (status == MagickFalse)
2073 continue;
cristy3ed852e2009-09-05 21:47:34 +00002074 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002075 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002076 {
2077 status=MagickFalse;
2078 continue;
2079 }
cristybb503372010-05-27 20:51:26 +00002080 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002081 {
cristy11a06d32015-01-04 12:03:27 +00002082 SetPixelViaPixelInfo(image,background,q);
cristyed231572011-07-14 02:18:59 +00002083 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002084 }
2085 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2086 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002087 }
2088 image_view=DestroyCacheView(image_view);
2089 if (status == MagickFalse)
2090 image=DestroyImage(image);
2091 return(image);
2092}
2093
2094/*
2095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2096% %
2097% %
2098% %
2099% R e f e r e n c e I m a g e %
2100% %
2101% %
2102% %
2103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104%
2105% ReferenceImage() increments the reference count associated with an image
2106% returning a pointer to the image.
2107%
2108% The format of the ReferenceImage method is:
2109%
2110% Image *ReferenceImage(Image *image)
2111%
2112% A description of each parameter follows:
2113%
2114% o image: the image.
2115%
2116*/
2117MagickExport Image *ReferenceImage(Image *image)
2118{
2119 assert(image != (Image *) NULL);
2120 if (image->debug != MagickFalse)
2121 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002122 assert(image->signature == MagickCoreSignature);
cristyf84a1932010-01-03 18:00:18 +00002123 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002124 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002125 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002126 return(image);
2127}
2128
2129/*
2130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131% %
2132% %
2133% %
2134% R e s e t I m a g e P a g e %
2135% %
2136% %
2137% %
2138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2139%
2140% ResetImagePage() resets the image page canvas and position.
2141%
2142% The format of the ResetImagePage method is:
2143%
2144% MagickBooleanType ResetImagePage(Image *image,const char *page)
2145%
2146% A description of each parameter follows:
2147%
2148% o image: the image.
2149%
2150% o page: the relative page specification.
2151%
2152*/
2153MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2154{
2155 MagickStatusType
2156 flags;
2157
2158 RectangleInfo
2159 geometry;
2160
2161 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002162 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002163 if (image->debug != MagickFalse)
2164 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2165 flags=ParseAbsoluteGeometry(page,&geometry);
2166 if ((flags & WidthValue) != 0)
2167 {
2168 if ((flags & HeightValue) == 0)
2169 geometry.height=geometry.width;
2170 image->page.width=geometry.width;
2171 image->page.height=geometry.height;
2172 }
2173 if ((flags & AspectValue) != 0)
2174 {
2175 if ((flags & XValue) != 0)
2176 image->page.x+=geometry.x;
2177 if ((flags & YValue) != 0)
2178 image->page.y+=geometry.y;
2179 }
2180 else
2181 {
2182 if ((flags & XValue) != 0)
2183 {
2184 image->page.x=geometry.x;
2185 if ((image->page.width == 0) && (geometry.x > 0))
2186 image->page.width=image->columns+geometry.x;
2187 }
2188 if ((flags & YValue) != 0)
2189 {
2190 image->page.y=geometry.y;
2191 if ((image->page.height == 0) && (geometry.y > 0))
2192 image->page.height=image->rows+geometry.y;
2193 }
2194 }
2195 return(MagickTrue);
2196}
2197
2198/*
2199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200% %
2201% %
2202% %
Cristy93452f02017-02-01 09:23:15 -05002203% S e t I m a g e A l p h a %
2204% %
2205% %
2206% %
2207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208%
2209% SetImageAlpha() sets the alpha levels of the image.
2210%
2211% The format of the SetImageAlpha method is:
2212%
2213% MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2214% ExceptionInfo *exception)
2215%
2216% A description of each parameter follows:
2217%
2218% o image: the image.
2219%
2220% o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
2221% fully transparent.
2222%
2223*/
2224MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2225 ExceptionInfo *exception)
2226{
2227 CacheView
2228 *image_view;
2229
2230 MagickBooleanType
2231 status;
2232
2233 ssize_t
2234 y;
2235
2236 assert(image != (Image *) NULL);
2237 if (image->debug != MagickFalse)
2238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2239 assert(image->signature == MagickCoreSignature);
2240 image->alpha_trait=BlendPixelTrait;
2241 status=MagickTrue;
2242 image_view=AcquireAuthenticCacheView(image,exception);
2243#if defined(MAGICKCORE_OPENMP_SUPPORT)
2244 #pragma omp parallel for schedule(static,4) shared(status) \
2245 magick_threads(image,image,image->rows,1)
2246#endif
2247 for (y=0; y < (ssize_t) image->rows; y++)
2248 {
2249 register Quantum
2250 *magick_restrict q;
2251
2252 register ssize_t
2253 x;
2254
2255 if (status == MagickFalse)
2256 continue;
2257 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2258 if (q == (Quantum *) NULL)
2259 {
2260 status=MagickFalse;
2261 continue;
2262 }
2263 for (x=0; x < (ssize_t) image->columns; x++)
2264 {
2265 if (GetPixelWriteMask(image,q) != 0)
2266 SetPixelAlpha(image,alpha,q);
2267 q+=GetPixelChannels(image);
2268 }
2269 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2270 status=MagickFalse;
2271 }
2272 image_view=DestroyCacheView(image_view);
2273 return(status);
2274}
2275
2276/*
2277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278% %
2279% %
2280% %
cristy3ed852e2009-09-05 21:47:34 +00002281% S e t I m a g e B a c k g r o u n d C o l o r %
2282% %
2283% %
2284% %
2285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286%
2287% SetImageBackgroundColor() initializes the image pixels to the image
2288% background color. The background color is defined by the background_color
2289% member of the image structure.
2290%
2291% The format of the SetImage method is:
2292%
cristyea1a8aa2011-10-20 13:24:06 +00002293% MagickBooleanType SetImageBackgroundColor(Image *image,
2294% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002295%
2296% A description of each parameter follows:
2297%
2298% o image: the image.
2299%
cristyea1a8aa2011-10-20 13:24:06 +00002300% o exception: return any errors or warnings in this structure.
2301%
cristy3ed852e2009-09-05 21:47:34 +00002302*/
cristyea1a8aa2011-10-20 13:24:06 +00002303MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2304 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002305{
2306 CacheView
2307 *image_view;
2308
cristy3ed852e2009-09-05 21:47:34 +00002309 MagickBooleanType
2310 status;
2311
dirkdc896c12014-10-15 16:28:15 +00002312 PixelInfo
2313 background;
2314
cristycb6d09b2010-06-19 01:59:36 +00002315 ssize_t
2316 y;
2317
cristy3ed852e2009-09-05 21:47:34 +00002318 assert(image != (Image *) NULL);
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002321 assert(image->signature == MagickCoreSignature);
cristy574cc262011-08-05 01:23:58 +00002322 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002323 return(MagickFalse);
Cristya739e8f2016-12-09 10:40:04 -05002324 if ((image->background_color.alpha != OpaqueAlpha) &&
2325 (image->alpha_trait == UndefinedPixelTrait))
2326 (void) SetImageAlphaChannel(image,OnAlphaChannel,exception);
dirkbfdd5bc2014-11-04 19:47:44 +00002327 ConformPixelInfo(image,&image->background_color,&background,exception);
cristy3ed852e2009-09-05 21:47:34 +00002328 /*
2329 Set image background color.
2330 */
2331 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002332 image_view=AcquireAuthenticCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +00002333 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002334 {
cristy4c08aed2011-07-01 19:47:50 +00002335 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002336 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002337
cristycb6d09b2010-06-19 01:59:36 +00002338 register ssize_t
2339 x;
2340
cristy3ed852e2009-09-05 21:47:34 +00002341 if (status == MagickFalse)
2342 continue;
2343 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002344 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002345 {
2346 status=MagickFalse;
2347 continue;
2348 }
cristybb503372010-05-27 20:51:26 +00002349 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002350 {
cristy11a06d32015-01-04 12:03:27 +00002351 SetPixelViaPixelInfo(image,&background,q);
cristyed231572011-07-14 02:18:59 +00002352 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002353 }
cristy3ed852e2009-09-05 21:47:34 +00002354 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2355 status=MagickFalse;
2356 }
2357 image_view=DestroyCacheView(image_view);
2358 return(status);
2359}
2360
2361/*
2362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2363% %
2364% %
2365% %
cristycf1296e2012-08-26 23:40:49 +00002366% S e t I m a g e C h a n n e l M a s k %
2367% %
2368% %
2369% %
2370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2371%
2372% SetImageChannelMask() sets the image channel mask from the specified channel
2373% mask.
2374%
2375% The format of the SetImageChannelMask method is:
2376%
2377% ChannelType SetImageChannelMask(Image *image,
2378% const ChannelType channel_mask)
2379%
2380% A description of each parameter follows:
2381%
2382% o image: the image.
2383%
2384% o channel_mask: the channel mask.
2385%
2386*/
2387MagickExport ChannelType SetImageChannelMask(Image *image,
2388 const ChannelType channel_mask)
2389{
cristybcd59342015-06-07 14:07:19 +00002390 return(SetPixelChannelMask(image,channel_mask));
cristycf1296e2012-08-26 23:40:49 +00002391}
2392
2393/*
2394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395% %
2396% %
2397% %
cristya5b77cb2010-05-07 19:34:48 +00002398% S e t I m a g e C o l o r %
2399% %
2400% %
2401% %
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403%
2404% SetImageColor() set the entire image canvas to the specified color.
2405%
2406% The format of the SetImageColor method is:
2407%
cristye941a752011-10-15 01:52:48 +00002408% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2409% ExeptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002410%
2411% A description of each parameter follows:
2412%
2413% o image: the image.
2414%
2415% o background: the image color.
2416%
cristye941a752011-10-15 01:52:48 +00002417% o exception: return any errors or warnings in this structure.
2418%
cristya5b77cb2010-05-07 19:34:48 +00002419*/
2420MagickExport MagickBooleanType SetImageColor(Image *image,
cristye941a752011-10-15 01:52:48 +00002421 const PixelInfo *color,ExceptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002422{
2423 CacheView
2424 *image_view;
2425
cristya5b77cb2010-05-07 19:34:48 +00002426 MagickBooleanType
2427 status;
2428
cristycb6d09b2010-06-19 01:59:36 +00002429 ssize_t
2430 y;
2431
cristya5b77cb2010-05-07 19:34:48 +00002432 assert(image != (Image *) NULL);
2433 if (image->debug != MagickFalse)
2434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002435 assert(image->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002436 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002437 image->colorspace=color->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002438 image->alpha_trait=color->alpha_trait;
cristya5b77cb2010-05-07 19:34:48 +00002439 image->fuzz=color->fuzz;
2440 image->depth=color->depth;
2441 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002442 image_view=AcquireAuthenticCacheView(image,exception);
cristya5b77cb2010-05-07 19:34:48 +00002443#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002444 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002445 magick_threads(image,image,image->rows,1)
cristya5b77cb2010-05-07 19:34:48 +00002446#endif
cristybb503372010-05-27 20:51:26 +00002447 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002448 {
cristy4c08aed2011-07-01 19:47:50 +00002449 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002450 *magick_restrict q;
cristya5b77cb2010-05-07 19:34:48 +00002451
cristycb6d09b2010-06-19 01:59:36 +00002452 register ssize_t
2453 x;
2454
cristya5b77cb2010-05-07 19:34:48 +00002455 if (status == MagickFalse)
2456 continue;
2457 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002458 if (q == (Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002459 {
2460 status=MagickFalse;
2461 continue;
2462 }
cristybb503372010-05-27 20:51:26 +00002463 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002464 {
cristy11a06d32015-01-04 12:03:27 +00002465 SetPixelViaPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002466 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002467 }
2468 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2469 status=MagickFalse;
2470 }
2471 image_view=DestroyCacheView(image_view);
2472 return(status);
2473}
2474
2475/*
2476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477% %
2478% %
2479% %
cristy3ed852e2009-09-05 21:47:34 +00002480% S e t I m a g e S t o r a g e C l a s s %
2481% %
2482% %
2483% %
2484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485%
2486% SetImageStorageClass() sets the image class: DirectClass for true color
2487% images or PseudoClass for colormapped images.
2488%
2489% The format of the SetImageStorageClass method is:
2490%
2491% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002492% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002493%
2494% A description of each parameter follows:
2495%
2496% o image: the image.
2497%
2498% o storage_class: The image class.
2499%
cristy574cc262011-08-05 01:23:58 +00002500% o exception: return any errors or warnings in this structure.
2501%
cristy3ed852e2009-09-05 21:47:34 +00002502*/
2503MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002504 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002505{
Cristyad4722f2016-12-14 16:12:13 -05002506 assert(image != (Image *) NULL);
2507 assert(image->signature == MagickCoreSignature);
2508 if (image->debug != MagickFalse)
2509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2510 assert(exception != (ExceptionInfo *) NULL);
2511 assert(exception->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002512 image->storage_class=storage_class;
Cristy227ac002016-12-16 19:46:04 -05002513 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002514}
2515
2516/*
2517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2518% %
2519% %
2520% %
cristy3ed852e2009-09-05 21:47:34 +00002521% S e t I m a g e E x t e n t %
2522% %
2523% %
2524% %
2525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2526%
2527% SetImageExtent() sets the image size (i.e. columns & rows).
2528%
2529% The format of the SetImageExtent method is:
2530%
cristy08429172011-07-14 17:18:16 +00002531% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002532% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002533%
2534% A description of each parameter follows:
2535%
2536% o image: the image.
2537%
2538% o columns: The image width in pixels.
2539%
2540% o rows: The image height in pixels.
2541%
cristy63240882011-08-05 19:05:27 +00002542% o exception: return any errors or warnings in this structure.
2543%
cristy3ed852e2009-09-05 21:47:34 +00002544*/
cristy08429172011-07-14 17:18:16 +00002545MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002546 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002547{
cristy537e2722010-09-21 15:30:59 +00002548 if ((columns == 0) || (rows == 0))
Cristy852231d2016-06-24 07:18:31 -04002549 ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
cristy537e2722010-09-21 15:30:59 +00002550 image->columns=columns;
2551 image->rows=rows;
cristyda950bb2015-07-18 23:17:28 +00002552 if (image->depth > (8*sizeof(MagickSizeType)))
2553 ThrowBinaryException(ImageError,"ImageDepthNotSupported",image->filename);
cristy6e437132011-08-12 13:02:19 +00002554 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002555}
2556
2557/*
2558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2559% %
2560% %
2561% %
2562+ S e t I m a g e I n f o %
2563% %
2564% %
2565% %
2566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567%
anthonye5b39652012-04-21 05:37:29 +00002568% SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
cristy3ed852e2009-09-05 21:47:34 +00002569% It is set to a type of image format based on the prefix or suffix of the
anthonye5b39652012-04-21 05:37:29 +00002570% filename. For example, 'ps:image' returns PS indicating a Postscript image.
2571% JPEG is returned for this filename: 'image.jpg'. The filename prefix has
cristy3ed852e2009-09-05 21:47:34 +00002572% precendence over the suffix. Use an optional index enclosed in brackets
2573% after a file name to specify a desired scene of a multi-resolution image
2574% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2575% indicates success.
2576%
2577% The format of the SetImageInfo method is:
2578%
2579% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002580% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002581%
2582% A description of each parameter follows:
2583%
cristyd965a422010-03-03 17:47:35 +00002584% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002585%
cristyd965a422010-03-03 17:47:35 +00002586% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002587%
2588% o exception: return any errors or warnings in this structure.
2589%
2590*/
2591MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002592 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002593{
2594 char
dirk8f681612015-04-16 21:05:08 +00002595 component[MagickPathExtent],
cristy151b66d2015-04-15 10:50:31 +00002596 magic[MagickPathExtent],
dirk8f681612015-04-16 21:05:08 +00002597 *q;
cristy3ed852e2009-09-05 21:47:34 +00002598
2599 const MagicInfo
2600 *magic_info;
2601
2602 const MagickInfo
2603 *magick_info;
2604
2605 ExceptionInfo
2606 *sans_exception;
2607
2608 Image
2609 *image;
2610
2611 MagickBooleanType
2612 status;
2613
2614 register const char
2615 *p;
2616
2617 ssize_t
2618 count;
2619
cristy3ed852e2009-09-05 21:47:34 +00002620 /*
2621 Look for 'image.format' in filename.
2622 */
2623 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002624 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002625 if (image_info->debug != MagickFalse)
2626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2627 image_info->filename);
dirk8f681612015-04-16 21:05:08 +00002628 *component='\0';
2629 GetPathComponent(image_info->filename,SubimagePath,component);
2630 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002631 {
cristy4f96a1d2014-01-04 15:31:36 +00002632 /*
2633 Look for scene specification (e.g. img0001.pcd[4]).
2634 */
dirk8f681612015-04-16 21:05:08 +00002635 if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002636 {
dirk8f681612015-04-16 21:05:08 +00002637 if (IsGeometry(component) != MagickFalse)
2638 (void) CloneString(&image_info->extract,component);
cristy4f96a1d2014-01-04 15:31:36 +00002639 }
2640 else
2641 {
2642 size_t
2643 first,
2644 last;
cristy3ed852e2009-09-05 21:47:34 +00002645
dirk8f681612015-04-16 21:05:08 +00002646 (void) CloneString(&image_info->scenes,component);
cristy4f96a1d2014-01-04 15:31:36 +00002647 image_info->scene=StringToUnsignedLong(image_info->scenes);
2648 image_info->number_scenes=image_info->scene;
2649 p=image_info->scenes;
2650 for (q=(char *) image_info->scenes; *q != '\0'; p++)
2651 {
2652 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2653 p++;
2654 first=(size_t) strtol(p,&q,10);
2655 last=first;
2656 while (isspace((int) ((unsigned char) *q)) != 0)
2657 q++;
2658 if (*q == '-')
2659 last=(size_t) strtol(q+1,&q,10);
2660 if (first > last)
2661 Swap(first,last);
2662 if (first < image_info->scene)
2663 image_info->scene=first;
2664 if (last > image_info->number_scenes)
2665 image_info->number_scenes=last;
2666 p=q;
2667 }
2668 image_info->number_scenes-=image_info->scene-1;
cristy3ed852e2009-09-05 21:47:34 +00002669 }
2670 }
dirk8f681612015-04-16 21:05:08 +00002671 *component='\0';
cristy6f7cebf2014-12-27 12:10:39 +00002672 if (*image_info->magick == '\0')
dirk8f681612015-04-16 21:05:08 +00002673 GetPathComponent(image_info->filename,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002674#if defined(MAGICKCORE_ZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002675 if (*component != '\0')
2676 if ((LocaleCompare(component,"gz") == 0) ||
2677 (LocaleCompare(component,"Z") == 0) ||
2678 (LocaleCompare(component,"svgz") == 0) ||
2679 (LocaleCompare(component,"wmz") == 0))
cristy3ed852e2009-09-05 21:47:34 +00002680 {
2681 char
cristy151b66d2015-04-15 10:50:31 +00002682 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002683
cristy151b66d2015-04-15 10:50:31 +00002684 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002685 path[strlen(path)-strlen(component)-1]='\0';
2686 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002687 }
2688#endif
2689#if defined(MAGICKCORE_BZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002690 if (*component != '\0')
2691 if (LocaleCompare(component,"bz2") == 0)
cristy3ed852e2009-09-05 21:47:34 +00002692 {
2693 char
cristy151b66d2015-04-15 10:50:31 +00002694 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002695
cristy151b66d2015-04-15 10:50:31 +00002696 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002697 path[strlen(path)-strlen(component)-1]='\0';
2698 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002699 }
2700#endif
2701 image_info->affirm=MagickFalse;
2702 sans_exception=AcquireExceptionInfo();
dirk8f681612015-04-16 21:05:08 +00002703 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002704 {
2705 MagickFormatType
2706 format_type;
2707
cristybb503372010-05-27 20:51:26 +00002708 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002709 i;
2710
2711 static const char
2712 *format_type_formats[] =
2713 {
2714 "AUTOTRACE",
2715 "BROWSE",
2716 "DCRAW",
2717 "EDIT",
cristy3ed852e2009-09-05 21:47:34 +00002718 "LAUNCH",
2719 "MPEG:DECODE",
2720 "MPEG:ENCODE",
2721 "PRINT",
2722 "PS:ALPHA",
2723 "PS:CMYK",
2724 "PS:COLOR",
2725 "PS:GRAY",
2726 "PS:MONO",
2727 "SCAN",
2728 "SHOW",
2729 "WIN",
2730 (char *) NULL
2731 };
2732
2733 /*
2734 User specified image format.
2735 */
dirk8f681612015-04-16 21:05:08 +00002736 (void) CopyMagickString(magic,component,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002737 LocaleUpper(magic);
2738 /*
2739 Look for explicit image formats.
2740 */
2741 format_type=UndefinedFormatType;
dirk80fd8af2015-02-22 00:45:51 +00002742 magick_info=GetMagickInfo(magic,sans_exception);
2743 if ((magick_info != (const MagickInfo *) NULL) &&
2744 (magick_info->format_type != UndefinedFormatType))
2745 format_type=magick_info->format_type;
cristy3ed852e2009-09-05 21:47:34 +00002746 i=0;
cristydd9a2532010-02-20 19:26:46 +00002747 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00002748 (format_type_formats[i] != (char *) NULL))
2749 {
2750 if ((*magic == *format_type_formats[i]) &&
2751 (LocaleCompare(magic,format_type_formats[i]) == 0))
2752 format_type=ExplicitFormatType;
2753 i++;
2754 }
cristy3ed852e2009-09-05 21:47:34 +00002755 if (format_type == UndefinedFormatType)
cristy151b66d2015-04-15 10:50:31 +00002756 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002757 else
2758 if (format_type == ExplicitFormatType)
2759 {
2760 image_info->affirm=MagickTrue;
cristy151b66d2015-04-15 10:50:31 +00002761 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002762 }
2763 if (LocaleCompare(magic,"RGB") == 0)
2764 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2765 }
2766 /*
2767 Look for explicit 'format:image' in filename.
2768 */
2769 *magic='\0';
2770 GetPathComponent(image_info->filename,MagickPath,magic);
2771 if (*magic == '\0')
Cristya8079ac2016-06-02 16:07:24 -04002772 {
2773 (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2774 magick_info=GetMagickInfo(magic,sans_exception);
Cristy0093cff2016-06-05 19:00:17 -04002775 GetPathComponent(image_info->filename,CanonicalPath,component);
2776 (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
Cristya8079ac2016-06-02 16:07:24 -04002777 }
cristy3ed852e2009-09-05 21:47:34 +00002778 else
2779 {
Cristy446b7ac2016-06-06 09:18:22 -04002780 const DelegateInfo
2781 *delegate_info;
2782
cristy3ed852e2009-09-05 21:47:34 +00002783 /*
2784 User specified image format.
2785 */
2786 LocaleUpper(magic);
Cristya8079ac2016-06-02 16:07:24 -04002787 magick_info=GetMagickInfo(magic,sans_exception);
Cristy75904212016-06-06 09:28:53 -04002788 delegate_info=GetDelegateInfo(magic,"*",sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002789 if (delegate_info == (const DelegateInfo *) NULL)
Cristy75904212016-06-06 09:28:53 -04002790 delegate_info=GetDelegateInfo("*",magic,sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002791 if (((magick_info != (const MagickInfo *) NULL) ||
2792 (delegate_info != (const DelegateInfo *) NULL)) &&
Cristya8079ac2016-06-02 16:07:24 -04002793 (IsMagickConflict(magic) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002794 {
Cristyb831d902016-05-07 08:23:15 -04002795 image_info->affirm=MagickTrue;
Cristy446b7ac2016-06-06 09:18:22 -04002796 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
Cristy0093cff2016-06-05 19:00:17 -04002797 GetPathComponent(image_info->filename,CanonicalPath,component);
2798 (void) CopyMagickString(image_info->filename,component,
2799 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002800 }
2801 }
cristy3ed852e2009-09-05 21:47:34 +00002802 sans_exception=DestroyExceptionInfo(sans_exception);
2803 if ((magick_info == (const MagickInfo *) NULL) ||
2804 (GetMagickEndianSupport(magick_info) == MagickFalse))
2805 image_info->endian=UndefinedEndian;
cristyd965a422010-03-03 17:47:35 +00002806 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00002807 {
2808 /*
cristyd965a422010-03-03 17:47:35 +00002809 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00002810 */
cristyd965a422010-03-03 17:47:35 +00002811 (void) InterpretImageFilename(image_info,(Image *) NULL,
dirk8f681612015-04-16 21:05:08 +00002812 image_info->filename,(int) image_info->scene,component,exception);
2813 if ((LocaleCompare(component,image_info->filename) != 0) &&
2814 (strchr(component,'%') == (char *) NULL))
cristyd965a422010-03-03 17:47:35 +00002815 image_info->adjoin=MagickFalse;
2816 }
2817 if ((image_info->adjoin != MagickFalse) && (frames > 0))
2818 {
2819 /*
2820 Some image formats do not support multiple frames per file.
2821 */
cristy3ed852e2009-09-05 21:47:34 +00002822 magick_info=GetMagickInfo(magic,exception);
2823 if (magick_info != (const MagickInfo *) NULL)
2824 if (GetMagickAdjoin(magick_info) == MagickFalse)
2825 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002826 }
2827 if (image_info->affirm != MagickFalse)
2828 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00002829 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00002830 {
dirk8f681612015-04-16 21:05:08 +00002831 unsigned char
2832 *magick;
2833
2834 size_t
2835 magick_size;
2836
cristy3ed852e2009-09-05 21:47:34 +00002837 /*
cristyd965a422010-03-03 17:47:35 +00002838 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00002839 */
cristy4f06b882015-04-17 00:16:45 +00002840 magick_size=GetMagicPatternExtent(exception);
dirk8f681612015-04-16 21:05:08 +00002841 if (magick_size == 0)
2842 return(MagickFalse);
cristy9950d572011-10-01 18:22:35 +00002843 image=AcquireImage(image_info,exception);
cristyd965a422010-03-03 17:47:35 +00002844 (void) CopyMagickString(image->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00002845 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002846 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2847 if (status == MagickFalse)
2848 {
2849 image=DestroyImage(image);
2850 return(MagickFalse);
2851 }
cristyd965a422010-03-03 17:47:35 +00002852 if ((IsBlobSeekable(image) == MagickFalse) ||
2853 (IsBlobExempt(image) != MagickFalse))
2854 {
2855 /*
2856 Copy standard input or pipe to temporary file.
2857 */
dirk8f681612015-04-16 21:05:08 +00002858 *component='\0';
2859 status=ImageToFile(image,component,exception);
cristyd965a422010-03-03 17:47:35 +00002860 (void) CloseBlob(image);
2861 if (status == MagickFalse)
2862 {
2863 image=DestroyImage(image);
2864 return(MagickFalse);
2865 }
2866 SetImageInfoFile(image_info,(FILE *) NULL);
dirk8f681612015-04-16 21:05:08 +00002867 (void) CopyMagickString(image->filename,component,MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002868 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2869 if (status == MagickFalse)
2870 {
2871 image=DestroyImage(image);
2872 return(MagickFalse);
2873 }
cristyee2f5d62015-07-28 13:19:43 +00002874 (void) CopyMagickString(image_info->filename,component,
2875 MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002876 image_info->temporary=MagickTrue;
2877 }
dirk8f681612015-04-16 21:05:08 +00002878 magick=(unsigned char *) AcquireMagickMemory(magick_size);
2879 if (magick == (unsigned char *) NULL)
2880 {
2881 (void) CloseBlob(image);
2882 image=DestroyImage(image);
2883 return(MagickFalse);
2884 }
2885 (void) ResetMagickMemory(magick,0,magick_size);
2886 count=ReadBlob(image,magick_size,magick);
cristyae958042013-01-05 15:48:19 +00002887 (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
cristyd965a422010-03-03 17:47:35 +00002888 (void) CloseBlob(image);
2889 image=DestroyImage(image);
2890 /*
2891 Check magic.xml configuration file.
2892 */
2893 sans_exception=AcquireExceptionInfo();
2894 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
dirk8f681612015-04-16 21:05:08 +00002895 magick=(unsigned char *) RelinquishMagickMemory(magick);
cristyd965a422010-03-03 17:47:35 +00002896 if ((magic_info != (const MagicInfo *) NULL) &&
2897 (GetMagicName(magic_info) != (char *) NULL))
2898 {
dirkca89a9b2015-02-22 01:19:21 +00002899 /*
2900 Try to use magick_info that was determined earlier by the extension
2901 */
2902 if ((magick_info != (const MagickInfo *) NULL) &&
2903 (GetMagickUseExtension(magick_info) != MagickFalse) &&
2904 (LocaleCompare(magick_info->module,GetMagicName(
2905 magic_info)) == 0))
2906 (void) CopyMagickString(image_info->magick,magick_info->name,
cristy151b66d2015-04-15 10:50:31 +00002907 MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002908 else
2909 {
2910 (void) CopyMagickString(image_info->magick,GetMagicName(
cristy151b66d2015-04-15 10:50:31 +00002911 magic_info),MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002912 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2913 }
cristyd965a422010-03-03 17:47:35 +00002914 if ((magick_info == (const MagickInfo *) NULL) ||
2915 (GetMagickEndianSupport(magick_info) == MagickFalse))
2916 image_info->endian=UndefinedEndian;
2917 sans_exception=DestroyExceptionInfo(sans_exception);
2918 return(MagickTrue);
2919 }
cristy3ed852e2009-09-05 21:47:34 +00002920 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2921 if ((magick_info == (const MagickInfo *) NULL) ||
2922 (GetMagickEndianSupport(magick_info) == MagickFalse))
2923 image_info->endian=UndefinedEndian;
2924 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00002925 }
cristy3ed852e2009-09-05 21:47:34 +00002926 return(MagickTrue);
2927}
2928
2929/*
2930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931% %
2932% %
2933% %
2934% S e t I m a g e I n f o B l o b %
2935% %
2936% %
2937% %
2938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939%
2940% SetImageInfoBlob() sets the image info blob member.
2941%
2942% The format of the SetImageInfoBlob method is:
2943%
2944% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2945% const size_t length)
2946%
2947% A description of each parameter follows:
2948%
2949% o image_info: the image info.
2950%
2951% o blob: the blob.
2952%
2953% o length: the blob length.
2954%
2955*/
2956MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2957 const size_t length)
2958{
2959 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002960 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002961 if (image_info->debug != MagickFalse)
2962 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2963 image_info->filename);
2964 image_info->blob=(void *) blob;
2965 image_info->length=length;
2966}
2967
2968/*
2969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970% %
2971% %
2972% %
Cristy93452f02017-02-01 09:23:15 -05002973% S e t I m a g e I n f o C u s t o m S t r e a m %
2974% %
2975% %
2976% %
2977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2978%
2979% SetImageInfoCustomStream() sets the image info custom stream handlers.
2980%
2981% The format of the SetImageInfoCustomStream method is:
2982%
2983% void SetImageInfoCustomStream(ImageInfo *image_info,
2984% ssize_t (*reader)(const unsigned char *,const size_t,const void *),
2985% ssize_t (*writer)(const unsigned char *,const size_t,const void *),
2986% size_t (*seeker)(const MagickOffsetType,const int,const void *),
2987% MagickOffsetType (*teller)(const void *))
2988%
2989% A description of each parameter follows:
2990%
2991% o image_info: the image info.
2992%
2993% o reader: your custom stream reader.
2994%
2995% o writer: your custom stream writer.
2996%
2997% o seeker: your custom stream seeker.
2998%
2999% o teller: your custom stream teller.
3000%
3001*/
3002MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
3003 ssize_t (*reader)(const unsigned char *,const size_t,const void *),
3004 ssize_t (*writer)(const unsigned char *,const size_t,const void *),
3005 size_t (*seeker)(const MagickOffsetType,const int,const void *),
3006 MagickOffsetType (*teller)(const void *))
3007{
3008 assert(image_info != (ImageInfo *) NULL);
3009 assert(image_info->signature == MagickCoreSignature);
3010 if (image_info->debug != MagickFalse)
3011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3012 image_info->filename);
3013 SetBlobCustomStream(image_info->blob,reader,writer,seeker,teller);
3014}
3015
3016/*
3017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018% %
3019% %
3020% %
cristy3ed852e2009-09-05 21:47:34 +00003021% S e t I m a g e I n f o F i l e %
3022% %
3023% %
3024% %
3025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3026%
3027% SetImageInfoFile() sets the image info file member.
3028%
3029% The format of the SetImageInfoFile method is:
3030%
3031% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3032%
3033% A description of each parameter follows:
3034%
3035% o image_info: the image info.
3036%
3037% o file: the file.
3038%
3039*/
3040MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3041{
3042 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003043 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003044 if (image_info->debug != MagickFalse)
3045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3046 image_info->filename);
3047 image_info->file=file;
3048}
3049
3050/*
3051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052% %
3053% %
3054% %
3055% S e t I m a g e M a s k %
3056% %
3057% %
3058% %
3059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3060%
3061% SetImageMask() associates a mask with the image. The mask must be the same
3062% dimensions as the image.
3063%
3064% The format of the SetImageMask method is:
3065%
cristyacd0d4c2015-07-25 16:12:33 +00003066% MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3067% const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003068%
3069% A description of each parameter follows:
3070%
3071% o image: the image.
3072%
cristyacd0d4c2015-07-25 16:12:33 +00003073% o type: the mask type, ReadPixelMask or WritePixelMask.
3074%
cristy3ed852e2009-09-05 21:47:34 +00003075% o mask: the image mask.
3076%
cristy018f07f2011-09-04 21:15:19 +00003077% o exception: return any errors or warnings in this structure.
3078%
cristy3ed852e2009-09-05 21:47:34 +00003079*/
cristyacd0d4c2015-07-25 16:12:33 +00003080MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3081 const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003082{
cristy10a6c612012-01-29 21:41:05 +00003083 CacheView
3084 *mask_view,
3085 *image_view;
3086
3087 MagickBooleanType
3088 status;
3089
3090 ssize_t
3091 y;
3092
3093 /*
3094 Set image mask.
3095 */
cristy3ed852e2009-09-05 21:47:34 +00003096 assert(image != (Image *) NULL);
3097 if (image->debug != MagickFalse)
3098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003099 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00003100 if (mask == (const Image *) NULL)
3101 {
cristyacd0d4c2015-07-25 16:12:33 +00003102 switch (type)
3103 {
3104 case WritePixelMask: image->write_mask=MagickFalse; break;
3105 default: image->read_mask=MagickFalse; break;
3106 }
cristyd5be1f12013-03-18 23:55:01 +00003107 return(SyncImagePixelCache(image,exception));
cristy10a6c612012-01-29 21:41:05 +00003108 }
cristyacd0d4c2015-07-25 16:12:33 +00003109 switch (type)
3110 {
3111 case WritePixelMask: image->write_mask=MagickTrue; break;
3112 default: image->read_mask=MagickTrue; break;
3113 }
cristyd5be1f12013-03-18 23:55:01 +00003114 if (SyncImagePixelCache(image,exception) == MagickFalse)
3115 return(MagickFalse);
3116 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003117 mask_view=AcquireVirtualCacheView(mask,exception);
3118 image_view=AcquireAuthenticCacheView(image,exception);
cristyd5be1f12013-03-18 23:55:01 +00003119#if defined(MAGICKCORE_OPENMP_SUPPORT)
3120 #pragma omp parallel for schedule(static,4) shared(status) \
3121 magick_threads(mask,image,1,1)
3122#endif
cristy10a6c612012-01-29 21:41:05 +00003123 for (y=0; y < (ssize_t) image->rows; y++)
3124 {
3125 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003126 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00003127
3128 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003129 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00003130
3131 register ssize_t
3132 x;
3133
3134 if (status == MagickFalse)
3135 continue;
3136 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3137 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3138 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3139 {
3140 status=MagickFalse;
3141 continue;
3142 }
3143 for (x=0; x < (ssize_t) image->columns; x++)
3144 {
Cristy0596ce22015-11-20 21:11:22 -05003145 MagickRealType
3146 intensity;
3147
Cristy3761dd42016-12-03 09:54:21 -05003148 intensity=0;
Cristy4da63352016-12-03 08:59:32 -05003149 if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3150 intensity=GetPixelIntensity(mask,p);
cristyacd0d4c2015-07-25 16:12:33 +00003151 switch (type)
3152 {
3153 case WritePixelMask:
3154 {
Cristyd60923b2016-12-02 19:37:09 -05003155 SetPixelWriteMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003156 break;
3157 }
3158 default:
3159 {
Cristyd60923b2016-12-02 19:37:09 -05003160 SetPixelReadMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003161 break;
3162 }
3163 }
cristy10a6c612012-01-29 21:41:05 +00003164 p+=GetPixelChannels(mask);
3165 q+=GetPixelChannels(image);
3166 }
3167 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3168 status=MagickFalse;
3169 }
3170 mask_view=DestroyCacheView(mask_view);
3171 image_view=DestroyCacheView(image_view);
3172 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003173}
3174
3175/*
3176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3177% %
3178% %
3179% %
Cristy03811ea2016-07-27 20:32:47 -04003180% S e t I m a g e R e g i o n M a s k %
cristy3ed852e2009-09-05 21:47:34 +00003181% %
3182% %
3183% %
3184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3185%
Cristyd47057b2016-07-28 18:57:46 -04003186% SetImageRegionMask() associates a mask with the image as defined by the
3187% specified region.
cristy3ed852e2009-09-05 21:47:34 +00003188%
Cristy03811ea2016-07-27 20:32:47 -04003189% The format of the SetImageRegionMask method is:
cristy3ed852e2009-09-05 21:47:34 +00003190%
Cristy03811ea2016-07-27 20:32:47 -04003191% MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3192% const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003193%
3194% A description of each parameter follows:
3195%
3196% o image: the image.
3197%
Cristy03811ea2016-07-27 20:32:47 -04003198% o type: the mask type, ReadPixelMask or WritePixelMask.
3199%
3200% o geometry: the mask region.
3201%
3202% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00003203%
3204*/
Cristy03811ea2016-07-27 20:32:47 -04003205MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3206 const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003207{
3208 CacheView
3209 *image_view;
3210
cristy3ed852e2009-09-05 21:47:34 +00003211 MagickBooleanType
3212 status;
3213
cristycb6d09b2010-06-19 01:59:36 +00003214 ssize_t
3215 y;
3216
Cristy03811ea2016-07-27 20:32:47 -04003217 /*
3218 Set image mask as defined by the region.
3219 */
cristy3ed852e2009-09-05 21:47:34 +00003220 assert(image != (Image *) NULL);
3221 if (image->debug != MagickFalse)
3222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003223 assert(image->signature == MagickCoreSignature);
Cristy03811ea2016-07-27 20:32:47 -04003224 if (region == (const RectangleInfo *) NULL)
3225 {
3226 switch (type)
3227 {
3228 case WritePixelMask: image->write_mask=MagickFalse; break;
3229 default: image->read_mask=MagickFalse; break;
3230 }
3231 return(SyncImagePixelCache(image,exception));
3232 }
3233 switch (type)
3234 {
3235 case WritePixelMask: image->write_mask=MagickTrue; break;
3236 default: image->read_mask=MagickTrue; break;
3237 }
3238 if (SyncImagePixelCache(image,exception) == MagickFalse)
3239 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00003240 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003241 image_view=AcquireAuthenticCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00003242#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003243 #pragma omp parallel for schedule(static,4) shared(status) \
Cristy03811ea2016-07-27 20:32:47 -04003244 magick_threads(image,image,1,1)
cristy3ed852e2009-09-05 21:47:34 +00003245#endif
cristybb503372010-05-27 20:51:26 +00003246 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003247 {
cristy4c08aed2011-07-01 19:47:50 +00003248 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003249 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003250
cristycb6d09b2010-06-19 01:59:36 +00003251 register ssize_t
3252 x;
3253
cristy3ed852e2009-09-05 21:47:34 +00003254 if (status == MagickFalse)
3255 continue;
3256 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003257 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003258 {
3259 status=MagickFalse;
3260 continue;
3261 }
cristybb503372010-05-27 20:51:26 +00003262 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003263 {
Cristy36610622016-07-28 17:41:37 -04003264 Quantum
3265 pixel;
Cristy03811ea2016-07-27 20:32:47 -04003266
Cristy36610622016-07-28 17:41:37 -04003267 pixel=0;
Cristy338f0882016-12-10 12:12:35 -05003268 if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3269 ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
Cristy36610622016-07-28 17:41:37 -04003270 pixel=QuantumRange;
Cristy03811ea2016-07-27 20:32:47 -04003271 switch (type)
3272 {
3273 case WritePixelMask:
3274 {
Cristy36610622016-07-28 17:41:37 -04003275 SetPixelWriteMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003276 break;
3277 }
3278 default:
3279 {
Cristy36610622016-07-28 17:41:37 -04003280 SetPixelReadMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003281 break;
3282 }
3283 }
cristyed231572011-07-14 02:18:59 +00003284 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003285 }
3286 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3287 status=MagickFalse;
3288 }
3289 image_view=DestroyCacheView(image_view);
3290 return(status);
3291}
3292
3293/*
3294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3295% %
3296% %
3297% %
cristy3ed852e2009-09-05 21:47:34 +00003298% 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 %
3299% %
3300% %
3301% %
3302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3303%
3304% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3305% image and returns the previous setting. A virtual pixel is any pixel access
3306% that is outside the boundaries of the image cache.
3307%
3308% The format of the SetImageVirtualPixelMethod() method is:
3309%
cristy387430f2012-02-07 13:09:46 +00003310% VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3311% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003312%
3313% A description of each parameter follows:
3314%
3315% o image: the image.
3316%
3317% o virtual_pixel_method: choose the type of virtual pixel.
3318%
cristy387430f2012-02-07 13:09:46 +00003319% o exception: return any errors or warnings in this structure.
3320%
cristy3ed852e2009-09-05 21:47:34 +00003321*/
cristy387430f2012-02-07 13:09:46 +00003322MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3323 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003324{
3325 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003326 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003327 if (image->debug != MagickFalse)
3328 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy387430f2012-02-07 13:09:46 +00003329 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
cristy3ed852e2009-09-05 21:47:34 +00003330}
3331
3332/*
3333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3334% %
3335% %
3336% %
cristy4285d782011-02-09 20:12:28 +00003337% S m u s h I m a g e s %
3338% %
3339% %
3340% %
3341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3342%
3343% SmushImages() takes all images from the current image pointer to the end
3344% of the image list and smushes them to each other top-to-bottom if the
3345% stack parameter is true, otherwise left-to-right.
3346%
3347% The current gravity setting now effects how the image is justified in the
3348% final image.
3349%
3350% The format of the SmushImages method is:
3351%
cristy4ca38e22011-02-10 02:57:49 +00003352% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003353% ExceptionInfo *exception)
3354%
3355% A description of each parameter follows:
3356%
cristy4ca38e22011-02-10 02:57:49 +00003357% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003358%
3359% o stack: A value other than 0 stacks the images top-to-bottom.
3360%
3361% o offset: minimum distance in pixels between images.
3362%
3363% o exception: return any errors or warnings in this structure.
3364%
3365*/
cristy4ca38e22011-02-10 02:57:49 +00003366
cristy7c6dc152011-02-11 14:10:55 +00003367static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003368 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003369{
cristy4d727152011-02-10 19:57:21 +00003370 CacheView
3371 *left_view,
3372 *right_view;
3373
3374 const Image
3375 *left_image,
3376 *right_image;
3377
cristy4d727152011-02-10 19:57:21 +00003378 RectangleInfo
3379 left_geometry,
3380 right_geometry;
3381
cristy4c08aed2011-07-01 19:47:50 +00003382 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003383 *p;
3384
cristy4d727152011-02-10 19:57:21 +00003385 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003386 i,
cristy4d727152011-02-10 19:57:21 +00003387 y;
3388
cristy7c6dc152011-02-11 14:10:55 +00003389 size_t
3390 gap;
3391
cristy4d727152011-02-10 19:57:21 +00003392 ssize_t
cristy4d727152011-02-10 19:57:21 +00003393 x;
3394
3395 if (images->previous == (Image *) NULL)
3396 return(0);
3397 right_image=images;
3398 SetGeometry(smush_image,&right_geometry);
3399 GravityAdjustGeometry(right_image->columns,right_image->rows,
3400 right_image->gravity,&right_geometry);
3401 left_image=images->previous;
3402 SetGeometry(smush_image,&left_geometry);
3403 GravityAdjustGeometry(left_image->columns,left_image->rows,
3404 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003405 gap=right_image->columns;
cristy46ff2672012-12-14 15:32:26 +00003406 left_view=AcquireVirtualCacheView(left_image,exception);
3407 right_view=AcquireVirtualCacheView(right_image,exception);
cristy4d727152011-02-10 19:57:21 +00003408 for (y=0; y < (ssize_t) smush_image->rows; y++)
3409 {
3410 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3411 {
cristydab7e912011-02-11 18:19:24 +00003412 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003413 if ((p == (const Quantum *) NULL) ||
3414 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003415 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003416 break;
3417 }
cristy4ef6f062011-02-10 20:30:22 +00003418 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003419 for (x=0; x < (ssize_t) right_image->columns; x++)
3420 {
cristydab7e912011-02-11 18:19:24 +00003421 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003422 exception);
cristy4c08aed2011-07-01 19:47:50 +00003423 if ((p == (const Quantum *) NULL) ||
3424 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3425 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003426 break;
3427 }
cristy7c6dc152011-02-11 14:10:55 +00003428 if ((x+i) < (ssize_t) gap)
3429 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003430 }
3431 right_view=DestroyCacheView(right_view);
3432 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003433 if (y < (ssize_t) smush_image->rows)
3434 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003435 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003436}
3437
cristy7c6dc152011-02-11 14:10:55 +00003438static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003439 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003440{
cristy4d727152011-02-10 19:57:21 +00003441 CacheView
3442 *bottom_view,
3443 *top_view;
3444
3445 const Image
3446 *bottom_image,
3447 *top_image;
3448
cristy4d727152011-02-10 19:57:21 +00003449 RectangleInfo
3450 bottom_geometry,
3451 top_geometry;
3452
cristy4c08aed2011-07-01 19:47:50 +00003453 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003454 *p;
3455
cristy4d727152011-02-10 19:57:21 +00003456 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003457 i,
cristy4d727152011-02-10 19:57:21 +00003458 x;
3459
cristy7c6dc152011-02-11 14:10:55 +00003460 size_t
3461 gap;
3462
cristy4d727152011-02-10 19:57:21 +00003463 ssize_t
cristy4d727152011-02-10 19:57:21 +00003464 y;
3465
3466 if (images->previous == (Image *) NULL)
3467 return(0);
3468 bottom_image=images;
3469 SetGeometry(smush_image,&bottom_geometry);
3470 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3471 bottom_image->gravity,&bottom_geometry);
3472 top_image=images->previous;
3473 SetGeometry(smush_image,&top_geometry);
3474 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3475 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003476 gap=bottom_image->rows;
cristy46ff2672012-12-14 15:32:26 +00003477 top_view=AcquireVirtualCacheView(top_image,exception);
3478 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
cristy4d727152011-02-10 19:57:21 +00003479 for (x=0; x < (ssize_t) smush_image->columns; x++)
3480 {
3481 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3482 {
cristydab7e912011-02-11 18:19:24 +00003483 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003484 if ((p == (const Quantum *) NULL) ||
3485 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3486 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003487 break;
3488 }
cristy4ef6f062011-02-10 20:30:22 +00003489 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003490 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3491 {
cristydab7e912011-02-11 18:19:24 +00003492 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3493 exception);
cristy4c08aed2011-07-01 19:47:50 +00003494 if ((p == (const Quantum *) NULL) ||
3495 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3496 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003497 break;
3498 }
cristy7c6dc152011-02-11 14:10:55 +00003499 if ((y+i) < (ssize_t) gap)
3500 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003501 }
3502 bottom_view=DestroyCacheView(bottom_view);
3503 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003504 if (x < (ssize_t) smush_image->columns)
3505 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003506 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003507}
3508
3509MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003510 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3511{
3512#define SmushImageTag "Smush/Image"
3513
cristy4ca38e22011-02-10 02:57:49 +00003514 const Image
3515 *image;
3516
cristy4285d782011-02-09 20:12:28 +00003517 Image
3518 *smush_image;
3519
3520 MagickBooleanType
cristy4285d782011-02-09 20:12:28 +00003521 proceed,
3522 status;
3523
3524 MagickOffsetType
3525 n;
3526
cristy5a5e4d92012-08-29 00:06:25 +00003527 PixelTrait
3528 alpha_trait;
3529
cristy4285d782011-02-09 20:12:28 +00003530 RectangleInfo
3531 geometry;
3532
3533 register const Image
3534 *next;
3535
3536 size_t
3537 height,
3538 number_images,
3539 width;
3540
3541 ssize_t
3542 x_offset,
cristy4285d782011-02-09 20:12:28 +00003543 y_offset;
3544
3545 /*
cristy7c6dc152011-02-11 14:10:55 +00003546 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003547 */
cristy4ca38e22011-02-10 02:57:49 +00003548 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003549 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003550 if (images->debug != MagickFalse)
3551 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003552 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003553 assert(exception->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003554 image=images;
cristy5a5e4d92012-08-29 00:06:25 +00003555 alpha_trait=image->alpha_trait;
cristy4285d782011-02-09 20:12:28 +00003556 number_images=1;
3557 width=image->columns;
3558 height=image->rows;
3559 next=GetNextImageInList(image);
3560 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3561 {
cristy17f11b02014-12-20 19:37:04 +00003562 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +00003563 alpha_trait=BlendPixelTrait;
cristy4285d782011-02-09 20:12:28 +00003564 number_images++;
3565 if (stack != MagickFalse)
3566 {
3567 if (next->columns > width)
3568 width=next->columns;
3569 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003570 if (next->previous != (Image *) NULL)
3571 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003572 continue;
3573 }
3574 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003575 if (next->previous != (Image *) NULL)
3576 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003577 if (next->rows > height)
3578 height=next->rows;
3579 }
3580 /*
cristy7c6dc152011-02-11 14:10:55 +00003581 Smush images.
cristy4285d782011-02-09 20:12:28 +00003582 */
3583 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3584 if (smush_image == (Image *) NULL)
3585 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003586 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003587 {
cristy4285d782011-02-09 20:12:28 +00003588 smush_image=DestroyImage(smush_image);
3589 return((Image *) NULL);
3590 }
cristy5a5e4d92012-08-29 00:06:25 +00003591 smush_image->alpha_trait=alpha_trait;
cristyea1a8aa2011-10-20 13:24:06 +00003592 (void) SetImageBackgroundColor(smush_image,exception);
cristy4285d782011-02-09 20:12:28 +00003593 status=MagickTrue;
3594 x_offset=0;
3595 y_offset=0;
cristy4285d782011-02-09 20:12:28 +00003596 for (n=0; n < (MagickOffsetType) number_images; n++)
3597 {
3598 SetGeometry(smush_image,&geometry);
3599 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3600 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003601 {
3602 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003603 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003604 }
cristy4285d782011-02-09 20:12:28 +00003605 else
cristy4ca38e22011-02-10 02:57:49 +00003606 {
cristy7c6dc152011-02-11 14:10:55 +00003607 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003608 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00003609 }
cristy39172402012-03-30 13:04:39 +00003610 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3611 y_offset,exception);
cristy4285d782011-02-09 20:12:28 +00003612 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3613 if (proceed == MagickFalse)
3614 break;
3615 if (stack == MagickFalse)
3616 {
3617 x_offset+=(ssize_t) image->columns;
3618 y_offset=0;
3619 }
3620 else
3621 {
3622 x_offset=0;
3623 y_offset+=(ssize_t) image->rows;
3624 }
3625 image=GetNextImageInList(image);
3626 }
cristy4ef6f062011-02-10 20:30:22 +00003627 if (stack == MagickFalse)
3628 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00003629 else
cristy4ef6f062011-02-10 20:30:22 +00003630 smush_image->rows=(size_t) y_offset;
cristy4285d782011-02-09 20:12:28 +00003631 if (status == MagickFalse)
3632 smush_image=DestroyImage(smush_image);
3633 return(smush_image);
3634}
3635
3636/*
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638% %
3639% %
3640% %
cristy3ed852e2009-09-05 21:47:34 +00003641% S t r i p I m a g e %
3642% %
3643% %
3644% %
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%
cristy376bda92009-12-22 21:15:23 +00003647% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00003648%
3649% The format of the StripImage method is:
3650%
cristye941a752011-10-15 01:52:48 +00003651% MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003652%
3653% A description of each parameter follows:
3654%
3655% o image: the image.
3656%
cristye941a752011-10-15 01:52:48 +00003657% o exception: return any errors or warnings in this structure.
3658%
cristy3ed852e2009-09-05 21:47:34 +00003659*/
cristye941a752011-10-15 01:52:48 +00003660MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003661{
cristye941a752011-10-15 01:52:48 +00003662 MagickBooleanType
3663 status;
3664
cristy3ed852e2009-09-05 21:47:34 +00003665 assert(image != (Image *) NULL);
3666 if (image->debug != MagickFalse)
3667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye941a752011-10-15 01:52:48 +00003668 (void) exception;
cristy3ed852e2009-09-05 21:47:34 +00003669 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00003670 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00003671 (void) DeleteImageProperty(image,"date:create");
3672 (void) DeleteImageProperty(image,"date:modify");
cristy42e14902014-05-01 22:40:40 +00003673 status=SetImageArtifact(image,"png:exclude-chunk",
Cristy8c2e6b42016-04-02 10:14:03 -04003674 "bKGD,cHRM,EXIF,gAMA,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
cristye941a752011-10-15 01:52:48 +00003675 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003676}
3677
3678/*
3679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3680% %
3681% %
3682% %
3683+ S y n c I m a g e %
3684% %
3685% %
3686% %
3687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3688%
3689% SyncImage() initializes the red, green, and blue intensities of each pixel
3690% as defined by the colormap index.
3691%
3692% The format of the SyncImage method is:
3693%
cristyea1a8aa2011-10-20 13:24:06 +00003694% MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003695%
3696% A description of each parameter follows:
3697%
3698% o image: the image.
3699%
cristyea1a8aa2011-10-20 13:24:06 +00003700% o exception: return any errors or warnings in this structure.
3701%
cristy3ed852e2009-09-05 21:47:34 +00003702*/
3703
cristyaedc0312012-01-08 01:07:37 +00003704static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3705 MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00003706{
cristyc8d63672012-01-11 13:03:13 +00003707 if ((size_t) index < image->colors)
cristyaedc0312012-01-08 01:07:37 +00003708 return(index);
cristy3ed852e2009-09-05 21:47:34 +00003709 *range_exception=MagickTrue;
cristyd9657d22012-08-23 14:25:31 +00003710 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00003711}
3712
cristyea1a8aa2011-10-20 13:24:06 +00003713MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003714{
3715 CacheView
3716 *image_view;
3717
cristy3ed852e2009-09-05 21:47:34 +00003718 MagickBooleanType
3719 range_exception,
dirkf5cb0472014-10-24 20:10:14 +00003720 status,
3721 taint;
cristy3ed852e2009-09-05 21:47:34 +00003722
cristycb6d09b2010-06-19 01:59:36 +00003723 ssize_t
3724 y;
3725
cristy3ed852e2009-09-05 21:47:34 +00003726 assert(image != (Image *) NULL);
3727 if (image->debug != MagickFalse)
3728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003729 assert(image->signature == MagickCoreSignature);
Cristye299a6f2017-01-20 08:00:35 -05003730 if (image->ping != MagickFalse)
3731 return(MagickTrue);
Cristye90afbe2017-01-02 19:10:34 -05003732 if (image->storage_class != PseudoClass)
cristy3ed852e2009-09-05 21:47:34 +00003733 return(MagickFalse);
Cristye90afbe2017-01-02 19:10:34 -05003734 assert(image->colormap != (PixelInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003735 range_exception=MagickFalse;
3736 status=MagickTrue;
dirkf5cb0472014-10-24 20:10:14 +00003737 taint=image->taint;
cristy46ff2672012-12-14 15:32:26 +00003738 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00003739#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003740 #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
cristy5e6b2592012-12-19 14:08:11 +00003741 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00003742#endif
cristybb503372010-05-27 20:51:26 +00003743 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003744 {
cristy4c08aed2011-07-01 19:47:50 +00003745 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003746 index;
3747
cristy4c08aed2011-07-01 19:47:50 +00003748 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003749 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003750
cristycb6d09b2010-06-19 01:59:36 +00003751 register ssize_t
3752 x;
3753
cristy48974b92009-12-19 02:36:06 +00003754 if (status == MagickFalse)
3755 continue;
cristy3ed852e2009-09-05 21:47:34 +00003756 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003757 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003758 {
3759 status=MagickFalse;
3760 continue;
3761 }
cristybb503372010-05-27 20:51:26 +00003762 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003763 {
cristyaedc0312012-01-08 01:07:37 +00003764 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
cristy11a06d32015-01-04 12:03:27 +00003765 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00003766 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003767 }
3768 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3769 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003770 }
3771 image_view=DestroyCacheView(image_view);
dirkf5cb0472014-10-24 20:10:14 +00003772 image->taint=taint;
cristycaf45802012-06-16 18:28:54 +00003773 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
dirkb081bb22016-01-27 12:56:48 +01003774 (void) ThrowMagickException(exception,GetMagickModule(),
3775 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003776 return(status);
3777}
cristy1626d332009-11-10 16:58:17 +00003778
3779/*
3780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3781% %
3782% %
3783% %
3784% S y n c I m a g e S e t t i n g s %
3785% %
3786% %
3787% %
3788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3789%
anthony5f78bca2012-10-05 06:51:00 +00003790% SyncImageSettings() syncs any image_info global options into per-image
3791% attributes.
3792%
anthonyc7994672012-11-17 05:33:27 +00003793% Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
anthony5f78bca2012-10-05 06:51:00 +00003794% that operations and coders can find such settings. In IMv7 if a desired
3795% per-image artifact is not set, then it will directly look for a global
anthonyc7994672012-11-17 05:33:27 +00003796% option as a fallback, as such this copy is no longer needed, only the
3797% link set up.
cristy1626d332009-11-10 16:58:17 +00003798%
3799% The format of the SyncImageSettings method is:
3800%
3801% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003802% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003803% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003804% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003805%
3806% A description of each parameter follows:
3807%
3808% o image_info: the image info.
3809%
3810% o image: the image.
3811%
cristy6fccee12011-10-20 18:43:18 +00003812% o exception: return any errors or warnings in this structure.
3813%
cristy1626d332009-11-10 16:58:17 +00003814*/
3815
3816MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003817 Image *images,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003818{
3819 Image
3820 *image;
3821
3822 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003823 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003824 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003825 assert(images->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003826 if (images->debug != MagickFalse)
3827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3828 image=images;
3829 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
cristy6fccee12011-10-20 18:43:18 +00003830 (void) SyncImageSettings(image_info,image,exception);
cristy1626d332009-11-10 16:58:17 +00003831 (void) DeleteImageOption(image_info,"page");
3832 return(MagickTrue);
3833}
3834
3835MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003836 Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003837{
cristy1626d332009-11-10 16:58:17 +00003838 const char
cristy202c1482012-10-05 23:47:57 +00003839 *option;
cristy1626d332009-11-10 16:58:17 +00003840
3841 GeometryInfo
3842 geometry_info;
3843
3844 MagickStatusType
3845 flags;
3846
cristy19eb6412010-04-23 14:42:29 +00003847 ResolutionType
3848 units;
3849
cristy1626d332009-11-10 16:58:17 +00003850 /*
3851 Sync image options.
3852 */
3853 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003854 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003855 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003856 assert(image->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003857 if (image->debug != MagickFalse)
3858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
dirkb797b2c2016-02-01 22:20:32 +01003859 option=GetImageOption(image_info,"alpha-color");
3860 if (option != (const char *) NULL)
3861 (void) QueryColorCompliance(option,AllCompliance,&image->alpha_color,
3862 exception);
cristy1626d332009-11-10 16:58:17 +00003863 option=GetImageOption(image_info,"background");
3864 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003865 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
cristy6fccee12011-10-20 18:43:18 +00003866 exception);
cristy1626d332009-11-10 16:58:17 +00003867 option=GetImageOption(image_info,"black-point-compensation");
3868 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003869 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003870 MagickBooleanOptions,MagickFalse,option);
3871 option=GetImageOption(image_info,"blue-primary");
3872 if (option != (const char *) NULL)
3873 {
3874 flags=ParseGeometry(option,&geometry_info);
3875 image->chromaticity.blue_primary.x=geometry_info.rho;
3876 image->chromaticity.blue_primary.y=geometry_info.sigma;
3877 if ((flags & SigmaValue) == 0)
3878 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3879 }
3880 option=GetImageOption(image_info,"bordercolor");
3881 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003882 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
cristy6fccee12011-10-20 18:43:18 +00003883 exception);
anthony72feaa62012-01-17 06:46:23 +00003884 /* FUTURE: do not sync compose to per-image compose setting here */
cristy1626d332009-11-10 16:58:17 +00003885 option=GetImageOption(image_info,"compose");
3886 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003887 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00003888 MagickFalse,option);
anthony72feaa62012-01-17 06:46:23 +00003889 /* -- */
cristy1626d332009-11-10 16:58:17 +00003890 option=GetImageOption(image_info,"compress");
3891 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003892 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003893 MagickCompressOptions,MagickFalse,option);
3894 option=GetImageOption(image_info,"debug");
3895 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003896 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003897 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00003898 option=GetImageOption(image_info,"density");
3899 if (option != (const char *) NULL)
3900 {
cristydd5f5912010-07-31 23:37:23 +00003901 flags=ParseGeometry(option,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +00003902 image->resolution.x=geometry_info.rho;
3903 image->resolution.y=geometry_info.sigma;
cristydd5f5912010-07-31 23:37:23 +00003904 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +00003905 image->resolution.y=image->resolution.x;
cristydd5f5912010-07-31 23:37:23 +00003906 }
cristy1626d332009-11-10 16:58:17 +00003907 option=GetImageOption(image_info,"depth");
3908 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003909 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003910 option=GetImageOption(image_info,"endian");
3911 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003912 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00003913 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003914 option=GetImageOption(image_info,"filter");
3915 if (option != (const char *) NULL)
dirk8b9f21c2016-02-01 22:30:19 +01003916 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00003917 MagickFalse,option);
3918 option=GetImageOption(image_info,"fuzz");
3919 if (option != (const char *) NULL)
cristydbdd0e32011-11-04 23:29:40 +00003920 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
cristy1626d332009-11-10 16:58:17 +00003921 option=GetImageOption(image_info,"gravity");
3922 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003923 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00003924 MagickFalse,option);
3925 option=GetImageOption(image_info,"green-primary");
3926 if (option != (const char *) NULL)
3927 {
3928 flags=ParseGeometry(option,&geometry_info);
3929 image->chromaticity.green_primary.x=geometry_info.rho;
3930 image->chromaticity.green_primary.y=geometry_info.sigma;
3931 if ((flags & SigmaValue) == 0)
3932 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
3933 }
3934 option=GetImageOption(image_info,"intent");
3935 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003936 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003937 MagickIntentOptions,MagickFalse,option);
cristy313634e2013-03-26 00:52:19 +00003938 option=GetImageOption(image_info,"intensity");
3939 if (option != (const char *) NULL)
3940 image->intensity=(PixelIntensityMethod) ParseCommandOption(
3941 MagickPixelIntensityOptions,MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003942 option=GetImageOption(image_info,"interlace");
3943 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003944 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00003945 MagickFalse,option);
3946 option=GetImageOption(image_info,"interpolate");
3947 if (option != (const char *) NULL)
cristy5c4e2582011-09-11 19:21:03 +00003948 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003949 MagickInterpolateOptions,MagickFalse,option);
3950 option=GetImageOption(image_info,"loop");
3951 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003952 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003953 option=GetImageOption(image_info,"orient");
3954 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003955 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003956 MagickOrientationOptions,MagickFalse,option);
cristy14ed6a22013-12-28 23:48:05 +00003957 option=GetImageOption(image_info,"page");
3958 if (option != (const char *) NULL)
3959 {
3960 char
3961 *geometry;
3962
3963 geometry=GetPageGeometry(option);
3964 flags=ParseAbsoluteGeometry(geometry,&image->page);
3965 geometry=DestroyString(geometry);
3966 }
cristy1626d332009-11-10 16:58:17 +00003967 option=GetImageOption(image_info,"quality");
3968 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003969 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003970 option=GetImageOption(image_info,"red-primary");
3971 if (option != (const char *) NULL)
3972 {
3973 flags=ParseGeometry(option,&geometry_info);
3974 image->chromaticity.red_primary.x=geometry_info.rho;
3975 image->chromaticity.red_primary.y=geometry_info.sigma;
3976 if ((flags & SigmaValue) == 0)
3977 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
3978 }
3979 if (image_info->quality != UndefinedCompressionQuality)
3980 image->quality=image_info->quality;
3981 option=GetImageOption(image_info,"scene");
3982 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003983 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003984 option=GetImageOption(image_info,"taint");
3985 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003986 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003987 MagickFalse,option);
3988 option=GetImageOption(image_info,"tile-offset");
3989 if (option != (const char *) NULL)
3990 {
3991 char
3992 *geometry;
3993
3994 geometry=GetPageGeometry(option);
3995 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
3996 geometry=DestroyString(geometry);
3997 }
3998 option=GetImageOption(image_info,"transparent-color");
3999 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00004000 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
cristy6fccee12011-10-20 18:43:18 +00004001 exception);
cristy1626d332009-11-10 16:58:17 +00004002 option=GetImageOption(image_info,"type");
4003 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004004 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00004005 option);
4006 option=GetImageOption(image_info,"units");
cristyc8d63672012-01-11 13:03:13 +00004007 units=image_info->units;
cristy1626d332009-11-10 16:58:17 +00004008 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00004009 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00004010 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00004011 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00004012 {
cristy19eb6412010-04-23 14:42:29 +00004013 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00004014 switch (image->units)
4015 {
4016 case PixelsPerInchResolution:
4017 {
cristy19eb6412010-04-23 14:42:29 +00004018 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00004019 {
cristy2a11bef2011-10-28 18:33:11 +00004020 image->resolution.x/=2.54;
4021 image->resolution.y/=2.54;
cristy1626d332009-11-10 16:58:17 +00004022 }
4023 break;
4024 }
4025 case PixelsPerCentimeterResolution:
4026 {
cristy19eb6412010-04-23 14:42:29 +00004027 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00004028 {
cristy2a11bef2011-10-28 18:33:11 +00004029 image->resolution.x=(double) ((size_t) (100.0*2.54*
4030 image->resolution.x+0.5))/100.0;
4031 image->resolution.y=(double) ((size_t) (100.0*2.54*
4032 image->resolution.y+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00004033 }
4034 break;
4035 }
4036 default:
4037 break;
4038 }
cristy19eb6412010-04-23 14:42:29 +00004039 image->units=units;
cristy1626d332009-11-10 16:58:17 +00004040 }
anthonyfd706f92012-01-19 04:22:02 +00004041 option=GetImageOption(image_info,"virtual-pixel");
4042 if (option != (const char *) NULL)
cristy387430f2012-02-07 13:09:46 +00004043 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
4044 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
4045 exception);
cristy1626d332009-11-10 16:58:17 +00004046 option=GetImageOption(image_info,"white-point");
4047 if (option != (const char *) NULL)
4048 {
4049 flags=ParseGeometry(option,&geometry_info);
4050 image->chromaticity.white_point.x=geometry_info.rho;
4051 image->chromaticity.white_point.y=geometry_info.sigma;
4052 if ((flags & SigmaValue) == 0)
4053 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4054 }
Cristy9c282cc2015-08-29 17:37:22 -04004055 /*
4056 Pointer to allow the lookup of pre-image artifact will fallback to a global
4057 option setting/define. This saves a lot of duplication of global options
4058 into per-image artifacts, while ensuring only specifically set per-image
4059 artifacts are preserved when parenthesis ends.
anthony643c6132012-11-07 14:50:28 +00004060 */
dirk98d3e1c2015-08-28 21:09:11 +02004061 if (image->image_info != (ImageInfo *) NULL)
4062 image->image_info=DestroyImageInfo(image->image_info);
Cristy36421ee2015-08-28 11:58:20 -04004063 image->image_info=CloneImageInfo(image_info);
cristy1626d332009-11-10 16:58:17 +00004064 return(MagickTrue);
4065}