blob: a07421b0e37374bef4d84430226a631a032d0089 [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;
cristyea1a8aa2011-10-20 13:24:06 +0000531 (void) SetImageBackgroundColor(append_image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000532 status=MagickTrue;
533 x_offset=0;
534 y_offset=0;
cristyeeebdde2012-04-14 16:29:34 +0000535 next=images;
cristy46ff2672012-12-14 15:32:26 +0000536 append_view=AcquireAuthenticCacheView(append_image,exception);
cristybb503372010-05-27 20:51:26 +0000537 for (n=0; n < (MagickOffsetType) number_images; n++)
cristy3ed852e2009-09-05 21:47:34 +0000538 {
cristyeeebdde2012-04-14 16:29:34 +0000539 CacheView
540 *image_view;
541
cristy9eed59f2013-02-19 15:26:48 +0000542 MagickBooleanType
543 proceed;
544
cristy3ed852e2009-09-05 21:47:34 +0000545 SetGeometry(append_image,&geometry);
Cristyc1e19262016-02-05 07:54:16 -0500546 GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
cristy3ed852e2009-09-05 21:47:34 +0000547 if (stack != MagickFalse)
548 x_offset-=geometry.x;
549 else
550 y_offset-=geometry.y;
Cristyc1e19262016-02-05 07:54:16 -0500551 image_view=AcquireVirtualCacheView(next,exception);
cristyb5d5f722009-11-04 03:03:49 +0000552#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000553 #pragma omp parallel for schedule(static,4) shared(status) \
Cristyc1e19262016-02-05 07:54:16 -0500554 magick_threads(next,next,next->rows,1)
cristy3ed852e2009-09-05 21:47:34 +0000555#endif
Cristyc1e19262016-02-05 07:54:16 -0500556 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000557 {
558 MagickBooleanType
559 sync;
560
cristye14e3202012-04-11 18:48:17 +0000561 PixelInfo
562 pixel;
563
cristy4c08aed2011-07-01 19:47:50 +0000564 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +0100565 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000566
cristy4c08aed2011-07-01 19:47:50 +0000567 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100568 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000569
cristycb6d09b2010-06-19 01:59:36 +0000570 register ssize_t
571 x;
572
cristy3ed852e2009-09-05 21:47:34 +0000573 if (status == MagickFalse)
574 continue;
Cristyc1e19262016-02-05 07:54:16 -0500575 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000576 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
Cristyc1e19262016-02-05 07:54:16 -0500577 next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000578 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000579 {
580 status=MagickFalse;
581 continue;
582 }
Cristyc1e19262016-02-05 07:54:16 -0500583 GetPixelInfo(next,&pixel);
584 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000585 {
Cristydf5e8b12016-12-02 17:26:39 -0500586 if (GetPixelWriteMask(next,p) == 0)
cristy10a6c612012-01-29 21:41:05 +0000587 {
cristyc3a58022013-10-09 23:22:42 +0000588 SetPixelBackgoundColor(append_image,q);
Cristyc1e19262016-02-05 07:54:16 -0500589 p+=GetPixelChannels(next);
cristy10a6c612012-01-29 21:41:05 +0000590 q+=GetPixelChannels(append_image);
591 continue;
592 }
Cristyc1e19262016-02-05 07:54:16 -0500593 GetPixelInfoPixel(next,p,&pixel);
cristy11a06d32015-01-04 12:03:27 +0000594 SetPixelViaPixelInfo(append_image,&pixel,q);
Cristyc1e19262016-02-05 07:54:16 -0500595 p+=GetPixelChannels(next);
cristyed231572011-07-14 02:18:59 +0000596 q+=GetPixelChannels(append_image);
cristy3ed852e2009-09-05 21:47:34 +0000597 }
598 sync=SyncCacheViewAuthenticPixels(append_view,exception);
599 if (sync == MagickFalse)
cristya65f35b2010-04-20 01:10:41 +0000600 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000601 }
602 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000603 if (stack == MagickFalse)
604 {
Cristyc1e19262016-02-05 07:54:16 -0500605 x_offset+=(ssize_t) next->columns;
cristy3ed852e2009-09-05 21:47:34 +0000606 y_offset=0;
607 }
608 else
609 {
610 x_offset=0;
Cristyc1e19262016-02-05 07:54:16 -0500611 y_offset+=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000612 }
cristyeeebdde2012-04-14 16:29:34 +0000613 proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
614 if (proceed == MagickFalse)
615 break;
616 next=GetNextImageInList(next);
cristy3ed852e2009-09-05 21:47:34 +0000617 }
618 append_view=DestroyCacheView(append_view);
619 if (status == MagickFalse)
620 append_image=DestroyImage(append_image);
621 return(append_image);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
cristy3ed852e2009-09-05 21:47:34 +0000629% C a t c h I m a g e E x c e p t i o n %
630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634%
635% CatchImageException() returns if no exceptions are found in the image
636% sequence, otherwise it determines the most severe exception and reports
637% it as a warning or error depending on the severity.
638%
639% The format of the CatchImageException method is:
640%
641% ExceptionType CatchImageException(Image *image)
642%
643% A description of each parameter follows:
644%
645% o image: An image sequence.
646%
647*/
648MagickExport ExceptionType CatchImageException(Image *image)
649{
650 ExceptionInfo
651 *exception;
652
653 ExceptionType
654 severity;
655
656 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000657 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000658 if (image->debug != MagickFalse)
659 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
660 exception=AcquireExceptionInfo();
cristy3ed852e2009-09-05 21:47:34 +0000661 CatchException(exception);
662 severity=exception->severity;
663 exception=DestroyExceptionInfo(exception);
664 return(severity);
665}
666
667/*
668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669% %
670% %
671% %
672% C l i p I m a g e P a t h %
673% %
674% %
675% %
676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677%
678% ClipImagePath() sets the image clip mask based any clipping path information
679% if it exists.
680%
681% The format of the ClipImagePath method is:
682%
683% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000684% const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000685%
686% A description of each parameter follows:
687%
688% o image: the image.
689%
690% o pathname: name of clipping path resource. If name is preceded by #, use
691% clipping path numbered by name.
692%
693% o inside: if non-zero, later operations take effect inside clipping path.
694% Otherwise later operations take effect outside clipping path.
695%
cristy018f07f2011-09-04 21:15:19 +0000696% o exception: return any errors or warnings in this structure.
697%
cristy3ed852e2009-09-05 21:47:34 +0000698*/
699
cristy018f07f2011-09-04 21:15:19 +0000700MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000701{
cristy018f07f2011-09-04 21:15:19 +0000702 return(ClipImagePath(image,"#1",MagickTrue,exception));
cristy3ed852e2009-09-05 21:47:34 +0000703}
704
705MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
cristy018f07f2011-09-04 21:15:19 +0000706 const MagickBooleanType inside,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000707{
708#define ClipImagePathTag "ClipPath/Image"
709
710 char
711 *property;
712
713 const char
714 *value;
715
716 Image
717 *clip_mask;
718
719 ImageInfo
720 *image_info;
721
722 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000723 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000724 if (image->debug != MagickFalse)
725 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
726 assert(pathname != NULL);
727 property=AcquireString(pathname);
cristy151b66d2015-04-15 10:50:31 +0000728 (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
cristy3ed852e2009-09-05 21:47:34 +0000729 pathname);
cristyd15e6592011-10-15 00:13:06 +0000730 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +0000731 property=DestroyString(property);
732 if (value == (const char *) NULL)
733 {
cristy6fccee12011-10-20 18:43:18 +0000734 ThrowFileException(exception,OptionError,"NoClipPathDefined",
cristy3ed852e2009-09-05 21:47:34 +0000735 image->filename);
736 return(MagickFalse);
737 }
738 image_info=AcquireImageInfo();
cristyee2f5d62015-07-28 13:19:43 +0000739 (void) CopyMagickString(image_info->filename,image->filename,
740 MagickPathExtent);
741 (void) ConcatenateMagickString(image_info->filename,pathname,
742 MagickPathExtent);
cristy6fccee12011-10-20 18:43:18 +0000743 clip_mask=BlobToImage(image_info,value,strlen(value),exception);
cristy3ed852e2009-09-05 21:47:34 +0000744 image_info=DestroyImageInfo(image_info);
745 if (clip_mask == (Image *) NULL)
746 return(MagickFalse);
747 if (clip_mask->storage_class == PseudoClass)
748 {
cristyea1a8aa2011-10-20 13:24:06 +0000749 (void) SyncImage(clip_mask,exception);
cristy6fccee12011-10-20 18:43:18 +0000750 if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000751 return(MagickFalse);
752 }
753 if (inside == MagickFalse)
cristy6fccee12011-10-20 18:43:18 +0000754 (void) NegateImage(clip_mask,MagickFalse,exception);
cristy151b66d2015-04-15 10:50:31 +0000755 (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000756 "8BIM:1999,2998:%s\nPS",pathname);
Cristy4da63352016-12-03 08:59:32 -0500757 (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
cristy3ed852e2009-09-05 21:47:34 +0000758 clip_mask=DestroyImage(clip_mask);
759 return(MagickTrue);
760}
761
762/*
763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
764% %
765% %
766% %
767% C l o n e I m a g e %
768% %
769% %
770% %
771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
772%
773% CloneImage() copies an image and returns the copy as a new image object.
anthony96f11ee2011-03-23 08:22:54 +0000774%
cristy3ed852e2009-09-05 21:47:34 +0000775% If the specified columns and rows is 0, an exact copy of the image is
776% returned, otherwise the pixel data is undefined and must be initialized
777% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
778% failure, a NULL image is returned and exception describes the reason for the
779% failure.
780%
781% The format of the CloneImage method is:
782%
cristybb503372010-05-27 20:51:26 +0000783% Image *CloneImage(const Image *image,const size_t columns,
784% const size_t rows,const MagickBooleanType orphan,
cristy3ed852e2009-09-05 21:47:34 +0000785% ExceptionInfo *exception)
786%
787% A description of each parameter follows:
788%
789% o image: the image.
790%
791% o columns: the number of columns in the cloned image.
792%
793% o rows: the number of rows in the cloned image.
794%
795% o detach: With a value other than 0, the cloned image is detached from
796% its parent I/O stream.
797%
798% o exception: return any errors or warnings in this structure.
799%
800*/
cristybb503372010-05-27 20:51:26 +0000801MagickExport Image *CloneImage(const Image *image,const size_t columns,
cristybee00932011-01-15 20:28:27 +0000802 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000803{
804 Image
805 *clone_image;
806
cristya19f1d72012-08-07 18:24:38 +0000807 double
cristy3ed852e2009-09-05 21:47:34 +0000808 scale;
809
810 size_t
811 length;
812
813 /*
814 Clone the image.
815 */
816 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000817 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000818 if (image->debug != MagickFalse)
819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
820 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000821 assert(exception->signature == MagickCoreSignature);
cristybe1cfca2014-10-21 14:00:29 +0000822 if ((image->columns == 0) || (image->rows == 0))
823 {
824 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
825 "NegativeOrZeroImageSize","`%s'",image->filename);
826 return((Image *) NULL);
827 }
cristy73bd4a52010-10-05 11:24:23 +0000828 clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
cristy3ed852e2009-09-05 21:47:34 +0000829 if (clone_image == (Image *) NULL)
830 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
831 (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
cristye1c94d92015-06-28 12:16:33 +0000832 clone_image->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +0000833 clone_image->storage_class=image->storage_class;
cristyed231572011-07-14 02:18:59 +0000834 clone_image->number_channels=image->number_channels;
cristyb3a73b52011-07-26 01:34:43 +0000835 clone_image->number_meta_channels=image->number_meta_channels;
cristy4c08aed2011-07-01 19:47:50 +0000836 clone_image->metacontent_extent=image->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +0000837 clone_image->colorspace=image->colorspace;
cristy883fde12013-04-08 00:50:13 +0000838 clone_image->read_mask=image->read_mask;
839 clone_image->write_mask=image->write_mask;
cristy8a46d822012-08-28 23:32:39 +0000840 clone_image->alpha_trait=image->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +0000841 clone_image->columns=image->columns;
842 clone_image->rows=image->rows;
843 clone_image->dither=image->dither;
cristy101ab702011-10-13 13:06:32 +0000844 if (image->colormap != (PixelInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000845 {
846 /*
847 Allocate and copy the image colormap.
848 */
849 clone_image->colors=image->colors;
850 length=(size_t) image->colors;
cristy101ab702011-10-13 13:06:32 +0000851 clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length,
cristy3ed852e2009-09-05 21:47:34 +0000852 sizeof(*clone_image->colormap));
cristy101ab702011-10-13 13:06:32 +0000853 if (clone_image->colormap == (PixelInfo *) NULL)
Cristyaecd0ad2016-05-16 16:05:02 -0400854 {
855 clone_image=DestroyImage(clone_image);
856 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
857 }
cristy3ed852e2009-09-05 21:47:34 +0000858 (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
859 sizeof(*clone_image->colormap));
860 }
Cristy36421ee2015-08-28 11:58:20 -0400861 clone_image->image_info=CloneImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +0000862 (void) CloneImageProfiles(clone_image,image);
863 (void) CloneImageProperties(clone_image,image);
864 (void) CloneImageArtifacts(clone_image,image);
865 GetTimerInfo(&clone_image->timer);
cristy3ed852e2009-09-05 21:47:34 +0000866 if (image->ascii85 != (void *) NULL)
867 Ascii85Initialize(clone_image);
868 clone_image->magick_columns=image->magick_columns;
869 clone_image->magick_rows=image->magick_rows;
870 clone_image->type=image->type;
cristy636dcb52011-08-26 13:23:49 +0000871 clone_image->channel_mask=image->channel_mask;
cristyed231572011-07-14 02:18:59 +0000872 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +0000873 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
cristy151b66d2015-04-15 10:50:31 +0000874 MagickPathExtent);
875 (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
cristy25baba02015-07-28 00:36:29 +0000876 (void) CopyMagickString(clone_image->filename,image->filename,
877 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000878 clone_image->progress_monitor=image->progress_monitor;
879 clone_image->client_data=image->client_data;
880 clone_image->reference_count=1;
cristybee00932011-01-15 20:28:27 +0000881 clone_image->next=image->next;
882 clone_image->previous=image->previous;
cristy3ed852e2009-09-05 21:47:34 +0000883 clone_image->list=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +0000884 if (detach == MagickFalse)
885 clone_image->blob=ReferenceBlob(image->blob);
886 else
cristybee00932011-01-15 20:28:27 +0000887 {
888 clone_image->next=NewImageList();
889 clone_image->previous=NewImageList();
890 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
891 }
cristy73724512010-04-12 14:43:14 +0000892 clone_image->ping=image->ping;
cristy3ed852e2009-09-05 21:47:34 +0000893 clone_image->debug=IsEventLogging();
cristy3d162a92014-02-16 14:05:06 +0000894 clone_image->semaphore=AcquireSemaphoreInfo();
cristy58a749e2014-05-25 17:36:53 +0000895 if ((columns == 0) || (rows == 0))
cristy3ed852e2009-09-05 21:47:34 +0000896 {
897 if (image->montage != (char *) NULL)
898 (void) CloneString(&clone_image->montage,image->montage);
899 if (image->directory != (char *) NULL)
900 (void) CloneString(&clone_image->directory,image->directory);
cristy3ed852e2009-09-05 21:47:34 +0000901 clone_image->cache=ReferencePixelCache(image->cache);
902 return(clone_image);
903 }
cristy51d26762014-05-26 01:29:41 +0000904 scale=1.0;
905 if (image->columns != 0)
906 scale=(double) columns/(double) image->columns;
cristybb503372010-05-27 20:51:26 +0000907 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
908 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
909 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
cristy51d26762014-05-26 01:29:41 +0000910 scale=1.0;
911 if (image->rows != 0)
cristyee2f5d62015-07-28 13:19:43 +0000912 scale=(double) rows/(double) image->rows;
cristybb503372010-05-27 20:51:26 +0000913 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
914 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
915 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
cristy3ed852e2009-09-05 21:47:34 +0000916 clone_image->cache=ClonePixelCache(image->cache);
Cristy5777d242016-06-16 16:58:13 -0400917 if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
918 clone_image=DestroyImage(clone_image);
cristy3ed852e2009-09-05 21:47:34 +0000919 return(clone_image);
920}
921
922/*
923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924% %
925% %
926% %
927% C l o n e I m a g e I n f o %
928% %
929% %
930% %
931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932%
933% CloneImageInfo() makes a copy of the given image info structure. If
934% NULL is specified, a new image info structure is created initialized to
935% default values.
936%
937% The format of the CloneImageInfo method is:
938%
939% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
940%
941% A description of each parameter follows:
942%
943% o image_info: the image info.
944%
945*/
946MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
947{
948 ImageInfo
949 *clone_info;
950
951 clone_info=AcquireImageInfo();
952 if (image_info == (ImageInfo *) NULL)
953 return(clone_info);
954 clone_info->compression=image_info->compression;
955 clone_info->temporary=image_info->temporary;
956 clone_info->adjoin=image_info->adjoin;
957 clone_info->antialias=image_info->antialias;
958 clone_info->scene=image_info->scene;
959 clone_info->number_scenes=image_info->number_scenes;
960 clone_info->depth=image_info->depth;
anthony72feaa62012-01-17 06:46:23 +0000961 (void) CloneString(&clone_info->size,image_info->size);
962 (void) CloneString(&clone_info->extract,image_info->extract);
963 (void) CloneString(&clone_info->scenes,image_info->scenes);
964 (void) CloneString(&clone_info->page,image_info->page);
cristy3ed852e2009-09-05 21:47:34 +0000965 clone_info->interlace=image_info->interlace;
966 clone_info->endian=image_info->endian;
967 clone_info->units=image_info->units;
968 clone_info->quality=image_info->quality;
anthony72feaa62012-01-17 06:46:23 +0000969 (void) CloneString(&clone_info->sampling_factor,image_info->sampling_factor);
970 (void) CloneString(&clone_info->server_name,image_info->server_name);
971 (void) CloneString(&clone_info->font,image_info->font);
972 (void) CloneString(&clone_info->texture,image_info->texture);
973 (void) CloneString(&clone_info->density,image_info->density);
cristy3ed852e2009-09-05 21:47:34 +0000974 clone_info->pointsize=image_info->pointsize;
975 clone_info->fuzz=image_info->fuzz;
dirkb797b2c2016-02-01 22:20:32 +0100976 clone_info->alpha_color=image_info->alpha_color;
cristy3ed852e2009-09-05 21:47:34 +0000977 clone_info->background_color=image_info->background_color;
978 clone_info->border_color=image_info->border_color;
cristy3ed852e2009-09-05 21:47:34 +0000979 clone_info->transparent_color=image_info->transparent_color;
980 clone_info->dither=image_info->dither;
981 clone_info->monochrome=image_info->monochrome;
cristy3ed852e2009-09-05 21:47:34 +0000982 clone_info->colorspace=image_info->colorspace;
983 clone_info->type=image_info->type;
984 clone_info->orientation=image_info->orientation;
cristy3ed852e2009-09-05 21:47:34 +0000985 clone_info->ping=image_info->ping;
986 clone_info->verbose=image_info->verbose;
cristy3ed852e2009-09-05 21:47:34 +0000987 clone_info->progress_monitor=image_info->progress_monitor;
988 clone_info->client_data=image_info->client_data;
989 clone_info->cache=image_info->cache;
990 if (image_info->cache != (void *) NULL)
991 clone_info->cache=ReferencePixelCache(image_info->cache);
992 if (image_info->profile != (void *) NULL)
993 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
994 image_info->profile);
995 SetImageInfoFile(clone_info,image_info->file);
996 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
997 clone_info->stream=image_info->stream;
cristy957f2612015-06-21 23:51:58 +0000998 (void) CopyMagickString(clone_info->magick,image_info->magick,
999 MagickPathExtent);
1000 (void) CopyMagickString(clone_info->unique,image_info->unique,
1001 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001002 (void) CopyMagickString(clone_info->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00001003 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001004 clone_info->channel=image_info->channel;
anthony1afdc7a2011-10-05 11:54:28 +00001005 (void) CloneImageOptions(clone_info,image_info);
cristy3ed852e2009-09-05 21:47:34 +00001006 clone_info->debug=IsEventLogging();
1007 clone_info->signature=image_info->signature;
1008 return(clone_info);
1009}
1010
1011/*
1012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1013% %
1014% %
1015% %
cristy957f2612015-06-21 23:51:58 +00001016% C o p y I m a g e P i x e l s %
1017% %
1018% %
1019% %
1020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1021%
1022% CopyImagePixels() copies pixels from the source image as defined by the
1023% geometry the destination image at the specified offset.
1024%
1025% The format of the CopyImagePixels method is:
1026%
1027% MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
cristy17fbd722015-06-22 00:46:58 +00001028% const RectangleInfo *geometry,const OffsetInfo *offset,
1029% ExceptionInfo *exception);
cristy957f2612015-06-21 23:51:58 +00001030%
1031% A description of each parameter follows:
1032%
1033% o image: the destination image.
1034%
1035% o source_image: the source image.
1036%
1037% o geometry: define the dimensions of the source pixel rectangle.
1038%
1039% o offset: define the offset in the destination image.
1040%
cristy17fbd722015-06-22 00:46:58 +00001041% o exception: return any errors or warnings in this structure.
1042%
cristy957f2612015-06-21 23:51:58 +00001043*/
1044MagickExport MagickBooleanType CopyImagePixels(Image *image,
1045 const Image *source_image,const RectangleInfo *geometry,
cristy17fbd722015-06-22 00:46:58 +00001046 const OffsetInfo *offset,ExceptionInfo *exception)
cristy957f2612015-06-21 23:51:58 +00001047{
cristy17fbd722015-06-22 00:46:58 +00001048#define CopyImageTag "Copy/Image"
1049
1050 CacheView
1051 *image_view,
1052 *source_view;
1053
1054 MagickBooleanType
1055 status;
1056
1057 MagickOffsetType
1058 progress;
1059
1060 ssize_t
1061 y;
1062
cristy957f2612015-06-21 23:51:58 +00001063 assert(image != (Image *) NULL);
1064 if (image->debug != MagickFalse)
1065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1066 assert(source_image != (Image *) NULL);
1067 assert(geometry != (RectangleInfo *) NULL);
1068 assert(offset != (OffsetInfo *) NULL);
cristy8c4c1c42015-06-22 23:51:22 +00001069 if ((offset->x < 0) || (offset->y < 0) ||
Cristy7d049b72015-09-26 20:50:55 -04001070 ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1071 ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
cristye742cae2015-06-22 19:40:29 +00001072 ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1073 image->filename);
cristy8c4c1c42015-06-22 23:51:22 +00001074 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1075 return(MagickFalse);
cristy17fbd722015-06-22 00:46:58 +00001076 /*
1077 Copy image pixels.
1078 */
1079 status=MagickTrue;
1080 progress=0;
1081 source_view=AcquireVirtualCacheView(source_image,exception);
1082 image_view=AcquireAuthenticCacheView(image,exception);
1083#if defined(MAGICKCORE_OPENMP_SUPPORT)
1084 #pragma omp parallel for schedule(static,4) shared(progress,status) \
cristye742cae2015-06-22 19:40:29 +00001085 magick_threads(image,source_image,geometry->height,1)
cristy17fbd722015-06-22 00:46:58 +00001086#endif
cristye742cae2015-06-22 19:40:29 +00001087 for (y=0; y < (ssize_t) geometry->height; y++)
cristy17fbd722015-06-22 00:46:58 +00001088 {
1089 MagickBooleanType
1090 sync;
1091
1092 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001093 *magick_restrict p;
cristy17fbd722015-06-22 00:46:58 +00001094
1095 register ssize_t
1096 x;
1097
1098 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001099 *magick_restrict q;
cristy17fbd722015-06-22 00:46:58 +00001100
1101 if (status == MagickFalse)
1102 continue;
cristye742cae2015-06-22 19:40:29 +00001103 p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1104 geometry->width,1,exception);
1105 q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1106 geometry->width,1,exception);
cristy17fbd722015-06-22 00:46:58 +00001107 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1108 {
1109 status=MagickFalse;
1110 continue;
1111 }
cristye742cae2015-06-22 19:40:29 +00001112 for (x=0; x < (ssize_t) geometry->width; x++)
cristy17fbd722015-06-22 00:46:58 +00001113 {
1114 register ssize_t
1115 i;
1116
1117 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
Cristy0093cff2016-06-05 19:00:17 -04001118 {
cristy17fbd722015-06-22 00:46:58 +00001119 PixelChannel channel=GetPixelChannelChannel(image,i);
1120 PixelTrait traits=GetPixelChannelTraits(image,channel);
1121 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1122 if ((traits == UndefinedPixelTrait) ||
dirk5a9b26e2016-07-23 13:05:55 +02001123 ((traits & UpdatePixelTrait) == 0) ||
cristy17fbd722015-06-22 00:46:58 +00001124 (source_traits == UndefinedPixelTrait))
1125 continue;
dirkd00a0022015-07-05 09:54:39 +00001126 SetPixelChannel(image,channel,p[i],q);
cristy17fbd722015-06-22 00:46:58 +00001127 }
dirkd00a0022015-07-05 09:54:39 +00001128 p+=GetPixelChannels(source_image);
1129 q+=GetPixelChannels(image);
cristy17fbd722015-06-22 00:46:58 +00001130 }
dirkd00a0022015-07-05 09:54:39 +00001131 sync=SyncCacheViewAuthenticPixels(image_view,exception);
cristy17fbd722015-06-22 00:46:58 +00001132 if (sync == MagickFalse)
1133 status=MagickFalse;
1134 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1135 {
1136 MagickBooleanType
1137 proceed;
1138
1139#if defined(MAGICKCORE_OPENMP_SUPPORT)
1140 #pragma omp critical (MagickCore_CopyImage)
1141#endif
1142 proceed=SetImageProgress(image,CopyImageTag,progress++,image->rows);
1143 if (proceed == MagickFalse)
1144 status=MagickFalse;
1145 }
1146 }
1147 source_view=DestroyCacheView(source_view);
1148 image_view=DestroyCacheView(image_view);
1149 return(status);
cristy957f2612015-06-21 23:51:58 +00001150}
1151
1152/*
1153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154% %
1155% %
1156% %
cristy3ed852e2009-09-05 21:47:34 +00001157% D e s t r o y I m a g e %
1158% %
1159% %
1160% %
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162%
1163% DestroyImage() dereferences an image, deallocating memory associated with
1164% the image if the reference count becomes zero.
1165%
1166% The format of the DestroyImage method is:
1167%
1168% Image *DestroyImage(Image *image)
1169%
1170% A description of each parameter follows:
1171%
1172% o image: the image.
1173%
1174*/
1175MagickExport Image *DestroyImage(Image *image)
1176{
1177 MagickBooleanType
1178 destroy;
1179
1180 /*
1181 Dereference image.
1182 */
1183 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001184 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001185 if (image->debug != MagickFalse)
1186 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1187 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001188 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001189 image->reference_count--;
1190 if (image->reference_count == 0)
1191 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00001192 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001193 if (destroy == MagickFalse)
1194 return((Image *) NULL);
1195 /*
1196 Destroy image.
1197 */
1198 DestroyImagePixels(image);
cristyed231572011-07-14 02:18:59 +00001199 image->channel_map=DestroyPixelChannelMap(image->channel_map);
cristy3ed852e2009-09-05 21:47:34 +00001200 if (image->montage != (char *) NULL)
1201 image->montage=DestroyString(image->montage);
1202 if (image->directory != (char *) NULL)
1203 image->directory=DestroyString(image->directory);
cristy101ab702011-10-13 13:06:32 +00001204 if (image->colormap != (PixelInfo *) NULL)
1205 image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
cristy3ed852e2009-09-05 21:47:34 +00001206 if (image->geometry != (char *) NULL)
1207 image->geometry=DestroyString(image->geometry);
cristy3ed852e2009-09-05 21:47:34 +00001208 DestroyImageProfiles(image);
1209 DestroyImageProperties(image);
1210 DestroyImageArtifacts(image);
Cristy36421ee2015-08-28 11:58:20 -04001211 if (image->ascii85 != (Ascii85Info *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001212 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
Cristy36421ee2015-08-28 11:58:20 -04001213 if (image->image_info != (ImageInfo *) NULL)
1214 image->image_info=DestroyImageInfo(image->image_info);
cristy3ed852e2009-09-05 21:47:34 +00001215 DestroyBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001216 if (image->semaphore != (SemaphoreInfo *) NULL)
cristy3d162a92014-02-16 14:05:06 +00001217 RelinquishSemaphoreInfo(&image->semaphore);
cristye1c94d92015-06-28 12:16:33 +00001218 image->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001219 image=(Image *) RelinquishMagickMemory(image);
1220 return(image);
1221}
1222
1223/*
1224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1225% %
1226% %
1227% %
1228% D e s t r o y I m a g e I n f o %
1229% %
1230% %
1231% %
1232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233%
1234% DestroyImageInfo() deallocates memory associated with an ImageInfo
1235% structure.
1236%
1237% The format of the DestroyImageInfo method is:
1238%
1239% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1240%
1241% A description of each parameter follows:
1242%
1243% o image_info: the image info.
1244%
1245*/
1246MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1247{
1248 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001249 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001250 if (image_info->debug != MagickFalse)
1251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1252 image_info->filename);
1253 if (image_info->size != (char *) NULL)
1254 image_info->size=DestroyString(image_info->size);
1255 if (image_info->extract != (char *) NULL)
1256 image_info->extract=DestroyString(image_info->extract);
1257 if (image_info->scenes != (char *) NULL)
1258 image_info->scenes=DestroyString(image_info->scenes);
1259 if (image_info->page != (char *) NULL)
1260 image_info->page=DestroyString(image_info->page);
1261 if (image_info->sampling_factor != (char *) NULL)
1262 image_info->sampling_factor=DestroyString(
1263 image_info->sampling_factor);
1264 if (image_info->server_name != (char *) NULL)
1265 image_info->server_name=DestroyString(
1266 image_info->server_name);
1267 if (image_info->font != (char *) NULL)
1268 image_info->font=DestroyString(image_info->font);
1269 if (image_info->texture != (char *) NULL)
1270 image_info->texture=DestroyString(image_info->texture);
1271 if (image_info->density != (char *) NULL)
1272 image_info->density=DestroyString(image_info->density);
cristy3ed852e2009-09-05 21:47:34 +00001273 if (image_info->cache != (void *) NULL)
1274 image_info->cache=DestroyPixelCache(image_info->cache);
1275 if (image_info->profile != (StringInfo *) NULL)
1276 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1277 image_info->profile);
anthony1afdc7a2011-10-05 11:54:28 +00001278 DestroyImageOptions(image_info);
cristye1c94d92015-06-28 12:16:33 +00001279 image_info->signature=(~MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001280 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1281 return(image_info);
1282}
1283
1284/*
1285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1286% %
1287% %
1288% %
1289+ D i s a s s o c i a t e I m a g e S t r e a m %
1290% %
1291% %
1292% %
1293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1294%
cristy4916cb42014-09-20 00:44:37 +00001295% DisassociateImageStream() disassociates the image stream. It checks if the
1296% blob of the specified image is referenced by other images. If the reference
1297% count is higher then 1 a new blob is assigned to the specified image.
cristy3ed852e2009-09-05 21:47:34 +00001298%
1299% The format of the DisassociateImageStream method is:
1300%
dirkcfe4c1c2014-09-20 07:38:59 +00001301% void DisassociateImageStream(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001302%
1303% A description of each parameter follows:
1304%
1305% o image: the image.
1306%
1307*/
1308MagickExport void DisassociateImageStream(Image *image)
1309{
cristy4916cb42014-09-20 00:44:37 +00001310 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001311 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001312 if (image->debug != MagickFalse)
1313 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy10f10ec2014-09-20 01:00:50 +00001314 DisassociateBlob(image);
cristy3ed852e2009-09-05 21:47:34 +00001315}
1316
1317/*
1318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1319% %
1320% %
1321% %
cristy3ed852e2009-09-05 21:47:34 +00001322% G e t I m a g e I n f o %
1323% %
1324% %
1325% %
1326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327%
1328% GetImageInfo() initializes image_info to default values.
1329%
1330% The format of the GetImageInfo method is:
1331%
1332% void GetImageInfo(ImageInfo *image_info)
1333%
1334% A description of each parameter follows:
1335%
1336% o image_info: the image info.
1337%
1338*/
1339MagickExport void GetImageInfo(ImageInfo *image_info)
1340{
cristyfa0ea942012-12-21 02:42:29 +00001341 char
1342 *synchronize;
1343
cristy3ed852e2009-09-05 21:47:34 +00001344 ExceptionInfo
1345 *exception;
1346
1347 /*
1348 File and image dimension members.
1349 */
1350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1351 assert(image_info != (ImageInfo *) NULL);
1352 (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1353 image_info->adjoin=MagickTrue;
1354 image_info->interlace=NoInterlace;
1355 image_info->channel=DefaultChannels;
1356 image_info->quality=UndefinedCompressionQuality;
1357 image_info->antialias=MagickTrue;
1358 image_info->dither=MagickTrue;
cristyfa0ea942012-12-21 02:42:29 +00001359 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1360 if (synchronize != (const char *) NULL)
1361 {
1362 image_info->synchronize=IsStringTrue(synchronize);
1363 synchronize=DestroyString(synchronize);
1364 }
cristy3ed852e2009-09-05 21:47:34 +00001365 exception=AcquireExceptionInfo();
dirkb797b2c2016-02-01 22:20:32 +01001366 (void) QueryColorCompliance(AlphaColor,AllCompliance,&image_info->alpha_color,
1367 exception);
cristy9950d572011-10-01 18:22:35 +00001368 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1369 &image_info->background_color,exception);
1370 (void) QueryColorCompliance(BorderColor,AllCompliance,
1371 &image_info->border_color,exception);
cristy9950d572011-10-01 18:22:35 +00001372 (void) QueryColorCompliance(TransparentColor,AllCompliance,
1373 &image_info->transparent_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00001374 exception=DestroyExceptionInfo(exception);
1375 image_info->debug=IsEventLogging();
cristye1c94d92015-06-28 12:16:33 +00001376 image_info->signature=MagickCoreSignature;
cristy3ed852e2009-09-05 21:47:34 +00001377}
1378
1379/*
1380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381% %
1382% %
1383% %
cristy15781e52009-12-05 23:05:27 +00001384% G e t I m a g e I n f o F i l e %
1385% %
1386% %
1387% %
1388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1389%
1390% GetImageInfoFile() returns the image info file member.
1391%
1392% The format of the GetImageInfoFile method is:
1393%
1394% FILE *GetImageInfoFile(const ImageInfo *image_info)
1395%
1396% A description of each parameter follows:
1397%
1398% o image_info: the image info.
1399%
1400*/
1401MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1402{
1403 return(image_info->file);
1404}
1405
1406/*
1407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408% %
1409% %
1410% %
cristy3ed852e2009-09-05 21:47:34 +00001411% G e t I m a g e M a s k %
1412% %
1413% %
1414% %
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416%
1417% GetImageMask() returns the mask associated with the image.
1418%
1419% The format of the GetImageMask method is:
1420%
dirkaf131f12016-01-10 01:29:22 +01001421% Image *GetImageMask(const Image *image,const PixelMask type,
1422% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001423%
1424% A description of each parameter follows:
1425%
1426% o image: the image.
1427%
dirkaf131f12016-01-10 01:29:22 +01001428% o type: the mask type, ReadPixelMask or WritePixelMask.
1429%
cristy3ed852e2009-09-05 21:47:34 +00001430*/
dirkaf131f12016-01-10 01:29:22 +01001431MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1432 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001433{
cristy10a6c612012-01-29 21:41:05 +00001434 CacheView
1435 *mask_view,
1436 *image_view;
1437
1438 Image
1439 *mask_image;
1440
1441 MagickBooleanType
1442 status;
1443
1444 ssize_t
1445 y;
1446
1447 /*
1448 Get image mask.
1449 */
1450 assert(image != (Image *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001451 if (image->debug != MagickFalse)
1452 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001453 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00001454 mask_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1455 if (mask_image == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001456 return((Image *) NULL);
cristy10a6c612012-01-29 21:41:05 +00001457 status=MagickTrue;
dirk4a26ef62015-11-19 21:47:29 +01001458 mask_image->alpha_trait=UndefinedPixelTrait;
dirkcd1d8792015-11-19 22:46:24 +01001459 (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
Cristy0596ce22015-11-20 21:11:22 -05001460 mask_image->read_mask=MagickFalse;
cristy46ff2672012-12-14 15:32:26 +00001461 image_view=AcquireVirtualCacheView(image,exception);
1462 mask_view=AcquireAuthenticCacheView(mask_image,exception);
cristy10a6c612012-01-29 21:41:05 +00001463 for (y=0; y < (ssize_t) image->rows; y++)
1464 {
1465 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01001466 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00001467
1468 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001469 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00001470
1471 register ssize_t
1472 x;
1473
1474 if (status == MagickFalse)
1475 continue;
1476 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1477 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1478 exception);
1479 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1480 {
1481 status=MagickFalse;
1482 continue;
1483 }
1484 for (x=0; x < (ssize_t) image->columns; x++)
1485 {
dirkaf131f12016-01-10 01:29:22 +01001486 switch (type)
1487 {
1488 case WritePixelMask:
1489 {
1490 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1491 break;
1492 }
1493 default:
1494 {
Dirk Lemstra633b2e92016-12-03 16:18:40 +01001495 SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
dirkaf131f12016-01-10 01:29:22 +01001496 break;
1497 }
1498 }
cristy10a6c612012-01-29 21:41:05 +00001499 p+=GetPixelChannels(image);
1500 q+=GetPixelChannels(mask_image);
1501 }
1502 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1503 status=MagickFalse;
1504 }
1505 mask_view=DestroyCacheView(mask_view);
1506 image_view=DestroyCacheView(image_view);
cristy1c2f48d2012-12-14 01:20:55 +00001507 if (status == MagickFalse)
1508 mask_image=DestroyImage(mask_image);
cristy10a6c612012-01-29 21:41:05 +00001509 return(mask_image);
cristy3ed852e2009-09-05 21:47:34 +00001510}
1511
1512/*
1513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1514% %
1515% %
1516% %
1517+ G e t I m a g e R e f e r e n c e C o u n t %
1518% %
1519% %
1520% %
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522%
1523% GetImageReferenceCount() returns the image reference count.
1524%
1525% The format of the GetReferenceCount method is:
1526%
cristybb503372010-05-27 20:51:26 +00001527% ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001528%
1529% A description of each parameter follows:
1530%
1531% o image: the image.
1532%
1533*/
cristybb503372010-05-27 20:51:26 +00001534MagickExport ssize_t GetImageReferenceCount(Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001535{
cristybb503372010-05-27 20:51:26 +00001536 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001537 reference_count;
1538
1539 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001540 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001541 if (image->debug != MagickFalse)
1542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyf84a1932010-01-03 18:00:18 +00001543 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001544 reference_count=image->reference_count;
cristyf84a1932010-01-03 18:00:18 +00001545 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001546 return(reference_count);
1547}
1548
1549/*
1550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1551% %
1552% %
1553% %
cristy3ed852e2009-09-05 21:47:34 +00001554% 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 %
1555% %
1556% %
1557% %
1558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559%
1560% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1561% image. A virtual pixel is any pixel access that is outside the boundaries
1562% of the image cache.
1563%
1564% The format of the GetImageVirtualPixelMethod() method is:
1565%
1566% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1567%
1568% A description of each parameter follows:
1569%
1570% o image: the image.
1571%
1572*/
1573MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1574{
1575 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001576 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001577 if (image->debug != MagickFalse)
1578 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1579 return(GetPixelCacheVirtualMethod(image));
1580}
1581
1582/*
1583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584% %
1585% %
1586% %
1587% I n t e r p r e t I m a g e F i l e n a m e %
1588% %
1589% %
1590% %
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592%
1593% InterpretImageFilename() interprets embedded characters in an image filename.
1594% The filename length is returned.
1595%
1596% The format of the InterpretImageFilename method is:
1597%
cristyee2b1232012-03-04 02:58:28 +00001598% size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1599% const char *format,int value,char *filename,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001600%
1601% A description of each parameter follows.
1602%
1603% o image_info: the image info..
1604%
1605% o image: the image.
1606%
1607% o format: A filename describing the format to use to write the numeric
1608% argument. Only the first numeric format identifier is replaced.
1609%
1610% o value: Numeric value to substitute into format filename.
1611%
1612% o filename: return the formatted filename in this character buffer.
1613%
cristy6fccee12011-10-20 18:43:18 +00001614% o exception: return any errors or warnings in this structure.
1615%
cristy3ed852e2009-09-05 21:47:34 +00001616*/
1617MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00001618 Image *image,const char *format,int value,char *filename,
1619 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001620{
1621 char
1622 *q;
1623
1624 int
1625 c;
1626
1627 MagickBooleanType
1628 canonical;
1629
1630 register const char
1631 *p;
1632
cristyad785752011-07-27 23:13:03 +00001633 size_t
1634 length;
1635
cristy3ed852e2009-09-05 21:47:34 +00001636 canonical=MagickFalse;
cristyc7b79fc2011-07-28 00:24:17 +00001637 length=0;
cristy151b66d2015-04-15 10:50:31 +00001638 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001639 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1640 {
1641 q=(char *) p+1;
1642 if (*q == '%')
1643 {
1644 p=q+1;
1645 continue;
1646 }
1647 if (*q == '0')
1648 {
cristybb503372010-05-27 20:51:26 +00001649 ssize_t
dirk86bacde2016-03-17 22:04:25 +01001650 foo;
cristy3ed852e2009-09-05 21:47:34 +00001651
dirk86bacde2016-03-17 22:04:25 +01001652 foo=(ssize_t) strtol(q,&q,10);
1653 (void) foo;
cristy3ed852e2009-09-05 21:47:34 +00001654 }
1655 switch (*q)
1656 {
1657 case 'd':
1658 case 'o':
1659 case 'x':
1660 {
1661 q++;
1662 c=(*q);
1663 *q='\0';
cristyee2f5d62015-07-28 13:19:43 +00001664 (void) FormatLocaleString(filename+(p-format),(size_t)
1665 (MagickPathExtent-(p-format)),p,value);
cristy3ed852e2009-09-05 21:47:34 +00001666 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001667 (void) ConcatenateMagickString(filename,q,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001668 canonical=MagickTrue;
1669 if (*(q-1) != '%')
1670 break;
1671 p++;
1672 break;
1673 }
1674 case '[':
1675 {
1676 char
cristy151b66d2015-04-15 10:50:31 +00001677 pattern[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001678
1679 const char
dirk86bacde2016-03-17 22:04:25 +01001680 *option;
cristy3ed852e2009-09-05 21:47:34 +00001681
cristy3ed852e2009-09-05 21:47:34 +00001682 register char
1683 *r;
1684
cristybb503372010-05-27 20:51:26 +00001685 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001686 i;
1687
cristycb6d09b2010-06-19 01:59:36 +00001688 ssize_t
1689 depth;
1690
cristy3ed852e2009-09-05 21:47:34 +00001691 /*
1692 Image option.
1693 */
anthony2cfa1a12012-05-12 05:18:07 +00001694 /* FUTURE: Compare update with code from InterpretImageProperties()
cristy97fc9f32012-06-13 21:04:44 +00001695 Note that a 'filename:' property should not need depth recursion.
anthony2cfa1a12012-05-12 05:18:07 +00001696 */
cristy3ed852e2009-09-05 21:47:34 +00001697 if (strchr(p,']') == (char *) NULL)
1698 break;
1699 depth=1;
1700 r=q+1;
cristy151b66d2015-04-15 10:50:31 +00001701 for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
cristy3ed852e2009-09-05 21:47:34 +00001702 {
1703 if (*r == '[')
1704 depth++;
1705 if (*r == ']')
1706 depth--;
1707 if (depth <= 0)
1708 break;
1709 pattern[i]=(*r++);
1710 }
1711 pattern[i]='\0';
1712 if (LocaleNCompare(pattern,"filename:",9) != 0)
1713 break;
dirk86bacde2016-03-17 22:04:25 +01001714 option=(const char *) NULL;
anthony06762232012-04-29 11:45:40 +00001715 if (image != (Image *) NULL)
dirk86bacde2016-03-17 22:04:25 +01001716 option=GetImageProperty(image,pattern,exception);
1717 if ((option == (const char *) NULL) && (image != (Image *) NULL))
1718 option=GetImageArtifact(image,pattern);
1719 if ((option == (const char *) NULL) &&
anthony06762232012-04-29 11:45:40 +00001720 (image_info != (ImageInfo *) NULL))
dirk86bacde2016-03-17 22:04:25 +01001721 option=GetImageOption(image_info,pattern);
1722 if (option == (const char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001723 break;
1724 q--;
1725 c=(*q);
1726 *q='\0';
dirk86bacde2016-03-17 22:04:25 +01001727 (void) CopyMagickString(filename+(p-format-length),option,(size_t)
cristy151b66d2015-04-15 10:50:31 +00001728 (MagickPathExtent-(p-format-length)));
cristyad785752011-07-27 23:13:03 +00001729 length+=strlen(pattern)-1;
cristy3ed852e2009-09-05 21:47:34 +00001730 *q=c;
cristy151b66d2015-04-15 10:50:31 +00001731 (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001732 canonical=MagickTrue;
1733 if (*(q-1) != '%')
1734 break;
1735 p++;
1736 break;
1737 }
1738 default:
1739 break;
1740 }
1741 }
1742 for (q=filename; *q != '\0'; q++)
1743 if ((*q == '%') && (*(q+1) == '%'))
cristy27bf23e2011-01-10 13:35:22 +00001744 {
cristy151b66d2015-04-15 10:50:31 +00001745 (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
cristy27bf23e2011-01-10 13:35:22 +00001746 canonical=MagickTrue;
1747 }
cristy3ed852e2009-09-05 21:47:34 +00001748 if (canonical == MagickFalse)
cristy151b66d2015-04-15 10:50:31 +00001749 (void) CopyMagickString(filename,format,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001750 return(strlen(filename));
1751}
1752
1753/*
1754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755% %
1756% %
1757% %
1758% I s H i g h D y n a m i c R a n g e I m a g e %
1759% %
1760% %
1761% %
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763%
1764% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1765% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1766% 0..65535.
1767%
1768% The format of the IsHighDynamicRangeImage method is:
1769%
1770% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1771% ExceptionInfo *exception)
1772%
1773% A description of each parameter follows:
1774%
1775% o image: the image.
1776%
1777% o exception: return any errors or warnings in this structure.
1778%
1779*/
1780MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1781 ExceptionInfo *exception)
1782{
1783#if !defined(MAGICKCORE_HDRI_SUPPORT)
1784 (void) image;
1785 (void) exception;
1786 return(MagickFalse);
1787#else
1788 CacheView
1789 *image_view;
1790
cristy3ed852e2009-09-05 21:47:34 +00001791 MagickBooleanType
1792 status;
1793
cristycb6d09b2010-06-19 01:59:36 +00001794 ssize_t
1795 y;
1796
cristy3ed852e2009-09-05 21:47:34 +00001797 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001798 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001799 if (image->debug != MagickFalse)
1800 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1801 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00001802 image_view=AcquireVirtualCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00001803#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001804 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00001805 magick_threads(image,image,image->rows,1)
cristy3ed852e2009-09-05 21:47:34 +00001806#endif
cristybb503372010-05-27 20:51:26 +00001807 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001808 {
cristy4c08aed2011-07-01 19:47:50 +00001809 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001810 *p;
1811
cristybb503372010-05-27 20:51:26 +00001812 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001813 x;
1814
1815 if (status == MagickFalse)
1816 continue;
1817 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001818 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001819 {
1820 status=MagickFalse;
1821 continue;
1822 }
cristybb503372010-05-27 20:51:26 +00001823 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001824 {
cristya905c052011-09-17 22:37:55 +00001825 register ssize_t
1826 i;
1827
Cristydf5e8b12016-12-02 17:26:39 -05001828 if (GetPixelWriteMask(image,p) == 0)
cristy10a6c612012-01-29 21:41:05 +00001829 {
1830 p+=GetPixelChannels(image);
1831 continue;
1832 }
cristya905c052011-09-17 22:37:55 +00001833 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1834 {
cristya19f1d72012-08-07 18:24:38 +00001835 double
cristya905c052011-09-17 22:37:55 +00001836 pixel;
1837
cristyb0a657e2012-08-29 00:45:37 +00001838 PixelTrait
1839 traits;
1840
1841 traits=GetPixelChannelTraits(image,(PixelChannel) i);
cristya905c052011-09-17 22:37:55 +00001842 if (traits == UndefinedPixelTrait)
1843 continue;
cristya19f1d72012-08-07 18:24:38 +00001844 pixel=(double) p[i];
cristya905c052011-09-17 22:37:55 +00001845 if ((pixel < 0.0) || (pixel > QuantumRange) ||
cristy569b0e32013-08-15 16:07:35 +00001846 (pixel != (double) ((QuantumAny) pixel)))
cristya905c052011-09-17 22:37:55 +00001847 break;
1848 }
cristyed231572011-07-14 02:18:59 +00001849 p+=GetPixelChannels(image);
cristya905c052011-09-17 22:37:55 +00001850 if (i < (ssize_t) GetPixelChannels(image))
1851 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001852 }
cristybb503372010-05-27 20:51:26 +00001853 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001854 status=MagickFalse;
1855 }
1856 image_view=DestroyCacheView(image_view);
1857 return(status != MagickFalse ? MagickFalse : MagickTrue);
1858#endif
1859}
1860
1861/*
1862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863% %
1864% %
1865% %
1866% I s I m a g e O b j e c t %
1867% %
1868% %
1869% %
1870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1871%
1872% IsImageObject() returns MagickTrue if the image sequence contains a valid
1873% set of image objects.
1874%
1875% The format of the IsImageObject method is:
1876%
1877% MagickBooleanType IsImageObject(const Image *image)
1878%
1879% A description of each parameter follows:
1880%
1881% o image: the image.
1882%
1883*/
1884MagickExport MagickBooleanType IsImageObject(const Image *image)
1885{
1886 register const Image
1887 *p;
1888
1889 assert(image != (Image *) NULL);
1890 if (image->debug != MagickFalse)
1891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1892 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
cristye1c94d92015-06-28 12:16:33 +00001893 if (p->signature != MagickCoreSignature)
cristy3ed852e2009-09-05 21:47:34 +00001894 return(MagickFalse);
1895 return(MagickTrue);
1896}
1897
1898/*
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900% %
1901% %
1902% %
1903% I s T a i n t I m a g e %
1904% %
1905% %
1906% %
1907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908%
1909% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1910% since it was first constituted.
1911%
1912% The format of the IsTaintImage method is:
1913%
1914% MagickBooleanType IsTaintImage(const Image *image)
1915%
1916% A description of each parameter follows:
1917%
1918% o image: the image.
1919%
1920*/
1921MagickExport MagickBooleanType IsTaintImage(const Image *image)
1922{
1923 char
cristy151b66d2015-04-15 10:50:31 +00001924 magick[MagickPathExtent],
1925 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001926
1927 register const Image
1928 *p;
1929
1930 assert(image != (Image *) NULL);
1931 if (image->debug != MagickFalse)
1932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00001933 assert(image->signature == MagickCoreSignature);
cristy151b66d2015-04-15 10:50:31 +00001934 (void) CopyMagickString(magick,image->magick,MagickPathExtent);
1935 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001936 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1937 {
1938 if (p->taint != MagickFalse)
1939 return(MagickTrue);
1940 if (LocaleCompare(p->magick,magick) != 0)
1941 return(MagickTrue);
1942 if (LocaleCompare(p->filename,filename) != 0)
1943 return(MagickTrue);
1944 }
1945 return(MagickFalse);
1946}
1947
1948/*
1949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950% %
1951% %
1952% %
1953% M o d i f y I m a g e %
1954% %
1955% %
1956% %
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958%
1959% ModifyImage() ensures that there is only a single reference to the image
1960% to be modified, updating the provided image pointer to point to a clone of
1961% the original image if necessary.
1962%
1963% The format of the ModifyImage method is:
1964%
1965% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
1966%
1967% A description of each parameter follows:
1968%
1969% o image: the image.
1970%
1971% o exception: return any errors or warnings in this structure.
1972%
1973*/
1974MagickExport MagickBooleanType ModifyImage(Image **image,
1975 ExceptionInfo *exception)
1976{
1977 Image
1978 *clone_image;
1979
1980 assert(image != (Image **) NULL);
1981 assert(*image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001982 assert((*image)->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001983 if ((*image)->debug != MagickFalse)
1984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1985 if (GetImageReferenceCount(*image) <= 1)
1986 return(MagickTrue);
1987 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
cristyf84a1932010-01-03 18:00:18 +00001988 LockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001989 (*image)->reference_count--;
cristyf84a1932010-01-03 18:00:18 +00001990 UnlockSemaphoreInfo((*image)->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001991 *image=clone_image;
1992 return(MagickTrue);
1993}
1994
1995/*
1996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1997% %
1998% %
1999% %
2000% N e w M a g i c k I m a g e %
2001% %
2002% %
2003% %
2004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005%
2006% NewMagickImage() creates a blank image canvas of the specified size and
2007% background color.
2008%
2009% The format of the NewMagickImage method is:
2010%
cristy44410ab2014-05-25 20:39:43 +00002011% Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2012% const size_t height,const PixelInfo *background,
cristy0740a982011-10-13 15:01:01 +00002013% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002014%
2015% A description of each parameter follows:
2016%
2017% o image: the image.
2018%
2019% o width: the image width.
2020%
2021% o height: the image height.
2022%
2023% o background: the image color.
2024%
cristy0740a982011-10-13 15:01:01 +00002025% o exception: return any errors or warnings in this structure.
2026%
cristy3ed852e2009-09-05 21:47:34 +00002027*/
2028MagickExport Image *NewMagickImage(const ImageInfo *image_info,
cristy0740a982011-10-13 15:01:01 +00002029 const size_t width,const size_t height,const PixelInfo *background,
2030 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002031{
2032 CacheView
2033 *image_view;
2034
cristy3ed852e2009-09-05 21:47:34 +00002035 Image
2036 *image;
2037
cristy3ed852e2009-09-05 21:47:34 +00002038 MagickBooleanType
2039 status;
2040
cristya905c052011-09-17 22:37:55 +00002041 ssize_t
2042 y;
2043
cristy3ed852e2009-09-05 21:47:34 +00002044 assert(image_info != (const ImageInfo *) NULL);
2045 if (image_info->debug != MagickFalse)
2046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002047 assert(image_info->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002048 assert(background != (const PixelInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00002049 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002050 image->columns=width;
2051 image->rows=height;
2052 image->colorspace=background->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002053 image->alpha_trait=background->alpha_trait;
cristy3ed852e2009-09-05 21:47:34 +00002054 image->fuzz=background->fuzz;
2055 image->depth=background->depth;
2056 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002057 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00002058#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002059 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002060 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00002061#endif
cristybb503372010-05-27 20:51:26 +00002062 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002063 {
cristy4c08aed2011-07-01 19:47:50 +00002064 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002065 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002066
cristycb6d09b2010-06-19 01:59:36 +00002067 register ssize_t
2068 x;
2069
cristy48974b92009-12-19 02:36:06 +00002070 if (status == MagickFalse)
2071 continue;
cristy3ed852e2009-09-05 21:47:34 +00002072 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002073 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002074 {
2075 status=MagickFalse;
2076 continue;
2077 }
cristybb503372010-05-27 20:51:26 +00002078 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002079 {
cristy11a06d32015-01-04 12:03:27 +00002080 SetPixelViaPixelInfo(image,background,q);
cristyed231572011-07-14 02:18:59 +00002081 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002082 }
2083 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2084 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002085 }
2086 image_view=DestroyCacheView(image_view);
2087 if (status == MagickFalse)
2088 image=DestroyImage(image);
2089 return(image);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% R e f e r e n c e I m a g e %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% ReferenceImage() increments the reference count associated with an image
2104% returning a pointer to the image.
2105%
2106% The format of the ReferenceImage method is:
2107%
2108% Image *ReferenceImage(Image *image)
2109%
2110% A description of each parameter follows:
2111%
2112% o image: the image.
2113%
2114*/
2115MagickExport Image *ReferenceImage(Image *image)
2116{
2117 assert(image != (Image *) NULL);
2118 if (image->debug != MagickFalse)
2119 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002120 assert(image->signature == MagickCoreSignature);
cristyf84a1932010-01-03 18:00:18 +00002121 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002122 image->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00002123 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002124 return(image);
2125}
2126
2127/*
2128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129% %
2130% %
2131% %
2132% R e s e t I m a g e P a g e %
2133% %
2134% %
2135% %
2136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2137%
2138% ResetImagePage() resets the image page canvas and position.
2139%
2140% The format of the ResetImagePage method is:
2141%
2142% MagickBooleanType ResetImagePage(Image *image,const char *page)
2143%
2144% A description of each parameter follows:
2145%
2146% o image: the image.
2147%
2148% o page: the relative page specification.
2149%
2150*/
2151MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2152{
2153 MagickStatusType
2154 flags;
2155
2156 RectangleInfo
2157 geometry;
2158
2159 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002160 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002161 if (image->debug != MagickFalse)
2162 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2163 flags=ParseAbsoluteGeometry(page,&geometry);
2164 if ((flags & WidthValue) != 0)
2165 {
2166 if ((flags & HeightValue) == 0)
2167 geometry.height=geometry.width;
2168 image->page.width=geometry.width;
2169 image->page.height=geometry.height;
2170 }
2171 if ((flags & AspectValue) != 0)
2172 {
2173 if ((flags & XValue) != 0)
2174 image->page.x+=geometry.x;
2175 if ((flags & YValue) != 0)
2176 image->page.y+=geometry.y;
2177 }
2178 else
2179 {
2180 if ((flags & XValue) != 0)
2181 {
2182 image->page.x=geometry.x;
2183 if ((image->page.width == 0) && (geometry.x > 0))
2184 image->page.width=image->columns+geometry.x;
2185 }
2186 if ((flags & YValue) != 0)
2187 {
2188 image->page.y=geometry.y;
2189 if ((image->page.height == 0) && (geometry.y > 0))
2190 image->page.height=image->rows+geometry.y;
2191 }
2192 }
2193 return(MagickTrue);
2194}
2195
2196/*
2197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198% %
2199% %
2200% %
cristy3ed852e2009-09-05 21:47:34 +00002201% S e t I m a g e B a c k g r o u n d C o l o r %
2202% %
2203% %
2204% %
2205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206%
2207% SetImageBackgroundColor() initializes the image pixels to the image
2208% background color. The background color is defined by the background_color
2209% member of the image structure.
2210%
2211% The format of the SetImage method is:
2212%
cristyea1a8aa2011-10-20 13:24:06 +00002213% MagickBooleanType SetImageBackgroundColor(Image *image,
2214% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002215%
2216% A description of each parameter follows:
2217%
2218% o image: the image.
2219%
cristyea1a8aa2011-10-20 13:24:06 +00002220% o exception: return any errors or warnings in this structure.
2221%
cristy3ed852e2009-09-05 21:47:34 +00002222*/
cristyea1a8aa2011-10-20 13:24:06 +00002223MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2224 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002225{
2226 CacheView
2227 *image_view;
2228
cristy3ed852e2009-09-05 21:47:34 +00002229 MagickBooleanType
2230 status;
2231
dirkdc896c12014-10-15 16:28:15 +00002232 PixelInfo
2233 background;
2234
cristycb6d09b2010-06-19 01:59:36 +00002235 ssize_t
2236 y;
2237
cristy3ed852e2009-09-05 21:47:34 +00002238 assert(image != (Image *) NULL);
2239 if (image->debug != MagickFalse)
2240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002241 assert(image->signature == MagickCoreSignature);
cristy574cc262011-08-05 01:23:58 +00002242 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002243 return(MagickFalse);
Cristya739e8f2016-12-09 10:40:04 -05002244 if ((image->background_color.alpha != OpaqueAlpha) &&
2245 (image->alpha_trait == UndefinedPixelTrait))
2246 (void) SetImageAlphaChannel(image,OnAlphaChannel,exception);
dirkbfdd5bc2014-11-04 19:47:44 +00002247 ConformPixelInfo(image,&image->background_color,&background,exception);
cristy3ed852e2009-09-05 21:47:34 +00002248 /*
2249 Set image background color.
2250 */
2251 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002252 image_view=AcquireAuthenticCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +00002253 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002254 {
cristy4c08aed2011-07-01 19:47:50 +00002255 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002256 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002257
cristycb6d09b2010-06-19 01:59:36 +00002258 register ssize_t
2259 x;
2260
cristy3ed852e2009-09-05 21:47:34 +00002261 if (status == MagickFalse)
2262 continue;
2263 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002264 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002265 {
2266 status=MagickFalse;
2267 continue;
2268 }
cristybb503372010-05-27 20:51:26 +00002269 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00002270 {
cristy11a06d32015-01-04 12:03:27 +00002271 SetPixelViaPixelInfo(image,&background,q);
cristyed231572011-07-14 02:18:59 +00002272 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002273 }
cristy3ed852e2009-09-05 21:47:34 +00002274 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2275 status=MagickFalse;
2276 }
2277 image_view=DestroyCacheView(image_view);
2278 return(status);
2279}
2280
2281/*
2282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2283% %
2284% %
2285% %
cristycf1296e2012-08-26 23:40:49 +00002286% S e t I m a g e C h a n n e l M a s k %
2287% %
2288% %
2289% %
2290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291%
2292% SetImageChannelMask() sets the image channel mask from the specified channel
2293% mask.
2294%
2295% The format of the SetImageChannelMask method is:
2296%
2297% ChannelType SetImageChannelMask(Image *image,
2298% const ChannelType channel_mask)
2299%
2300% A description of each parameter follows:
2301%
2302% o image: the image.
2303%
2304% o channel_mask: the channel mask.
2305%
2306*/
2307MagickExport ChannelType SetImageChannelMask(Image *image,
2308 const ChannelType channel_mask)
2309{
cristybcd59342015-06-07 14:07:19 +00002310 return(SetPixelChannelMask(image,channel_mask));
cristycf1296e2012-08-26 23:40:49 +00002311}
2312
2313/*
2314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315% %
2316% %
2317% %
cristya5b77cb2010-05-07 19:34:48 +00002318% S e t I m a g e C o l o r %
2319% %
2320% %
2321% %
2322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2323%
2324% SetImageColor() set the entire image canvas to the specified color.
2325%
2326% The format of the SetImageColor method is:
2327%
cristye941a752011-10-15 01:52:48 +00002328% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2329% ExeptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002330%
2331% A description of each parameter follows:
2332%
2333% o image: the image.
2334%
2335% o background: the image color.
2336%
cristye941a752011-10-15 01:52:48 +00002337% o exception: return any errors or warnings in this structure.
2338%
cristya5b77cb2010-05-07 19:34:48 +00002339*/
2340MagickExport MagickBooleanType SetImageColor(Image *image,
cristye941a752011-10-15 01:52:48 +00002341 const PixelInfo *color,ExceptionInfo *exception)
cristya5b77cb2010-05-07 19:34:48 +00002342{
2343 CacheView
2344 *image_view;
2345
cristya5b77cb2010-05-07 19:34:48 +00002346 MagickBooleanType
2347 status;
2348
cristycb6d09b2010-06-19 01:59:36 +00002349 ssize_t
2350 y;
2351
cristya5b77cb2010-05-07 19:34:48 +00002352 assert(image != (Image *) NULL);
2353 if (image->debug != MagickFalse)
2354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00002355 assert(image->signature == MagickCoreSignature);
cristy4c08aed2011-07-01 19:47:50 +00002356 assert(color != (const PixelInfo *) NULL);
cristya5b77cb2010-05-07 19:34:48 +00002357 image->colorspace=color->colorspace;
cristy8a46d822012-08-28 23:32:39 +00002358 image->alpha_trait=color->alpha_trait;
cristya5b77cb2010-05-07 19:34:48 +00002359 image->fuzz=color->fuzz;
2360 image->depth=color->depth;
2361 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002362 image_view=AcquireAuthenticCacheView(image,exception);
cristya5b77cb2010-05-07 19:34:48 +00002363#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00002364 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00002365 magick_threads(image,image,image->rows,1)
cristya5b77cb2010-05-07 19:34:48 +00002366#endif
cristybb503372010-05-27 20:51:26 +00002367 for (y=0; y < (ssize_t) image->rows; y++)
cristya5b77cb2010-05-07 19:34:48 +00002368 {
cristy4c08aed2011-07-01 19:47:50 +00002369 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002370 *magick_restrict q;
cristya5b77cb2010-05-07 19:34:48 +00002371
cristycb6d09b2010-06-19 01:59:36 +00002372 register ssize_t
2373 x;
2374
cristya5b77cb2010-05-07 19:34:48 +00002375 if (status == MagickFalse)
2376 continue;
2377 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002378 if (q == (Quantum *) NULL)
cristya5b77cb2010-05-07 19:34:48 +00002379 {
2380 status=MagickFalse;
2381 continue;
2382 }
cristybb503372010-05-27 20:51:26 +00002383 for (x=0; x < (ssize_t) image->columns; x++)
cristya5b77cb2010-05-07 19:34:48 +00002384 {
cristy11a06d32015-01-04 12:03:27 +00002385 SetPixelViaPixelInfo(image,color,q);
cristyed231572011-07-14 02:18:59 +00002386 q+=GetPixelChannels(image);
cristya5b77cb2010-05-07 19:34:48 +00002387 }
2388 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2389 status=MagickFalse;
2390 }
2391 image_view=DestroyCacheView(image_view);
2392 return(status);
2393}
2394
2395/*
2396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397% %
2398% %
2399% %
cristy3ed852e2009-09-05 21:47:34 +00002400% S e t I m a g e S t o r a g e C l a s s %
2401% %
2402% %
2403% %
2404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2405%
2406% SetImageStorageClass() sets the image class: DirectClass for true color
2407% images or PseudoClass for colormapped images.
2408%
2409% The format of the SetImageStorageClass method is:
2410%
2411% MagickBooleanType SetImageStorageClass(Image *image,
cristy63240882011-08-05 19:05:27 +00002412% const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002413%
2414% A description of each parameter follows:
2415%
2416% o image: the image.
2417%
2418% o storage_class: The image class.
2419%
cristy574cc262011-08-05 01:23:58 +00002420% o exception: return any errors or warnings in this structure.
2421%
cristy3ed852e2009-09-05 21:47:34 +00002422*/
2423MagickExport MagickBooleanType SetImageStorageClass(Image *image,
cristy574cc262011-08-05 01:23:58 +00002424 const ClassType storage_class,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002425{
cristy3ed852e2009-09-05 21:47:34 +00002426 image->storage_class=storage_class;
cristy6e437132011-08-12 13:02:19 +00002427 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002428}
2429
2430/*
2431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2432% %
2433% %
2434% %
cristy3ed852e2009-09-05 21:47:34 +00002435% S e t I m a g e E x t e n t %
2436% %
2437% %
2438% %
2439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2440%
2441% SetImageExtent() sets the image size (i.e. columns & rows).
2442%
2443% The format of the SetImageExtent method is:
2444%
cristy08429172011-07-14 17:18:16 +00002445% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002446% const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002447%
2448% A description of each parameter follows:
2449%
2450% o image: the image.
2451%
2452% o columns: The image width in pixels.
2453%
2454% o rows: The image height in pixels.
2455%
cristy63240882011-08-05 19:05:27 +00002456% o exception: return any errors or warnings in this structure.
2457%
cristy3ed852e2009-09-05 21:47:34 +00002458*/
cristy08429172011-07-14 17:18:16 +00002459MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
cristy63240882011-08-05 19:05:27 +00002460 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002461{
cristy537e2722010-09-21 15:30:59 +00002462 if ((columns == 0) || (rows == 0))
Cristy852231d2016-06-24 07:18:31 -04002463 ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
cristy537e2722010-09-21 15:30:59 +00002464 image->columns=columns;
2465 image->rows=rows;
cristyda950bb2015-07-18 23:17:28 +00002466 if (image->depth > (8*sizeof(MagickSizeType)))
2467 ThrowBinaryException(ImageError,"ImageDepthNotSupported",image->filename);
cristy6e437132011-08-12 13:02:19 +00002468 return(SyncImagePixelCache(image,exception));
cristy3ed852e2009-09-05 21:47:34 +00002469}
2470
2471/*
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473% %
2474% %
2475% %
2476+ S e t I m a g e I n f o %
2477% %
2478% %
2479% %
2480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2481%
anthonye5b39652012-04-21 05:37:29 +00002482% SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
cristy3ed852e2009-09-05 21:47:34 +00002483% It is set to a type of image format based on the prefix or suffix of the
anthonye5b39652012-04-21 05:37:29 +00002484% filename. For example, 'ps:image' returns PS indicating a Postscript image.
2485% JPEG is returned for this filename: 'image.jpg'. The filename prefix has
cristy3ed852e2009-09-05 21:47:34 +00002486% precendence over the suffix. Use an optional index enclosed in brackets
2487% after a file name to specify a desired scene of a multi-resolution image
2488% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2489% indicates success.
2490%
2491% The format of the SetImageInfo method is:
2492%
2493% MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002494% const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002495%
2496% A description of each parameter follows:
2497%
cristyd965a422010-03-03 17:47:35 +00002498% o image_info: the image info.
cristy3ed852e2009-09-05 21:47:34 +00002499%
cristyd965a422010-03-03 17:47:35 +00002500% o frames: the number of images you intend to write.
cristy3ed852e2009-09-05 21:47:34 +00002501%
2502% o exception: return any errors or warnings in this structure.
2503%
2504*/
2505MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
cristyd965a422010-03-03 17:47:35 +00002506 const unsigned int frames,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002507{
2508 char
dirk8f681612015-04-16 21:05:08 +00002509 component[MagickPathExtent],
cristy151b66d2015-04-15 10:50:31 +00002510 magic[MagickPathExtent],
dirk8f681612015-04-16 21:05:08 +00002511 *q;
cristy3ed852e2009-09-05 21:47:34 +00002512
2513 const MagicInfo
2514 *magic_info;
2515
2516 const MagickInfo
2517 *magick_info;
2518
2519 ExceptionInfo
2520 *sans_exception;
2521
2522 Image
2523 *image;
2524
2525 MagickBooleanType
2526 status;
2527
2528 register const char
2529 *p;
2530
2531 ssize_t
2532 count;
2533
cristy3ed852e2009-09-05 21:47:34 +00002534 /*
2535 Look for 'image.format' in filename.
2536 */
2537 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002538 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002539 if (image_info->debug != MagickFalse)
2540 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2541 image_info->filename);
dirk8f681612015-04-16 21:05:08 +00002542 *component='\0';
2543 GetPathComponent(image_info->filename,SubimagePath,component);
2544 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002545 {
cristy4f96a1d2014-01-04 15:31:36 +00002546 /*
2547 Look for scene specification (e.g. img0001.pcd[4]).
2548 */
dirk8f681612015-04-16 21:05:08 +00002549 if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002550 {
dirk8f681612015-04-16 21:05:08 +00002551 if (IsGeometry(component) != MagickFalse)
2552 (void) CloneString(&image_info->extract,component);
cristy4f96a1d2014-01-04 15:31:36 +00002553 }
2554 else
2555 {
2556 size_t
2557 first,
2558 last;
cristy3ed852e2009-09-05 21:47:34 +00002559
dirk8f681612015-04-16 21:05:08 +00002560 (void) CloneString(&image_info->scenes,component);
cristy4f96a1d2014-01-04 15:31:36 +00002561 image_info->scene=StringToUnsignedLong(image_info->scenes);
2562 image_info->number_scenes=image_info->scene;
2563 p=image_info->scenes;
2564 for (q=(char *) image_info->scenes; *q != '\0'; p++)
2565 {
2566 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2567 p++;
2568 first=(size_t) strtol(p,&q,10);
2569 last=first;
2570 while (isspace((int) ((unsigned char) *q)) != 0)
2571 q++;
2572 if (*q == '-')
2573 last=(size_t) strtol(q+1,&q,10);
2574 if (first > last)
2575 Swap(first,last);
2576 if (first < image_info->scene)
2577 image_info->scene=first;
2578 if (last > image_info->number_scenes)
2579 image_info->number_scenes=last;
2580 p=q;
2581 }
2582 image_info->number_scenes-=image_info->scene-1;
cristy3ed852e2009-09-05 21:47:34 +00002583 }
2584 }
dirk8f681612015-04-16 21:05:08 +00002585 *component='\0';
cristy6f7cebf2014-12-27 12:10:39 +00002586 if (*image_info->magick == '\0')
dirk8f681612015-04-16 21:05:08 +00002587 GetPathComponent(image_info->filename,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002588#if defined(MAGICKCORE_ZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002589 if (*component != '\0')
2590 if ((LocaleCompare(component,"gz") == 0) ||
2591 (LocaleCompare(component,"Z") == 0) ||
2592 (LocaleCompare(component,"svgz") == 0) ||
2593 (LocaleCompare(component,"wmz") == 0))
cristy3ed852e2009-09-05 21:47:34 +00002594 {
2595 char
cristy151b66d2015-04-15 10:50:31 +00002596 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002597
cristy151b66d2015-04-15 10:50:31 +00002598 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002599 path[strlen(path)-strlen(component)-1]='\0';
2600 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002601 }
2602#endif
2603#if defined(MAGICKCORE_BZLIB_DELEGATE)
dirk8f681612015-04-16 21:05:08 +00002604 if (*component != '\0')
2605 if (LocaleCompare(component,"bz2") == 0)
cristy3ed852e2009-09-05 21:47:34 +00002606 {
2607 char
cristy151b66d2015-04-15 10:50:31 +00002608 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002609
cristy151b66d2015-04-15 10:50:31 +00002610 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
dirk8f681612015-04-16 21:05:08 +00002611 path[strlen(path)-strlen(component)-1]='\0';
2612 GetPathComponent(path,ExtensionPath,component);
cristy3ed852e2009-09-05 21:47:34 +00002613 }
2614#endif
2615 image_info->affirm=MagickFalse;
2616 sans_exception=AcquireExceptionInfo();
dirk8f681612015-04-16 21:05:08 +00002617 if (*component != '\0')
cristy3ed852e2009-09-05 21:47:34 +00002618 {
2619 MagickFormatType
2620 format_type;
2621
cristybb503372010-05-27 20:51:26 +00002622 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002623 i;
2624
2625 static const char
2626 *format_type_formats[] =
2627 {
2628 "AUTOTRACE",
2629 "BROWSE",
2630 "DCRAW",
2631 "EDIT",
cristy3ed852e2009-09-05 21:47:34 +00002632 "LAUNCH",
2633 "MPEG:DECODE",
2634 "MPEG:ENCODE",
2635 "PRINT",
2636 "PS:ALPHA",
2637 "PS:CMYK",
2638 "PS:COLOR",
2639 "PS:GRAY",
2640 "PS:MONO",
2641 "SCAN",
2642 "SHOW",
2643 "WIN",
2644 (char *) NULL
2645 };
2646
2647 /*
2648 User specified image format.
2649 */
dirk8f681612015-04-16 21:05:08 +00002650 (void) CopyMagickString(magic,component,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002651 LocaleUpper(magic);
2652 /*
2653 Look for explicit image formats.
2654 */
2655 format_type=UndefinedFormatType;
dirk80fd8af2015-02-22 00:45:51 +00002656 magick_info=GetMagickInfo(magic,sans_exception);
2657 if ((magick_info != (const MagickInfo *) NULL) &&
2658 (magick_info->format_type != UndefinedFormatType))
2659 format_type=magick_info->format_type;
cristy3ed852e2009-09-05 21:47:34 +00002660 i=0;
cristydd9a2532010-02-20 19:26:46 +00002661 while ((format_type == UndefinedFormatType) &&
cristy3ed852e2009-09-05 21:47:34 +00002662 (format_type_formats[i] != (char *) NULL))
2663 {
2664 if ((*magic == *format_type_formats[i]) &&
2665 (LocaleCompare(magic,format_type_formats[i]) == 0))
2666 format_type=ExplicitFormatType;
2667 i++;
2668 }
cristy3ed852e2009-09-05 21:47:34 +00002669 if (format_type == UndefinedFormatType)
cristy151b66d2015-04-15 10:50:31 +00002670 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002671 else
2672 if (format_type == ExplicitFormatType)
2673 {
2674 image_info->affirm=MagickTrue;
cristy151b66d2015-04-15 10:50:31 +00002675 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002676 }
2677 if (LocaleCompare(magic,"RGB") == 0)
2678 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2679 }
2680 /*
2681 Look for explicit 'format:image' in filename.
2682 */
2683 *magic='\0';
2684 GetPathComponent(image_info->filename,MagickPath,magic);
2685 if (*magic == '\0')
Cristya8079ac2016-06-02 16:07:24 -04002686 {
2687 (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2688 magick_info=GetMagickInfo(magic,sans_exception);
Cristy0093cff2016-06-05 19:00:17 -04002689 GetPathComponent(image_info->filename,CanonicalPath,component);
2690 (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
Cristya8079ac2016-06-02 16:07:24 -04002691 }
cristy3ed852e2009-09-05 21:47:34 +00002692 else
2693 {
Cristy446b7ac2016-06-06 09:18:22 -04002694 const DelegateInfo
2695 *delegate_info;
2696
cristy3ed852e2009-09-05 21:47:34 +00002697 /*
2698 User specified image format.
2699 */
2700 LocaleUpper(magic);
Cristya8079ac2016-06-02 16:07:24 -04002701 magick_info=GetMagickInfo(magic,sans_exception);
Cristy75904212016-06-06 09:28:53 -04002702 delegate_info=GetDelegateInfo(magic,"*",sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002703 if (delegate_info == (const DelegateInfo *) NULL)
Cristy75904212016-06-06 09:28:53 -04002704 delegate_info=GetDelegateInfo("*",magic,sans_exception);
Cristy446b7ac2016-06-06 09:18:22 -04002705 if (((magick_info != (const MagickInfo *) NULL) ||
2706 (delegate_info != (const DelegateInfo *) NULL)) &&
Cristya8079ac2016-06-02 16:07:24 -04002707 (IsMagickConflict(magic) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002708 {
Cristyb831d902016-05-07 08:23:15 -04002709 image_info->affirm=MagickTrue;
Cristy446b7ac2016-06-06 09:18:22 -04002710 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
Cristy0093cff2016-06-05 19:00:17 -04002711 GetPathComponent(image_info->filename,CanonicalPath,component);
2712 (void) CopyMagickString(image_info->filename,component,
2713 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002714 }
2715 }
cristy3ed852e2009-09-05 21:47:34 +00002716 sans_exception=DestroyExceptionInfo(sans_exception);
2717 if ((magick_info == (const MagickInfo *) NULL) ||
2718 (GetMagickEndianSupport(magick_info) == MagickFalse))
2719 image_info->endian=UndefinedEndian;
cristyd965a422010-03-03 17:47:35 +00002720 if ((image_info->adjoin != MagickFalse) && (frames > 1))
cristy3ed852e2009-09-05 21:47:34 +00002721 {
2722 /*
cristyd965a422010-03-03 17:47:35 +00002723 Test for multiple image support (e.g. image%02d.png).
cristy3ed852e2009-09-05 21:47:34 +00002724 */
cristyd965a422010-03-03 17:47:35 +00002725 (void) InterpretImageFilename(image_info,(Image *) NULL,
dirk8f681612015-04-16 21:05:08 +00002726 image_info->filename,(int) image_info->scene,component,exception);
2727 if ((LocaleCompare(component,image_info->filename) != 0) &&
2728 (strchr(component,'%') == (char *) NULL))
cristyd965a422010-03-03 17:47:35 +00002729 image_info->adjoin=MagickFalse;
2730 }
2731 if ((image_info->adjoin != MagickFalse) && (frames > 0))
2732 {
2733 /*
2734 Some image formats do not support multiple frames per file.
2735 */
cristy3ed852e2009-09-05 21:47:34 +00002736 magick_info=GetMagickInfo(magic,exception);
2737 if (magick_info != (const MagickInfo *) NULL)
2738 if (GetMagickAdjoin(magick_info) == MagickFalse)
2739 image_info->adjoin=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002740 }
2741 if (image_info->affirm != MagickFalse)
2742 return(MagickTrue);
cristyd965a422010-03-03 17:47:35 +00002743 if (frames == 0)
cristy3ed852e2009-09-05 21:47:34 +00002744 {
dirk8f681612015-04-16 21:05:08 +00002745 unsigned char
2746 *magick;
2747
2748 size_t
2749 magick_size;
2750
cristy3ed852e2009-09-05 21:47:34 +00002751 /*
cristyd965a422010-03-03 17:47:35 +00002752 Determine the image format from the first few bytes of the file.
cristy3ed852e2009-09-05 21:47:34 +00002753 */
cristy4f06b882015-04-17 00:16:45 +00002754 magick_size=GetMagicPatternExtent(exception);
dirk8f681612015-04-16 21:05:08 +00002755 if (magick_size == 0)
2756 return(MagickFalse);
cristy9950d572011-10-01 18:22:35 +00002757 image=AcquireImage(image_info,exception);
cristyd965a422010-03-03 17:47:35 +00002758 (void) CopyMagickString(image->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +00002759 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00002760 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2761 if (status == MagickFalse)
2762 {
2763 image=DestroyImage(image);
2764 return(MagickFalse);
2765 }
cristyd965a422010-03-03 17:47:35 +00002766 if ((IsBlobSeekable(image) == MagickFalse) ||
2767 (IsBlobExempt(image) != MagickFalse))
2768 {
2769 /*
2770 Copy standard input or pipe to temporary file.
2771 */
dirk8f681612015-04-16 21:05:08 +00002772 *component='\0';
2773 status=ImageToFile(image,component,exception);
cristyd965a422010-03-03 17:47:35 +00002774 (void) CloseBlob(image);
2775 if (status == MagickFalse)
2776 {
2777 image=DestroyImage(image);
2778 return(MagickFalse);
2779 }
2780 SetImageInfoFile(image_info,(FILE *) NULL);
dirk8f681612015-04-16 21:05:08 +00002781 (void) CopyMagickString(image->filename,component,MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002782 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2783 if (status == MagickFalse)
2784 {
2785 image=DestroyImage(image);
2786 return(MagickFalse);
2787 }
cristyee2f5d62015-07-28 13:19:43 +00002788 (void) CopyMagickString(image_info->filename,component,
2789 MagickPathExtent);
cristyd965a422010-03-03 17:47:35 +00002790 image_info->temporary=MagickTrue;
2791 }
dirk8f681612015-04-16 21:05:08 +00002792 magick=(unsigned char *) AcquireMagickMemory(magick_size);
2793 if (magick == (unsigned char *) NULL)
2794 {
2795 (void) CloseBlob(image);
2796 image=DestroyImage(image);
2797 return(MagickFalse);
2798 }
2799 (void) ResetMagickMemory(magick,0,magick_size);
2800 count=ReadBlob(image,magick_size,magick);
cristyae958042013-01-05 15:48:19 +00002801 (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
cristyd965a422010-03-03 17:47:35 +00002802 (void) CloseBlob(image);
2803 image=DestroyImage(image);
2804 /*
2805 Check magic.xml configuration file.
2806 */
2807 sans_exception=AcquireExceptionInfo();
2808 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
dirk8f681612015-04-16 21:05:08 +00002809 magick=(unsigned char *) RelinquishMagickMemory(magick);
cristyd965a422010-03-03 17:47:35 +00002810 if ((magic_info != (const MagicInfo *) NULL) &&
2811 (GetMagicName(magic_info) != (char *) NULL))
2812 {
dirkca89a9b2015-02-22 01:19:21 +00002813 /*
2814 Try to use magick_info that was determined earlier by the extension
2815 */
2816 if ((magick_info != (const MagickInfo *) NULL) &&
2817 (GetMagickUseExtension(magick_info) != MagickFalse) &&
2818 (LocaleCompare(magick_info->module,GetMagicName(
2819 magic_info)) == 0))
2820 (void) CopyMagickString(image_info->magick,magick_info->name,
cristy151b66d2015-04-15 10:50:31 +00002821 MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002822 else
2823 {
2824 (void) CopyMagickString(image_info->magick,GetMagicName(
cristy151b66d2015-04-15 10:50:31 +00002825 magic_info),MagickPathExtent);
dirkca89a9b2015-02-22 01:19:21 +00002826 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2827 }
cristyd965a422010-03-03 17:47:35 +00002828 if ((magick_info == (const MagickInfo *) NULL) ||
2829 (GetMagickEndianSupport(magick_info) == MagickFalse))
2830 image_info->endian=UndefinedEndian;
2831 sans_exception=DestroyExceptionInfo(sans_exception);
2832 return(MagickTrue);
2833 }
cristy3ed852e2009-09-05 21:47:34 +00002834 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2835 if ((magick_info == (const MagickInfo *) NULL) ||
2836 (GetMagickEndianSupport(magick_info) == MagickFalse))
2837 image_info->endian=UndefinedEndian;
2838 sans_exception=DestroyExceptionInfo(sans_exception);
cristy3ed852e2009-09-05 21:47:34 +00002839 }
cristy3ed852e2009-09-05 21:47:34 +00002840 return(MagickTrue);
2841}
2842
2843/*
2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845% %
2846% %
2847% %
2848% S e t I m a g e I n f o B l o b %
2849% %
2850% %
2851% %
2852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853%
2854% SetImageInfoBlob() sets the image info blob member.
2855%
2856% The format of the SetImageInfoBlob method is:
2857%
2858% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2859% const size_t length)
2860%
2861% A description of each parameter follows:
2862%
2863% o image_info: the image info.
2864%
2865% o blob: the blob.
2866%
2867% o length: the blob length.
2868%
2869*/
2870MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2871 const size_t length)
2872{
2873 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002874 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002875 if (image_info->debug != MagickFalse)
2876 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2877 image_info->filename);
2878 image_info->blob=(void *) blob;
2879 image_info->length=length;
2880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
2887% S e t I m a g e I n f o F i l e %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% SetImageInfoFile() sets the image info file member.
2894%
2895% The format of the SetImageInfoFile method is:
2896%
2897% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2898%
2899% A description of each parameter follows:
2900%
2901% o image_info: the image info.
2902%
2903% o file: the file.
2904%
2905*/
2906MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2907{
2908 assert(image_info != (ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002909 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00002910 if (image_info->debug != MagickFalse)
2911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2912 image_info->filename);
2913 image_info->file=file;
2914}
2915
2916/*
2917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918% %
2919% %
2920% %
Cristy03811ea2016-07-27 20:32:47 -04002921% S e t I m a g e A l p h a %
2922% %
2923% %
2924% %
2925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926%
2927% SetImageAlpha() sets the alpha levels of the image.
2928%
2929% The format of the SetImageAlpha method is:
2930%
2931% MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2932% ExceptionInfo *exception)
2933%
2934% A description of each parameter follows:
2935%
2936% o image: the image.
2937%
2938% o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
2939% fully transparent.
2940%
2941*/
2942MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2943 ExceptionInfo *exception)
2944{
2945 CacheView
2946 *image_view;
2947
2948 MagickBooleanType
2949 status;
2950
2951 ssize_t
2952 y;
2953
2954 assert(image != (Image *) NULL);
2955 if (image->debug != MagickFalse)
2956 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2957 assert(image->signature == MagickCoreSignature);
2958 image->alpha_trait=BlendPixelTrait;
2959 status=MagickTrue;
2960 image_view=AcquireAuthenticCacheView(image,exception);
2961#if defined(MAGICKCORE_OPENMP_SUPPORT)
2962 #pragma omp parallel for schedule(static,4) shared(status) \
2963 magick_threads(image,image,image->rows,1)
2964#endif
2965 for (y=0; y < (ssize_t) image->rows; y++)
2966 {
2967 register Quantum
2968 *magick_restrict q;
2969
2970 register ssize_t
2971 x;
2972
2973 if (status == MagickFalse)
2974 continue;
2975 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2976 if (q == (Quantum *) NULL)
2977 {
2978 status=MagickFalse;
2979 continue;
2980 }
2981 for (x=0; x < (ssize_t) image->columns; x++)
2982 {
Cristydf5e8b12016-12-02 17:26:39 -05002983 if (GetPixelWriteMask(image,q) != 0)
Cristy03811ea2016-07-27 20:32:47 -04002984 SetPixelAlpha(image,alpha,q);
2985 q+=GetPixelChannels(image);
2986 }
2987 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2988 status=MagickFalse;
2989 }
2990 image_view=DestroyCacheView(image_view);
2991 return(status);
2992}
2993
2994/*
2995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996% %
2997% %
2998% %
cristy3ed852e2009-09-05 21:47:34 +00002999% S e t I m a g e M a s k %
3000% %
3001% %
3002% %
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004%
3005% SetImageMask() associates a mask with the image. The mask must be the same
3006% dimensions as the image.
3007%
3008% The format of the SetImageMask method is:
3009%
cristyacd0d4c2015-07-25 16:12:33 +00003010% MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3011% const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003012%
3013% A description of each parameter follows:
3014%
3015% o image: the image.
3016%
cristyacd0d4c2015-07-25 16:12:33 +00003017% o type: the mask type, ReadPixelMask or WritePixelMask.
3018%
cristy3ed852e2009-09-05 21:47:34 +00003019% o mask: the image mask.
3020%
cristy018f07f2011-09-04 21:15:19 +00003021% o exception: return any errors or warnings in this structure.
3022%
cristy3ed852e2009-09-05 21:47:34 +00003023*/
cristyacd0d4c2015-07-25 16:12:33 +00003024MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3025 const Image *mask,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003026{
cristy10a6c612012-01-29 21:41:05 +00003027 CacheView
3028 *mask_view,
3029 *image_view;
3030
3031 MagickBooleanType
3032 status;
3033
3034 ssize_t
3035 y;
3036
3037 /*
3038 Set image mask.
3039 */
cristy3ed852e2009-09-05 21:47:34 +00003040 assert(image != (Image *) NULL);
3041 if (image->debug != MagickFalse)
3042 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003043 assert(image->signature == MagickCoreSignature);
cristy10a6c612012-01-29 21:41:05 +00003044 if (mask == (const Image *) NULL)
3045 {
cristyacd0d4c2015-07-25 16:12:33 +00003046 switch (type)
3047 {
3048 case WritePixelMask: image->write_mask=MagickFalse; break;
3049 default: image->read_mask=MagickFalse; break;
3050 }
cristyd5be1f12013-03-18 23:55:01 +00003051 return(SyncImagePixelCache(image,exception));
cristy10a6c612012-01-29 21:41:05 +00003052 }
cristyacd0d4c2015-07-25 16:12:33 +00003053 switch (type)
3054 {
3055 case WritePixelMask: image->write_mask=MagickTrue; break;
3056 default: image->read_mask=MagickTrue; break;
3057 }
cristyd5be1f12013-03-18 23:55:01 +00003058 if (SyncImagePixelCache(image,exception) == MagickFalse)
3059 return(MagickFalse);
3060 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003061 mask_view=AcquireVirtualCacheView(mask,exception);
3062 image_view=AcquireAuthenticCacheView(image,exception);
cristyd5be1f12013-03-18 23:55:01 +00003063#if defined(MAGICKCORE_OPENMP_SUPPORT)
3064 #pragma omp parallel for schedule(static,4) shared(status) \
3065 magick_threads(mask,image,1,1)
3066#endif
cristy10a6c612012-01-29 21:41:05 +00003067 for (y=0; y < (ssize_t) image->rows; y++)
3068 {
3069 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003070 *magick_restrict p;
cristy10a6c612012-01-29 21:41:05 +00003071
3072 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003073 *magick_restrict q;
cristy10a6c612012-01-29 21:41:05 +00003074
3075 register ssize_t
3076 x;
3077
3078 if (status == MagickFalse)
3079 continue;
3080 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3081 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3082 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3083 {
3084 status=MagickFalse;
3085 continue;
3086 }
3087 for (x=0; x < (ssize_t) image->columns; x++)
3088 {
Cristy0596ce22015-11-20 21:11:22 -05003089 MagickRealType
3090 intensity;
3091
Cristy3761dd42016-12-03 09:54:21 -05003092 intensity=0;
Cristy4da63352016-12-03 08:59:32 -05003093 if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3094 intensity=GetPixelIntensity(mask,p);
cristyacd0d4c2015-07-25 16:12:33 +00003095 switch (type)
3096 {
3097 case WritePixelMask:
3098 {
Cristyd60923b2016-12-02 19:37:09 -05003099 SetPixelWriteMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003100 break;
3101 }
3102 default:
3103 {
Cristyd60923b2016-12-02 19:37:09 -05003104 SetPixelReadMask(image,ClampToQuantum(intensity),q);
cristyacd0d4c2015-07-25 16:12:33 +00003105 break;
3106 }
3107 }
cristy10a6c612012-01-29 21:41:05 +00003108 p+=GetPixelChannels(mask);
3109 q+=GetPixelChannels(image);
3110 }
3111 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3112 status=MagickFalse;
3113 }
3114 mask_view=DestroyCacheView(mask_view);
3115 image_view=DestroyCacheView(image_view);
3116 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003117}
3118
3119/*
3120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121% %
3122% %
3123% %
Cristy03811ea2016-07-27 20:32:47 -04003124% S e t I m a g e R e g i o n M a s k %
cristy3ed852e2009-09-05 21:47:34 +00003125% %
3126% %
3127% %
3128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129%
Cristyd47057b2016-07-28 18:57:46 -04003130% SetImageRegionMask() associates a mask with the image as defined by the
3131% specified region.
cristy3ed852e2009-09-05 21:47:34 +00003132%
Cristy03811ea2016-07-27 20:32:47 -04003133% The format of the SetImageRegionMask method is:
cristy3ed852e2009-09-05 21:47:34 +00003134%
Cristy03811ea2016-07-27 20:32:47 -04003135% MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3136% const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003137%
3138% A description of each parameter follows:
3139%
3140% o image: the image.
3141%
Cristy03811ea2016-07-27 20:32:47 -04003142% o type: the mask type, ReadPixelMask or WritePixelMask.
3143%
3144% o geometry: the mask region.
3145%
3146% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00003147%
3148*/
Cristy03811ea2016-07-27 20:32:47 -04003149MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3150 const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003151{
3152 CacheView
3153 *image_view;
3154
cristy3ed852e2009-09-05 21:47:34 +00003155 MagickBooleanType
3156 status;
3157
cristycb6d09b2010-06-19 01:59:36 +00003158 ssize_t
3159 y;
3160
Cristy03811ea2016-07-27 20:32:47 -04003161 /*
3162 Set image mask as defined by the region.
3163 */
cristy3ed852e2009-09-05 21:47:34 +00003164 assert(image != (Image *) NULL);
3165 if (image->debug != MagickFalse)
3166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003167 assert(image->signature == MagickCoreSignature);
Cristy03811ea2016-07-27 20:32:47 -04003168 if (region == (const RectangleInfo *) NULL)
3169 {
3170 switch (type)
3171 {
3172 case WritePixelMask: image->write_mask=MagickFalse; break;
3173 default: image->read_mask=MagickFalse; break;
3174 }
3175 return(SyncImagePixelCache(image,exception));
3176 }
3177 switch (type)
3178 {
3179 case WritePixelMask: image->write_mask=MagickTrue; break;
3180 default: image->read_mask=MagickTrue; break;
3181 }
3182 if (SyncImagePixelCache(image,exception) == MagickFalse)
3183 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00003184 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00003185 image_view=AcquireAuthenticCacheView(image,exception);
cristyb5d5f722009-11-04 03:03:49 +00003186#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003187 #pragma omp parallel for schedule(static,4) shared(status) \
Cristy03811ea2016-07-27 20:32:47 -04003188 magick_threads(image,image,1,1)
cristy3ed852e2009-09-05 21:47:34 +00003189#endif
cristybb503372010-05-27 20:51:26 +00003190 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003191 {
cristy4c08aed2011-07-01 19:47:50 +00003192 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003193 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003194
cristycb6d09b2010-06-19 01:59:36 +00003195 register ssize_t
3196 x;
3197
cristy3ed852e2009-09-05 21:47:34 +00003198 if (status == MagickFalse)
3199 continue;
3200 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003201 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003202 {
3203 status=MagickFalse;
3204 continue;
3205 }
cristybb503372010-05-27 20:51:26 +00003206 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003207 {
Cristy36610622016-07-28 17:41:37 -04003208 Quantum
3209 pixel;
Cristy03811ea2016-07-27 20:32:47 -04003210
Cristy36610622016-07-28 17:41:37 -04003211 pixel=0;
Cristy338f0882016-12-10 12:12:35 -05003212 if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3213 ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
Cristy36610622016-07-28 17:41:37 -04003214 pixel=QuantumRange;
Cristy03811ea2016-07-27 20:32:47 -04003215 switch (type)
3216 {
3217 case WritePixelMask:
3218 {
Cristy36610622016-07-28 17:41:37 -04003219 SetPixelWriteMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003220 break;
3221 }
3222 default:
3223 {
Cristy36610622016-07-28 17:41:37 -04003224 SetPixelReadMask(image,pixel,q);
Cristy03811ea2016-07-27 20:32:47 -04003225 break;
3226 }
3227 }
cristyed231572011-07-14 02:18:59 +00003228 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003229 }
3230 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3231 status=MagickFalse;
3232 }
3233 image_view=DestroyCacheView(image_view);
3234 return(status);
3235}
3236
3237/*
3238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3239% %
3240% %
3241% %
cristy3ed852e2009-09-05 21:47:34 +00003242% 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 %
3243% %
3244% %
3245% %
3246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3247%
3248% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3249% image and returns the previous setting. A virtual pixel is any pixel access
3250% that is outside the boundaries of the image cache.
3251%
3252% The format of the SetImageVirtualPixelMethod() method is:
3253%
cristy387430f2012-02-07 13:09:46 +00003254% VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3255% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003256%
3257% A description of each parameter follows:
3258%
3259% o image: the image.
3260%
3261% o virtual_pixel_method: choose the type of virtual pixel.
3262%
cristy387430f2012-02-07 13:09:46 +00003263% o exception: return any errors or warnings in this structure.
3264%
cristy3ed852e2009-09-05 21:47:34 +00003265*/
cristy387430f2012-02-07 13:09:46 +00003266MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3267 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003268{
3269 assert(image != (const Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003270 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003271 if (image->debug != MagickFalse)
3272 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy387430f2012-02-07 13:09:46 +00003273 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
cristy3ed852e2009-09-05 21:47:34 +00003274}
3275
3276/*
3277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3278% %
3279% %
3280% %
cristy4285d782011-02-09 20:12:28 +00003281% S m u s h I m a g e s %
3282% %
3283% %
3284% %
3285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3286%
3287% SmushImages() takes all images from the current image pointer to the end
3288% of the image list and smushes them to each other top-to-bottom if the
3289% stack parameter is true, otherwise left-to-right.
3290%
3291% The current gravity setting now effects how the image is justified in the
3292% final image.
3293%
3294% The format of the SmushImages method is:
3295%
cristy4ca38e22011-02-10 02:57:49 +00003296% Image *SmushImages(const Image *images,const MagickBooleanType stack,
cristy4285d782011-02-09 20:12:28 +00003297% ExceptionInfo *exception)
3298%
3299% A description of each parameter follows:
3300%
cristy4ca38e22011-02-10 02:57:49 +00003301% o images: the image sequence.
cristy4285d782011-02-09 20:12:28 +00003302%
3303% o stack: A value other than 0 stacks the images top-to-bottom.
3304%
3305% o offset: minimum distance in pixels between images.
3306%
3307% o exception: return any errors or warnings in this structure.
3308%
3309*/
cristy4ca38e22011-02-10 02:57:49 +00003310
cristy7c6dc152011-02-11 14:10:55 +00003311static ssize_t SmushXGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003312 const ssize_t offset,ExceptionInfo *exception)
cristy4ca38e22011-02-10 02:57:49 +00003313{
cristy4d727152011-02-10 19:57:21 +00003314 CacheView
3315 *left_view,
3316 *right_view;
3317
3318 const Image
3319 *left_image,
3320 *right_image;
3321
cristy4d727152011-02-10 19:57:21 +00003322 RectangleInfo
3323 left_geometry,
3324 right_geometry;
3325
cristy4c08aed2011-07-01 19:47:50 +00003326 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003327 *p;
3328
cristy4d727152011-02-10 19:57:21 +00003329 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003330 i,
cristy4d727152011-02-10 19:57:21 +00003331 y;
3332
cristy7c6dc152011-02-11 14:10:55 +00003333 size_t
3334 gap;
3335
cristy4d727152011-02-10 19:57:21 +00003336 ssize_t
cristy4d727152011-02-10 19:57:21 +00003337 x;
3338
3339 if (images->previous == (Image *) NULL)
3340 return(0);
3341 right_image=images;
3342 SetGeometry(smush_image,&right_geometry);
3343 GravityAdjustGeometry(right_image->columns,right_image->rows,
3344 right_image->gravity,&right_geometry);
3345 left_image=images->previous;
3346 SetGeometry(smush_image,&left_geometry);
3347 GravityAdjustGeometry(left_image->columns,left_image->rows,
3348 left_image->gravity,&left_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003349 gap=right_image->columns;
cristy46ff2672012-12-14 15:32:26 +00003350 left_view=AcquireVirtualCacheView(left_image,exception);
3351 right_view=AcquireVirtualCacheView(right_image,exception);
cristy4d727152011-02-10 19:57:21 +00003352 for (y=0; y < (ssize_t) smush_image->rows; y++)
3353 {
3354 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3355 {
cristydab7e912011-02-11 18:19:24 +00003356 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003357 if ((p == (const Quantum *) NULL) ||
3358 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
cristy7c6dc152011-02-11 14:10:55 +00003359 ((left_image->columns-x-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003360 break;
3361 }
cristy4ef6f062011-02-10 20:30:22 +00003362 i=(ssize_t) left_image->columns-x-1;
cristy4d727152011-02-10 19:57:21 +00003363 for (x=0; x < (ssize_t) right_image->columns; x++)
3364 {
cristydab7e912011-02-11 18:19:24 +00003365 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
cristy279d8212011-02-10 20:05:02 +00003366 exception);
cristy4c08aed2011-07-01 19:47:50 +00003367 if ((p == (const Quantum *) NULL) ||
3368 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3369 ((x+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003370 break;
3371 }
cristy7c6dc152011-02-11 14:10:55 +00003372 if ((x+i) < (ssize_t) gap)
3373 gap=(size_t) (x+i);
cristy4d727152011-02-10 19:57:21 +00003374 }
3375 right_view=DestroyCacheView(right_view);
3376 left_view=DestroyCacheView(left_view);
cristydab7e912011-02-11 18:19:24 +00003377 if (y < (ssize_t) smush_image->rows)
3378 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003379 return((ssize_t) gap-offset);
cristyad5e6ee2011-02-10 14:26:00 +00003380}
3381
cristy7c6dc152011-02-11 14:10:55 +00003382static ssize_t SmushYGap(const Image *smush_image,const Image *images,
cristy4ef6f062011-02-10 20:30:22 +00003383 const ssize_t offset,ExceptionInfo *exception)
cristyad5e6ee2011-02-10 14:26:00 +00003384{
cristy4d727152011-02-10 19:57:21 +00003385 CacheView
3386 *bottom_view,
3387 *top_view;
3388
3389 const Image
3390 *bottom_image,
3391 *top_image;
3392
cristy4d727152011-02-10 19:57:21 +00003393 RectangleInfo
3394 bottom_geometry,
3395 top_geometry;
3396
cristy4c08aed2011-07-01 19:47:50 +00003397 register const Quantum
cristydab7e912011-02-11 18:19:24 +00003398 *p;
3399
cristy4d727152011-02-10 19:57:21 +00003400 register ssize_t
cristy4ef6f062011-02-10 20:30:22 +00003401 i,
cristy4d727152011-02-10 19:57:21 +00003402 x;
3403
cristy7c6dc152011-02-11 14:10:55 +00003404 size_t
3405 gap;
3406
cristy4d727152011-02-10 19:57:21 +00003407 ssize_t
cristy4d727152011-02-10 19:57:21 +00003408 y;
3409
3410 if (images->previous == (Image *) NULL)
3411 return(0);
3412 bottom_image=images;
3413 SetGeometry(smush_image,&bottom_geometry);
3414 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3415 bottom_image->gravity,&bottom_geometry);
3416 top_image=images->previous;
3417 SetGeometry(smush_image,&top_geometry);
3418 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3419 &top_geometry);
cristy7c6dc152011-02-11 14:10:55 +00003420 gap=bottom_image->rows;
cristy46ff2672012-12-14 15:32:26 +00003421 top_view=AcquireVirtualCacheView(top_image,exception);
3422 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
cristy4d727152011-02-10 19:57:21 +00003423 for (x=0; x < (ssize_t) smush_image->columns; x++)
3424 {
3425 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3426 {
cristydab7e912011-02-11 18:19:24 +00003427 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003428 if ((p == (const Quantum *) NULL) ||
3429 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3430 ((top_image->rows-y-1) >= gap))
cristy4d727152011-02-10 19:57:21 +00003431 break;
3432 }
cristy4ef6f062011-02-10 20:30:22 +00003433 i=(ssize_t) top_image->rows-y-1;
cristy4d727152011-02-10 19:57:21 +00003434 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3435 {
cristydab7e912011-02-11 18:19:24 +00003436 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3437 exception);
cristy4c08aed2011-07-01 19:47:50 +00003438 if ((p == (const Quantum *) NULL) ||
3439 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3440 ((y+i) >= (ssize_t) gap))
cristy4d727152011-02-10 19:57:21 +00003441 break;
3442 }
cristy7c6dc152011-02-11 14:10:55 +00003443 if ((y+i) < (ssize_t) gap)
3444 gap=(size_t) (y+i);
cristy4d727152011-02-10 19:57:21 +00003445 }
3446 bottom_view=DestroyCacheView(bottom_view);
3447 top_view=DestroyCacheView(top_view);
cristydab7e912011-02-11 18:19:24 +00003448 if (x < (ssize_t) smush_image->columns)
3449 return(offset);
cristy7c6dc152011-02-11 14:10:55 +00003450 return((ssize_t) gap-offset);
cristy4ca38e22011-02-10 02:57:49 +00003451}
3452
3453MagickExport Image *SmushImages(const Image *images,
cristy4285d782011-02-09 20:12:28 +00003454 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3455{
3456#define SmushImageTag "Smush/Image"
3457
cristy4ca38e22011-02-10 02:57:49 +00003458 const Image
3459 *image;
3460
cristy4285d782011-02-09 20:12:28 +00003461 Image
3462 *smush_image;
3463
3464 MagickBooleanType
cristy4285d782011-02-09 20:12:28 +00003465 proceed,
3466 status;
3467
3468 MagickOffsetType
3469 n;
3470
cristy5a5e4d92012-08-29 00:06:25 +00003471 PixelTrait
3472 alpha_trait;
3473
cristy4285d782011-02-09 20:12:28 +00003474 RectangleInfo
3475 geometry;
3476
3477 register const Image
3478 *next;
3479
3480 size_t
3481 height,
3482 number_images,
3483 width;
3484
3485 ssize_t
3486 x_offset,
cristy4285d782011-02-09 20:12:28 +00003487 y_offset;
3488
3489 /*
cristy7c6dc152011-02-11 14:10:55 +00003490 Compute maximum area of smushed area.
cristy4285d782011-02-09 20:12:28 +00003491 */
cristy4ca38e22011-02-10 02:57:49 +00003492 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003493 assert(images->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003494 if (images->debug != MagickFalse)
3495 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
cristy4285d782011-02-09 20:12:28 +00003496 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003497 assert(exception->signature == MagickCoreSignature);
cristy4ca38e22011-02-10 02:57:49 +00003498 image=images;
cristy5a5e4d92012-08-29 00:06:25 +00003499 alpha_trait=image->alpha_trait;
cristy4285d782011-02-09 20:12:28 +00003500 number_images=1;
3501 width=image->columns;
3502 height=image->rows;
3503 next=GetNextImageInList(image);
3504 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3505 {
cristy17f11b02014-12-20 19:37:04 +00003506 if (next->alpha_trait != UndefinedPixelTrait)
cristy5a5e4d92012-08-29 00:06:25 +00003507 alpha_trait=BlendPixelTrait;
cristy4285d782011-02-09 20:12:28 +00003508 number_images++;
3509 if (stack != MagickFalse)
3510 {
3511 if (next->columns > width)
3512 width=next->columns;
3513 height+=next->rows;
cristy4ef6f062011-02-10 20:30:22 +00003514 if (next->previous != (Image *) NULL)
3515 height+=offset;
cristy4285d782011-02-09 20:12:28 +00003516 continue;
3517 }
3518 width+=next->columns;
cristy4ef6f062011-02-10 20:30:22 +00003519 if (next->previous != (Image *) NULL)
3520 width+=offset;
cristy4285d782011-02-09 20:12:28 +00003521 if (next->rows > height)
3522 height=next->rows;
3523 }
3524 /*
cristy7c6dc152011-02-11 14:10:55 +00003525 Smush images.
cristy4285d782011-02-09 20:12:28 +00003526 */
3527 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3528 if (smush_image == (Image *) NULL)
3529 return((Image *) NULL);
cristy574cc262011-08-05 01:23:58 +00003530 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
cristy4285d782011-02-09 20:12:28 +00003531 {
cristy4285d782011-02-09 20:12:28 +00003532 smush_image=DestroyImage(smush_image);
3533 return((Image *) NULL);
3534 }
cristy5a5e4d92012-08-29 00:06:25 +00003535 smush_image->alpha_trait=alpha_trait;
cristyea1a8aa2011-10-20 13:24:06 +00003536 (void) SetImageBackgroundColor(smush_image,exception);
cristy4285d782011-02-09 20:12:28 +00003537 status=MagickTrue;
3538 x_offset=0;
3539 y_offset=0;
cristy4285d782011-02-09 20:12:28 +00003540 for (n=0; n < (MagickOffsetType) number_images; n++)
3541 {
3542 SetGeometry(smush_image,&geometry);
3543 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3544 if (stack != MagickFalse)
cristy4ca38e22011-02-10 02:57:49 +00003545 {
3546 x_offset-=geometry.x;
cristy7c6dc152011-02-11 14:10:55 +00003547 y_offset-=SmushYGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003548 }
cristy4285d782011-02-09 20:12:28 +00003549 else
cristy4ca38e22011-02-10 02:57:49 +00003550 {
cristy7c6dc152011-02-11 14:10:55 +00003551 x_offset-=SmushXGap(smush_image,image,offset,exception);
cristy4ca38e22011-02-10 02:57:49 +00003552 y_offset-=geometry.y;
cristy4ca38e22011-02-10 02:57:49 +00003553 }
cristy39172402012-03-30 13:04:39 +00003554 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3555 y_offset,exception);
cristy4285d782011-02-09 20:12:28 +00003556 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3557 if (proceed == MagickFalse)
3558 break;
3559 if (stack == MagickFalse)
3560 {
3561 x_offset+=(ssize_t) image->columns;
3562 y_offset=0;
3563 }
3564 else
3565 {
3566 x_offset=0;
3567 y_offset+=(ssize_t) image->rows;
3568 }
3569 image=GetNextImageInList(image);
3570 }
cristy4ef6f062011-02-10 20:30:22 +00003571 if (stack == MagickFalse)
3572 smush_image->columns=(size_t) x_offset;
cristy4d727152011-02-10 19:57:21 +00003573 else
cristy4ef6f062011-02-10 20:30:22 +00003574 smush_image->rows=(size_t) y_offset;
cristy4285d782011-02-09 20:12:28 +00003575 if (status == MagickFalse)
3576 smush_image=DestroyImage(smush_image);
3577 return(smush_image);
3578}
3579
3580/*
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582% %
3583% %
3584% %
cristy3ed852e2009-09-05 21:47:34 +00003585% S t r i p I m a g e %
3586% %
3587% %
3588% %
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590%
cristy376bda92009-12-22 21:15:23 +00003591% StripImage() strips an image of all profiles and comments.
cristy3ed852e2009-09-05 21:47:34 +00003592%
3593% The format of the StripImage method is:
3594%
cristye941a752011-10-15 01:52:48 +00003595% MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003596%
3597% A description of each parameter follows:
3598%
3599% o image: the image.
3600%
cristye941a752011-10-15 01:52:48 +00003601% o exception: return any errors or warnings in this structure.
3602%
cristy3ed852e2009-09-05 21:47:34 +00003603*/
cristye941a752011-10-15 01:52:48 +00003604MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003605{
cristye941a752011-10-15 01:52:48 +00003606 MagickBooleanType
3607 status;
3608
cristy3ed852e2009-09-05 21:47:34 +00003609 assert(image != (Image *) NULL);
3610 if (image->debug != MagickFalse)
3611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye941a752011-10-15 01:52:48 +00003612 (void) exception;
cristy3ed852e2009-09-05 21:47:34 +00003613 DestroyImageProfiles(image);
cristy6b9aca12010-02-21 01:50:11 +00003614 (void) DeleteImageProperty(image,"comment");
cristy7c99caa2010-09-13 17:19:54 +00003615 (void) DeleteImageProperty(image,"date:create");
3616 (void) DeleteImageProperty(image,"date:modify");
cristy42e14902014-05-01 22:40:40 +00003617 status=SetImageArtifact(image,"png:exclude-chunk",
Cristy8c2e6b42016-04-02 10:14:03 -04003618 "bKGD,cHRM,EXIF,gAMA,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
cristye941a752011-10-15 01:52:48 +00003619 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003620}
3621
3622/*
3623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3624% %
3625% %
3626% %
3627+ S y n c I m a g e %
3628% %
3629% %
3630% %
3631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632%
3633% SyncImage() initializes the red, green, and blue intensities of each pixel
3634% as defined by the colormap index.
3635%
3636% The format of the SyncImage method is:
3637%
cristyea1a8aa2011-10-20 13:24:06 +00003638% MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003639%
3640% A description of each parameter follows:
3641%
3642% o image: the image.
3643%
cristyea1a8aa2011-10-20 13:24:06 +00003644% o exception: return any errors or warnings in this structure.
3645%
cristy3ed852e2009-09-05 21:47:34 +00003646*/
3647
cristyaedc0312012-01-08 01:07:37 +00003648static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3649 MagickBooleanType *range_exception)
cristy3ed852e2009-09-05 21:47:34 +00003650{
cristyc8d63672012-01-11 13:03:13 +00003651 if ((size_t) index < image->colors)
cristyaedc0312012-01-08 01:07:37 +00003652 return(index);
cristy3ed852e2009-09-05 21:47:34 +00003653 *range_exception=MagickTrue;
cristyd9657d22012-08-23 14:25:31 +00003654 return((Quantum) 0);
cristy3ed852e2009-09-05 21:47:34 +00003655}
3656
cristyea1a8aa2011-10-20 13:24:06 +00003657MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003658{
3659 CacheView
3660 *image_view;
3661
cristy3ed852e2009-09-05 21:47:34 +00003662 MagickBooleanType
3663 range_exception,
dirkf5cb0472014-10-24 20:10:14 +00003664 status,
3665 taint;
cristy3ed852e2009-09-05 21:47:34 +00003666
cristycb6d09b2010-06-19 01:59:36 +00003667 ssize_t
3668 y;
3669
cristy3ed852e2009-09-05 21:47:34 +00003670 assert(image != (Image *) NULL);
3671 if (image->debug != MagickFalse)
3672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristye1c94d92015-06-28 12:16:33 +00003673 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003674 if (image->storage_class == DirectClass)
3675 return(MagickFalse);
3676 range_exception=MagickFalse;
3677 status=MagickTrue;
dirkf5cb0472014-10-24 20:10:14 +00003678 taint=image->taint;
cristy46ff2672012-12-14 15:32:26 +00003679 image_view=AcquireAuthenticCacheView(image,exception);
cristy48974b92009-12-19 02:36:06 +00003680#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00003681 #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
cristy5e6b2592012-12-19 14:08:11 +00003682 magick_threads(image,image,image->rows,1)
cristy48974b92009-12-19 02:36:06 +00003683#endif
cristybb503372010-05-27 20:51:26 +00003684 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003685 {
cristy4c08aed2011-07-01 19:47:50 +00003686 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003687 index;
3688
cristy4c08aed2011-07-01 19:47:50 +00003689 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01003690 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003691
cristycb6d09b2010-06-19 01:59:36 +00003692 register ssize_t
3693 x;
3694
cristy48974b92009-12-19 02:36:06 +00003695 if (status == MagickFalse)
3696 continue;
cristy3ed852e2009-09-05 21:47:34 +00003697 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00003698 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003699 {
3700 status=MagickFalse;
3701 continue;
3702 }
cristybb503372010-05-27 20:51:26 +00003703 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00003704 {
cristyaedc0312012-01-08 01:07:37 +00003705 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
cristy11a06d32015-01-04 12:03:27 +00003706 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +00003707 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00003708 }
3709 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3710 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00003711 }
3712 image_view=DestroyCacheView(image_view);
dirkf5cb0472014-10-24 20:10:14 +00003713 image->taint=taint;
cristycaf45802012-06-16 18:28:54 +00003714 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
dirkb081bb22016-01-27 12:56:48 +01003715 (void) ThrowMagickException(exception,GetMagickModule(),
3716 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003717 return(status);
3718}
cristy1626d332009-11-10 16:58:17 +00003719
3720/*
3721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722% %
3723% %
3724% %
3725% S y n c I m a g e S e t t i n g s %
3726% %
3727% %
3728% %
3729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730%
anthony5f78bca2012-10-05 06:51:00 +00003731% SyncImageSettings() syncs any image_info global options into per-image
3732% attributes.
3733%
anthonyc7994672012-11-17 05:33:27 +00003734% Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
anthony5f78bca2012-10-05 06:51:00 +00003735% that operations and coders can find such settings. In IMv7 if a desired
3736% per-image artifact is not set, then it will directly look for a global
anthonyc7994672012-11-17 05:33:27 +00003737% option as a fallback, as such this copy is no longer needed, only the
3738% link set up.
cristy1626d332009-11-10 16:58:17 +00003739%
3740% The format of the SyncImageSettings method is:
3741%
3742% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003743% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003744% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003745% Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003746%
3747% A description of each parameter follows:
3748%
3749% o image_info: the image info.
3750%
3751% o image: the image.
3752%
cristy6fccee12011-10-20 18:43:18 +00003753% o exception: return any errors or warnings in this structure.
3754%
cristy1626d332009-11-10 16:58:17 +00003755*/
3756
3757MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003758 Image *images,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003759{
3760 Image
3761 *image;
3762
3763 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003764 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003765 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003766 assert(images->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003767 if (images->debug != MagickFalse)
3768 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3769 image=images;
3770 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
cristy6fccee12011-10-20 18:43:18 +00003771 (void) SyncImageSettings(image_info,image,exception);
cristy1626d332009-11-10 16:58:17 +00003772 (void) DeleteImageOption(image_info,"page");
3773 return(MagickTrue);
3774}
3775
3776MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
cristy6fccee12011-10-20 18:43:18 +00003777 Image *image,ExceptionInfo *exception)
cristy1626d332009-11-10 16:58:17 +00003778{
cristy1626d332009-11-10 16:58:17 +00003779 const char
cristy202c1482012-10-05 23:47:57 +00003780 *option;
cristy1626d332009-11-10 16:58:17 +00003781
3782 GeometryInfo
3783 geometry_info;
3784
3785 MagickStatusType
3786 flags;
3787
cristy19eb6412010-04-23 14:42:29 +00003788 ResolutionType
3789 units;
3790
cristy1626d332009-11-10 16:58:17 +00003791 /*
3792 Sync image options.
3793 */
3794 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003795 assert(image_info->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003796 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003797 assert(image->signature == MagickCoreSignature);
cristy1626d332009-11-10 16:58:17 +00003798 if (image->debug != MagickFalse)
3799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
dirkb797b2c2016-02-01 22:20:32 +01003800 option=GetImageOption(image_info,"alpha-color");
3801 if (option != (const char *) NULL)
3802 (void) QueryColorCompliance(option,AllCompliance,&image->alpha_color,
3803 exception);
cristy1626d332009-11-10 16:58:17 +00003804 option=GetImageOption(image_info,"background");
3805 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003806 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
cristy6fccee12011-10-20 18:43:18 +00003807 exception);
cristy1626d332009-11-10 16:58:17 +00003808 option=GetImageOption(image_info,"black-point-compensation");
3809 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003810 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003811 MagickBooleanOptions,MagickFalse,option);
3812 option=GetImageOption(image_info,"blue-primary");
3813 if (option != (const char *) NULL)
3814 {
3815 flags=ParseGeometry(option,&geometry_info);
3816 image->chromaticity.blue_primary.x=geometry_info.rho;
3817 image->chromaticity.blue_primary.y=geometry_info.sigma;
3818 if ((flags & SigmaValue) == 0)
3819 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3820 }
3821 option=GetImageOption(image_info,"bordercolor");
3822 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003823 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
cristy6fccee12011-10-20 18:43:18 +00003824 exception);
anthony72feaa62012-01-17 06:46:23 +00003825 /* FUTURE: do not sync compose to per-image compose setting here */
cristy1626d332009-11-10 16:58:17 +00003826 option=GetImageOption(image_info,"compose");
3827 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003828 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
cristy1626d332009-11-10 16:58:17 +00003829 MagickFalse,option);
anthony72feaa62012-01-17 06:46:23 +00003830 /* -- */
cristy1626d332009-11-10 16:58:17 +00003831 option=GetImageOption(image_info,"compress");
3832 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003833 image->compression=(CompressionType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003834 MagickCompressOptions,MagickFalse,option);
3835 option=GetImageOption(image_info,"debug");
3836 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003837 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003838 MagickFalse,option);
cristydd5f5912010-07-31 23:37:23 +00003839 option=GetImageOption(image_info,"density");
3840 if (option != (const char *) NULL)
3841 {
cristydd5f5912010-07-31 23:37:23 +00003842 flags=ParseGeometry(option,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +00003843 image->resolution.x=geometry_info.rho;
3844 image->resolution.y=geometry_info.sigma;
cristydd5f5912010-07-31 23:37:23 +00003845 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +00003846 image->resolution.y=image->resolution.x;
cristydd5f5912010-07-31 23:37:23 +00003847 }
cristy1626d332009-11-10 16:58:17 +00003848 option=GetImageOption(image_info,"depth");
3849 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003850 image->depth=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003851 option=GetImageOption(image_info,"endian");
3852 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003853 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy1626d332009-11-10 16:58:17 +00003854 MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003855 option=GetImageOption(image_info,"filter");
3856 if (option != (const char *) NULL)
dirk8b9f21c2016-02-01 22:30:19 +01003857 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
cristy1626d332009-11-10 16:58:17 +00003858 MagickFalse,option);
3859 option=GetImageOption(image_info,"fuzz");
3860 if (option != (const char *) NULL)
cristydbdd0e32011-11-04 23:29:40 +00003861 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
cristy1626d332009-11-10 16:58:17 +00003862 option=GetImageOption(image_info,"gravity");
3863 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003864 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
cristy1626d332009-11-10 16:58:17 +00003865 MagickFalse,option);
3866 option=GetImageOption(image_info,"green-primary");
3867 if (option != (const char *) NULL)
3868 {
3869 flags=ParseGeometry(option,&geometry_info);
3870 image->chromaticity.green_primary.x=geometry_info.rho;
3871 image->chromaticity.green_primary.y=geometry_info.sigma;
3872 if ((flags & SigmaValue) == 0)
3873 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
3874 }
3875 option=GetImageOption(image_info,"intent");
3876 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003877 image->rendering_intent=(RenderingIntent) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003878 MagickIntentOptions,MagickFalse,option);
cristy313634e2013-03-26 00:52:19 +00003879 option=GetImageOption(image_info,"intensity");
3880 if (option != (const char *) NULL)
3881 image->intensity=(PixelIntensityMethod) ParseCommandOption(
3882 MagickPixelIntensityOptions,MagickFalse,option);
cristy1626d332009-11-10 16:58:17 +00003883 option=GetImageOption(image_info,"interlace");
3884 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003885 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
cristy1626d332009-11-10 16:58:17 +00003886 MagickFalse,option);
3887 option=GetImageOption(image_info,"interpolate");
3888 if (option != (const char *) NULL)
cristy5c4e2582011-09-11 19:21:03 +00003889 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003890 MagickInterpolateOptions,MagickFalse,option);
3891 option=GetImageOption(image_info,"loop");
3892 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003893 image->iterations=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003894 option=GetImageOption(image_info,"orient");
3895 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003896 image->orientation=(OrientationType) ParseCommandOption(
cristy1626d332009-11-10 16:58:17 +00003897 MagickOrientationOptions,MagickFalse,option);
cristy14ed6a22013-12-28 23:48:05 +00003898 option=GetImageOption(image_info,"page");
3899 if (option != (const char *) NULL)
3900 {
3901 char
3902 *geometry;
3903
3904 geometry=GetPageGeometry(option);
3905 flags=ParseAbsoluteGeometry(geometry,&image->page);
3906 geometry=DestroyString(geometry);
3907 }
cristy1626d332009-11-10 16:58:17 +00003908 option=GetImageOption(image_info,"quality");
3909 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003910 image->quality=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003911 option=GetImageOption(image_info,"red-primary");
3912 if (option != (const char *) NULL)
3913 {
3914 flags=ParseGeometry(option,&geometry_info);
3915 image->chromaticity.red_primary.x=geometry_info.rho;
3916 image->chromaticity.red_primary.y=geometry_info.sigma;
3917 if ((flags & SigmaValue) == 0)
3918 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
3919 }
3920 if (image_info->quality != UndefinedCompressionQuality)
3921 image->quality=image_info->quality;
3922 option=GetImageOption(image_info,"scene");
3923 if (option != (const char *) NULL)
cristye27293e2009-12-18 02:53:20 +00003924 image->scene=StringToUnsignedLong(option);
cristy1626d332009-11-10 16:58:17 +00003925 option=GetImageOption(image_info,"taint");
3926 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003927 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
cristy1626d332009-11-10 16:58:17 +00003928 MagickFalse,option);
3929 option=GetImageOption(image_info,"tile-offset");
3930 if (option != (const char *) NULL)
3931 {
3932 char
3933 *geometry;
3934
3935 geometry=GetPageGeometry(option);
3936 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
3937 geometry=DestroyString(geometry);
3938 }
3939 option=GetImageOption(image_info,"transparent-color");
3940 if (option != (const char *) NULL)
cristy9950d572011-10-01 18:22:35 +00003941 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
cristy6fccee12011-10-20 18:43:18 +00003942 exception);
cristy1626d332009-11-10 16:58:17 +00003943 option=GetImageOption(image_info,"type");
3944 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003945 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy1626d332009-11-10 16:58:17 +00003946 option);
3947 option=GetImageOption(image_info,"units");
cristyc8d63672012-01-11 13:03:13 +00003948 units=image_info->units;
cristy1626d332009-11-10 16:58:17 +00003949 if (option != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +00003950 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
cristy1626d332009-11-10 16:58:17 +00003951 MagickFalse,option);
cristy19eb6412010-04-23 14:42:29 +00003952 if (units != UndefinedResolution)
cristy1626d332009-11-10 16:58:17 +00003953 {
cristy19eb6412010-04-23 14:42:29 +00003954 if (image->units != units)
cristy1626d332009-11-10 16:58:17 +00003955 switch (image->units)
3956 {
3957 case PixelsPerInchResolution:
3958 {
cristy19eb6412010-04-23 14:42:29 +00003959 if (units == PixelsPerCentimeterResolution)
cristy1626d332009-11-10 16:58:17 +00003960 {
cristy2a11bef2011-10-28 18:33:11 +00003961 image->resolution.x/=2.54;
3962 image->resolution.y/=2.54;
cristy1626d332009-11-10 16:58:17 +00003963 }
3964 break;
3965 }
3966 case PixelsPerCentimeterResolution:
3967 {
cristy19eb6412010-04-23 14:42:29 +00003968 if (units == PixelsPerInchResolution)
cristy1626d332009-11-10 16:58:17 +00003969 {
cristy2a11bef2011-10-28 18:33:11 +00003970 image->resolution.x=(double) ((size_t) (100.0*2.54*
3971 image->resolution.x+0.5))/100.0;
3972 image->resolution.y=(double) ((size_t) (100.0*2.54*
3973 image->resolution.y+0.5))/100.0;
cristy1626d332009-11-10 16:58:17 +00003974 }
3975 break;
3976 }
3977 default:
3978 break;
3979 }
cristy19eb6412010-04-23 14:42:29 +00003980 image->units=units;
cristy1626d332009-11-10 16:58:17 +00003981 }
anthonyfd706f92012-01-19 04:22:02 +00003982 option=GetImageOption(image_info,"virtual-pixel");
3983 if (option != (const char *) NULL)
cristy387430f2012-02-07 13:09:46 +00003984 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
3985 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
3986 exception);
cristy1626d332009-11-10 16:58:17 +00003987 option=GetImageOption(image_info,"white-point");
3988 if (option != (const char *) NULL)
3989 {
3990 flags=ParseGeometry(option,&geometry_info);
3991 image->chromaticity.white_point.x=geometry_info.rho;
3992 image->chromaticity.white_point.y=geometry_info.sigma;
3993 if ((flags & SigmaValue) == 0)
3994 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
3995 }
Cristy9c282cc2015-08-29 17:37:22 -04003996 /*
3997 Pointer to allow the lookup of pre-image artifact will fallback to a global
3998 option setting/define. This saves a lot of duplication of global options
3999 into per-image artifacts, while ensuring only specifically set per-image
4000 artifacts are preserved when parenthesis ends.
anthony643c6132012-11-07 14:50:28 +00004001 */
dirk98d3e1c2015-08-28 21:09:11 +02004002 if (image->image_info != (ImageInfo *) NULL)
4003 image->image_info=DestroyImageInfo(image->image_info);
Cristy36421ee2015-08-28 11:58:20 -04004004 image->image_info=CloneImageInfo(image_info);
cristy1626d332009-11-10 16:58:17 +00004005 return(MagickTrue);
4006}